C8051F340 USB Fn hacking

/************************************************************************************
 *                           C8051F340 USB Fn hacking
 * 说明:
 *     简单跟踪一下这个C8051F340 USB的使用。
 *
 *                                               2017-4-1 深圳 南山平山村 曾剑锋
 ***********************************************************************************/

void main(void)
{
    System_Init (); --------------------+
    USB0_Init ();                       |
    EA = 1;                             |
                                        |
    while (1) {                         |
        Key_Scan();                     |      ------------------------------------+
        Key_Handle();                   |      ------------------------------------*-+
    }                                   |                                          | |
}                                       |                                          | |
                                        |                                          | |
void System_Init (void)    <------------+                                          | |
{                                                                                  | |
    PCA0MD &= ~0x40;                    // Disable Watchdog timer                  | |
    Sysclk_Init ();      -------+       // initialize system clock                 | |
    Port_Init ();               |       // configure cross bar      -----------+   | |
    Timer_Init ();              |       // configure timer          -----------*-+ | |
}                               |                                              | | | |
                                |                                              | | | |
void Sysclk_Init (void)   <-----+                                              | | | |
{                                                                              | | | |
#ifdef _USB_LOW_SPEED_                                                         | | | |
                                                                               | | | |
    OSCICN |= 0x03;                     // Configure internal oscillator for   | | | |
    // its maximum frequency and enable                                        | | | |
    // missing clock detector                                                  | | | |
                                                                               | | | |
    CLKSEL  = SYS_EXT_OSC;              // Select System clock                 | | | |
    CLKSEL |= USB_INT_OSC_DIV_2;        // Select USB clock                    | | | |
#else                                                                          | | | |
    OSCICN |= 0x03;                     // Configure internal oscillator for   | | | |
    // its maximum frequency and enable                                        | | | |
    // missing clock detector                                                  | | | |
                                                                               | | | |
    CLKMUL  = 0x00;                     // Select internal oscillator as       | | | |
    // input to clock multiplier                                               | | | |
                                                                               | | | |
    CLKMUL |= 0x80;                     // Enable clock multiplier             | | | |
    CLKMUL |= 0xC0;                     // Initialize the clock multiplier     | | | |
    Delay();                            // Delay for clock multiplier to begin | | | |
                                                                               | | | |
    while(!(CLKMUL & 0x20));            // Wait for multiplier to lock         | | | |
    CLKSEL  = SYS_INT_OSC;              // Select system clock                 | | | |
    CLKSEL |= USB_4X_CLOCK;             // Select USB clock                    | | | |
#endif  /* _USB_LOW_SPEED_ */                                                  | | | |
}                                                                              | | | |
                                                                               | | | |
void Port_Init(void)                <------------------------------------------+ | | |
{                                                                                | | |
    P0MDOUT        = 0xFF;                                                       | | |
    P0SKIP        = 0xFF;                                                        | | |
    P2MDIN   = 0xFF;                 // Port 2 pin 5 set as analog input         | | |
    P2SKIP   = 0xFF;                    // Port 2 pin 5 skipped by crossbar      | | |
                                                                                 | | |
    XBR1        = 0x40;                    // Enable Crossbar                    | | |
                                                                                 | | |
    DebugLEDOFF;                        // ¹Ø±Õµ÷Êﵮ                            | | |
}                                                                                | | |
                                                                                 | | |
void Timer_Init (void)                                                           | | |
{                                                                                | | |
    TMR2CN  = 0x00;                     // Stop Timer2; Clear TF2;               | | |
                                                                                 | | |
    CKCON  &= ~0xF0;                    // Timer2 clocked based on T2XCLK;       | | |
    TMR2L   = 0x7F;                      // Timer/Counter 2 Low                  | | |
    TMR2H   = 0xFF;                      // Timer/Counter 2 High                 | | |
    TMR2RLL = 0xEF;                         // Timer/Counter 2 Reload Low        | | |
    TMR2RLH    = 0xD8;                         // Timer/Counter 2 Reload High    | | |
                                                                                 | | |
    ET2     = 1;                        // Enable Timer2 interrupts              | | |
    TR2     = 1;                        // Start Timer2                          | | |
}                                                                                | | |
                                                                                 | | |
void USB0_Init (void)          <-------------------------------------------------+ | |
{                                                                                  | |
                                                                                   | |
    //    #define POLL_WRITE_BYTE(addr, data) while(USB0ADR & 0x80);              | |
    //                                    WRITE_BYTE(addr, data);                  | |
    POLL_WRITE_BYTE (POWER, 0x08);      // Force Asynchronous USB Reset       ---+ | |
    POLL_WRITE_BYTE (IN1IE, 0x07);      // Enable Endpoint 0-1 in interrupts     | | |
    POLL_WRITE_BYTE (OUT1IE,0x07);      // Enable Endpoint 0-1 out interrupts    | | |
    POLL_WRITE_BYTE (CMIE, 0x07);       // Enable Reset, Resume, and Suspend     | | |
    // interrupts                                                                | | |
    USB0XCN = 0xE0;                     // Enable transceiver; select full speed | | |
    POLL_WRITE_BYTE (CLKREC,0x89);      // Enable clock recovery, single-step    | | |
    // mode disabled                                                             | | |
                                                                                 | | |
    EIE1 |= 0x02;                       // Enable USB0 Interrupts                | | |
                                                                                 | | |
    // Enable USB0 by clearing the USB                                           | | |
    POLL_WRITE_BYTE (POWER, 0x01);      // Inhibit Bit and enable suspend        | | |
    // detection                                                                 | | |
                                                                                 | | |
}                                                                                | | |
                                                                                 | | |
#define POLL_WRITE_BYTE(addr, data) while(USB0ADR & 0x80);         <------------+ | |
    WRITE_BYTE(addr, data);                                         -----+         | |
                                                                         |         | |
#define WRITE_BYTE(addr, data) USB0ADR = (addr); USB0DAT = data     <----+         | |
                                                                         |         | |
sfr  USB0DAT      =  0x97;             // USB0 Data Register        <----+         | |
                                                                                   | |
void Key_Scan(void) {             <------------------------------------------------+ |
    static unsigned char AllKeyBk;                                                   |
    unsigned char AllKey = 0;                                                        |
    unsigned char i = 0;                                                             |
                                                                                     |
    if(b_ScanKey) {    // 定时器中每过10ms会对这个变量置1一次                        |
        b_ScanKey = 0;                                                               |
        AllKey = P2;                                                                 |
        AllKey >>= 2;                                                                |
        if(AllKey != 0x3F) {    // 有键按下                                          |
            if(AllKeyBk != AllKey) {                                                 |
                LongKeyCnt = 0;    // 有新的按键按下,重新去抖                       |
            }                                                                        |
            AllKeyBk = AllKey;                                                       |
            LongKeyCnt++;                                                            |
            if(LongKeyCnt > 1) {    // 20ms 去抖                                     |
                key_status[KEYALL] = KEY_DOWN;                                       |
                for( i = 0; i < 6; i++) {                                            |
                    // 判断每一个按键的状态                                          |
                    if( (AllKey & 0x01) == 0 ) {                                     |
                        key_status[i] = KEY_DOWN;                                    |
                    } else {                                                         |
                        key_status[i] = KEY_UP;                                      |
                    }                                                                |
                    AllKey >>= 1;                                                    |
                }                                                                    |
            }                                                                        |
        } else {                                                                     |
            key_status[KEYALL] = KEY_UP;                                             |
            LongKeyCnt = 0;                 // 当按键抬起来之后这里会置零            |
            for( i = 0; i < 6; i++) {                                                |
                key_status[i] = KEY_UP;                                              |
            }                                                                        |
        }                                                                            |
    }                                                                                |
}                                                                                    |
                                                                                     |
void Key_Handle(void)          <-----------------------------------------------------+
{
    static unsigned char key_status_bk[6] = {KEY_UP};
    unsigned char i;
    unsigned char cnt_i;

    cnt_i = 2;
    if(key_status[KEYF1] == KEY_DOWN) {
        if(key_status[KEYF1] != key_status_bk[KEYF1]) {
            IN_PACKET[cnt_i] = KB_F1;
            DebugLEDON;
            cnt_i++;
        }
    } else if(key_status[KEYF1] == KEY_UP) {
        if(key_status[KEYF1] != key_status_bk[KEYF1]) {    // 按键状态发生改变,只发送一次数据
            DebugLEDOFF;
        }
    }
    if(key_status[KEYF2] == KEY_DOWN) {
        if(key_status[KEYF2] != key_status_bk[KEYF2]) {
            IN_PACKET[cnt_i] = KB_F2;
            DebugLEDON;
            cnt_i++;
        }
    } else if(key_status[KEYF2] == KEY_UP) {
        if(key_status[KEYF2] != key_status_bk[KEYF2]) {    // 按键状态发生改变,只发送一次数据
            DebugLEDOFF;
        }
    }
    if(key_status[KEYF3] == KEY_DOWN) {
        if(key_status[KEYF3] != key_status_bk[KEYF3]) {
            IN_PACKET[cnt_i] = KB_F3;
            DebugLEDON;
            cnt_i++;
        }
    } else if(key_status[KEYF3] == KEY_UP) {
        if(key_status[KEYF3] != key_status_bk[KEYF3]) {    // 按键状态发生改变,只发送一次数据
            DebugLEDOFF;
        }
    }
    if(key_status[KEYF4] == KEY_DOWN) {
        if(key_status[KEYF4] != key_status_bk[KEYF4]) {
            IN_PACKET[cnt_i] = KB_F4;
            DebugLEDON;
            cnt_i++;
        }
    } else if(key_status[KEYF4] == KEY_UP) {
        if(key_status[KEYF4] != key_status_bk[KEYF4]) {    // 按键状态发生改变,只发送一次数据
            DebugLEDOFF;
        }
    }
    if(key_status[KEYF5] == KEY_DOWN) {
        if(key_status[KEYF5] != key_status_bk[KEYF5]) {
            IN_PACKET[cnt_i] = KB_F5;
            DebugLEDON;
            cnt_i++;
        }
    } else if(key_status[KEYF5] == KEY_UP) {
        if(key_status[KEYF5] != key_status_bk[KEYF5]) {    // 按键状态发生改变,只发送一次数据
            DebugLEDOFF;
        }
    }
    if(key_status[KEYF6] == KEY_DOWN) {
        if(key_status[KEYF6] != key_status_bk[KEYF6]) {
            IN_PACKET[cnt_i] = KB_F6;
            DebugLEDON;
            cnt_i++;
        }
    } else if(key_status[KEYF6] == KEY_UP) {
        if(key_status[KEYF6] != key_status_bk[KEYF6]) {    // 按键状态发生改变,只发送一次数据
            DebugLEDOFF;
        }
    }
    if(key_status[KEYALL] == KEY_DOWN){
        if(key_status[KEYALL] != key_status_bk[KEYALL]) {
            SendPacket (0);
        }
    } else if(key_status[KEYALL] == KEY_UP){
        for(i = 2; i < 6; i++) {
            IN_PACKET[i] = 0;                              -------+
        }                                                         |
        if(key_status[KEYALL] != key_status_bk[KEYALL]) {  -------*-+
            SendPacket (0);                                       | |
        }                                                         | |
    }                                                             | |
                                                                  | |
    for(i = 0; i < 7; i++) {                                      | |
        key_status_bk[i] = key_status[i];                         | |
    }                                                             | |
}                                                                 | |
                                                                  | |
unsigned char IN_PACKET[8] ={0,0,0,0,0,0,0,0};            <-------+ |
                                                                    |
unsigned char key_status[7] = {KEY_UP};                   <---------+

void Timer2_ISR (void) interrupt 5        // 10ms
{
    static unsigned Timer2_Cnt = 0;

    Timer2_Cnt++;
    b_ScanKey = 1;    // for key count

    if( (Timer2_Cnt%50) == 0 )    {
    }

    if( Timer2_Cnt == 50000)
        Timer2_Cnt = 0;

    TF2H = 0;                           // Clear Timer2 interrupt flag
}

//-----------------------------------------------------------------------------
// Usb_ISR
//-----------------------------------------------------------------------------
//
// Called after any USB type interrupt, this handler determines which type
// of interrupt occurred, and calls the specific routine to handle it.
//
//-----------------------------------------------------------------------------
void Usb_ISR (void) interrupt 8        // USB中断入口
{

    unsigned char bCommon, bIn, bOut;
    POLL_READ_BYTE (CMINT, bCommon);    // USB0公共中断寄存器    ------+
    POLL_READ_BYTE (IN1INT, bIn);        // USB0输入端点中断寄存器     |
    POLL_READ_BYTE (OUT1INT, bOut);        // USB0输出端点中断寄存器   |
    {                                                                  |
        if (bCommon & rbRSUINT) {        // 恢复-> 没有实质的动作      |
            Usb_Resume ();                                 ------------*-+
        }                                                              | |
        if (bCommon & rbRSTINT) {        // 复位                       | |
            Usb_Reset ();                                  ------------*-*-+
        }                                                              | | |
        if (bCommon & rbSUSINT)  {        // 挂起                      | | |
            Usb_Suspend ();                                ------------*-*-*---+
        }                                                              | | |   |
        if (bIn & rbEP0) {                // 端点0中断处理             | | |   |
            Handle_Control ();                             ------------*-*-*---*-----+
        }                                                              | | |   |     |
        if (bIn & rbIN1) {              // 端点1输入中断处理           | | |   |     |
            Handle_In1 ();                                 ------------*-*-*---*-+   |
        }                                                              | | |   | |   |
        if (bOut & rbOUT1) {            // 端点1输出中断处理           | | |   | |   |
            Handle_Out1 ();                                ------------*-*-*---*-*-+ |
        }                                                              | | |   | | | |
    }                                                                  | | |   | | | |
}                                                                      | | |   | | | |
                                                                       | | |   | | | |
#define POLL_READ_BYTE(addr, target) while(USB0ADR & 0x80);     <-----+ | |   | | | |
    READ_BYTE(addr, target);                               -------+      | |   | | | |
                                                                  |      | |   | | | |
#define READ_BYTE(addr, target) USB0ADR = (0x80 | addr);  <------+      | |   | | | |
                         while (USB0ADR & 0x80); target = USB0DAT        | |   | | | |
                                                                         | |   | | | |
void Usb_Resume(void)                     <------------------------------+ |   | | | |
{                                                                          |   | | | |
    volatile int k;                                                        |   | | | |
                                                                           |   | | | |
    k++;                                                                   |   | | | |
                                                                           |   | | | |
    // Add code for resume                                                 |   | | | |
}                                                                          |   | | | |
                                                                           |   | | | |
void Usb_Reset (void)                     <--------------------------------+   | | | |
{                                                                              | | | |
    USB0_STATE = DEV_DEFAULT;           // Set device state to default         | | | |
                                                                               | | | |
    POLL_WRITE_BYTE (POWER, 0x01);      // Clear usb inhibit bit to enable USB | | | |
    // suspend detection                                                       | | | |
                                                                               | | | |
    EP_STATUS[0] = EP_IDLE;             // Set default Endpoint Status         | | | |
    EP_STATUS[1] = EP_HALT;                                                    | | | |
    EP_STATUS[2] = EP_HALT;                                                    | | | |
}                                                                              | | | |
                                                                               | | | |
void Usb_Suspend (void)         <----------------------------------------------+ | | |
{                                                                                | | |
    volatile int k;                                                              | | |
    k++;                                                                         | | |
}                                                                                | | |
                                                                                 | | |
void Handle_In1 ()              <------------------------------------------------+ | |
{                                                                                  | |
    EP_STATUS[1] = EP_IDLE;                                                        | |
}                                                                                  | |
                                                                                   | |
void Handle_Out1 ()             <--------------------------------------------------+ |
{                                                                                    |
                                                                                     |
    unsigned char Count = 0;                                                         |
    unsigned char ControlReg;                                                        |
                                                                                     |
    POLL_WRITE_BYTE (INDEX, 1);         // Set index to endpoint 2 registers         |
    POLL_READ_BYTE (EOUTCSR1, ControlReg);                                           |
                                                                                     |
    if (EP_STATUS[1] == EP_HALT)        // If endpoint is halted, send a stall       |
    {                                                                                |
        POLL_WRITE_BYTE (EOUTCSR1, rbOutSDSTL);                                      |
    }                                                                                |
                                                                                     |
    else                                // Otherwise read received packet            |
        // from host                                                                 |
    {                                                                                |
        if (ControlReg & rbOutSTSTL)     // Clear sent stall bit if last             |
            // packet was a stall                                                    |
        {                                                                            |
            POLL_WRITE_BYTE (EOUTCSR1, rbOutCLRDT);                                  |
        }                                                                            |
                                                                                     |
        Setup_OUT_BUFFER ();             // configure buffer to save                 |
        // received data                                                             |
        Fifo_Read(FIFO_EP1, OUT_BUFFER.Length, OUT_BUFFER.Ptr);                      |
                                                                                     |
        // process data according to received Report ID.                             |
        // In systems with Report Descriptors that do not define report IDs,         |
        // the host will still format OUT packets with a prefix byte                 |
        // of '0x00'.                                                                |
                                                                                     |
        ReportHandler_OUT (OUT_BUFFER.Ptr[0]);                                       |
                                                                                     |
        POLL_WRITE_BYTE (EOUTCSR1, 0);   // Clear Out Packet ready bit               |
    }                                                                                |
}                                                                                    |
                                                                                     |
//-----------------------------------------------------------------------------      |
// Handle_Control                                                                    |
//-----------------------------------------------------------------------------      |
//                                                                                   |
// Return Value : None                                                               |
// Parameters   : None                                                               |
//                                                                                   |
// - Decode Incoming SETUP requests                                                  |
// - Load data packets on fifo while in transmit mode                                |
//                                                                                   |
//-----------------------------------------------------------------------------      |
                                                                                     |
void Handle_Control (void)                    <--------------------------------------+
{
    unsigned char ControlReg;           // Temporary storage for EP control register

    POLL_WRITE_BYTE (INDEX, 0);         // ¶ËµãË÷ÒýÖÁ ¶Ëµã0
    POLL_READ_BYTE (E0CSR, ControlReg); // Read control register

    if (EP_STATUS[0] == EP_ADDRESS)     // Handle Status Phase of Set Address
        // command
    {
        POLL_WRITE_BYTE (FADDR, SETUP.wValue.c[LSB]);
        EP_STATUS[0] = EP_IDLE;
    }

    if (ControlReg & rbSTSTL)           // If last packet was a sent stall,
        {                                   // reset STSTL bit and return EP0
            // to idle state
            POLL_WRITE_BYTE (E0CSR, 0);
            EP_STATUS[0] = EP_IDLE;
            return;
        }

    if (ControlReg & rbSUEND)           // If last SETUP transaction was
    {                                   // ended prematurely then set
        POLL_WRITE_BYTE (E0CSR, rbDATAEND);
        // Serviced SETUP End bit and return EP0
        POLL_WRITE_BYTE (E0CSR, rbSSUEND);
        EP_STATUS[0] = EP_IDLE;          // to idle state
    }

    if (EP_STATUS[0] == EP_IDLE)        // If Endpoint 0 is in idle mode
    {
        if (ControlReg & rbOPRDY)        // Make sure that EP 0 has an Out Packet
        {                                // ready from host although if EP0
            // is idle, this should always be the case
            /*
                                                     typedef struct
                                                     {
            // typedef union {unsigned int i; unsigned char c[2];} WORD;

            unsigned char bmRequestType;        // Request recipient, type, and dir.
            unsigned char bRequest;             // Specific standard request number
            WORD wValue;                        // varies according to request
            WORD wIndex;                        // varies according to request
            WORD wLength;                       // Number of bytes to transfer
            } setup_buffer;                        // End of SETUP Packet Type
             */
            Fifo_Read (FIFO_EP0, 8, (unsigned char *)&SETUP);
            // Get SETUP Packet off of Fifo, it is currently Big-Endian
            // Compiler Specific - these next three statements swap the bytes of the
            // SETUP packet words to Big Endian so they can be compared to other 16-bit
            // values elsewhere properly
            SETUP.wValue.i = SETUP.wValue.c[MSB] + 256*SETUP.wValue.c[LSB];
            SETUP.wIndex.i = SETUP.wIndex.c[MSB] + 256*SETUP.wIndex.c[LSB];
            SETUP.wLength.i = SETUP.wLength.c[MSB] + 256*SETUP.wLength.c[LSB];

            // Intercept HID class-specific requests
            if( (SETUP.bmRequestType & ~0x80) == DSC_HID) {
                switch (SETUP.bRequest) {
                    case GET_REPORT:
                        Get_Report ();                ----------------------------------+
                        break;                                                          |
                    case SET_REPORT:                                                    |
                        Set_Report ();                                                  |
                        break;                                                          |
                    case GET_IDLE:                                                      |
                        Get_Idle ();                                                    |
                        break;                                                          |
                    case SET_IDLE:                                                      |
                        Set_Idle ();                                                    |
                        break;                                                          |
                    case GET_PROTOCOL:                                                  |
                        Get_Protocol ();                                                |
                        break;                                                          |
                    case SET_PROTOCOL:                                                  |
                        Set_Protocol ();                                                |
                        break;                                                          |
                    default:                                                            |
                        Force_Stall ();      // Send stall to host if invalid           |
                        break;                 // request                               |
                }                                                                       |
            } else                                                                      |
                                                                                        |
                switch (SETUP.bRequest)       // Call correct subroutine to handle      |
                {                             // each kind of standard request          |
                    case GET_STATUS:                                                    |
                        Get_Status ();                                                  |
                        break;                                                          |
                    case CLEAR_FEATURE:                                                 |
                        Clear_Feature ();                                               |
                        break;                                                          |
                    case SET_FEATURE:                                                   |
                        Set_Feature ();                                                 |
                        break;                                                          |
                    case SET_ADDRESS:                                                   |
                        Set_Address ();                                                 |
                        break;                                                          |
                    case GET_DESCRIPTOR:                                                |
                        Get_Descriptor ();                                              |
                        break;                                                          |
                    case GET_CONFIGURATION:                                             |
                        Get_Configuration ();                                           |
                        break;                                                          |
                    case SET_CONFIGURATION:                                             |
                        Set_Configuration ();                                           |
                        break;                                                          |
                    case GET_INTERFACE:                                                 |
                        Get_Interface ();                                               |
                        break;                                                          |
                    case SET_INTERFACE:                                                 |
                        Set_Interface ();                                               |
                        break;                                                          |
                    default:                                                            |
                        Force_Stall ();         // Send stall to host if invalid request|
                        break;                                                          |
                }                                                                       |
        }                                                                               |
    }                                                                                   |
                                                                                        |
    if (EP_STATUS[0] == EP_TX)          // See if endpoint should transmit              |
    {                                                                                   |
        if (!(ControlReg & rbINPRDY) )   // Don't overwrite last packet                 |
        {                                                                               |
            // Read control register                                                    |
            POLL_READ_BYTE (E0CSR, ControlReg);                                         |
                                                                                        |
            // Check to see if SETUP End or Out Packet received, if so do not put       |
            // any new data on FIFO                                                     |
            if ((!(ControlReg & rbSUEND)) || (!(ControlReg & rbOPRDY)))                 |
            {                                                                           |
                // Add In Packet ready flag to E0CSR bitmask                            |
                ControlReg = rbINPRDY;                                                  |
                if (DATASIZE >= EP0_PACKET_SIZE)                                        |
                {                                                                       |
                    // Break Data into multiple packets if larger than Max Packet       |
                    Fifo_Write_InterruptServiceRoutine (FIFO_EP0, EP0_PACKET_SIZE,      |
                            (unsigned char*)DATAPTR);                                   |
                    // Advance data pointer                                             |
                    DATAPTR  += EP0_PACKET_SIZE;                                        |
                    // Decrement data size                                              |
                    DATASIZE -= EP0_PACKET_SIZE;                                        |
                    // Increment data sent counter                                      |
                    DATASENT += EP0_PACKET_SIZE;                                        |
                }                                                                       |
                else                                                                    |
                {                                                                       |
                    // If data is less than Max Packet size or zero                     |
                    Fifo_Write_InterruptServiceRoutine (FIFO_EP0, DATASIZE,             |
                            (unsigned char*)DATAPTR);                                   |
                    ControlReg |= rbDATAEND;// Add Data End bit to bitmask              |
                    EP_STATUS[0] = EP_IDLE; // Return EP 0 to idle state                |
                }                                                                       |
                if (DATASENT == SETUP.wLength.i)                                        |
                {                                                                       |
                    // This case exists when the host requests an even multiple of      |
                    // your endpoint zero max packet size, and you need to exit         |
                    // transmit mode without sending a zero length packet               |
                    ControlReg |= rbDATAEND;// Add Data End bit to mask                 |
                    EP_STATUS[0] = EP_IDLE; // Return EP 0 to idle state                |
                }                                                                       |
                // Write mask to E0CSR                                                  |
                POLL_WRITE_BYTE(E0CSR, ControlReg);                                     |
            }                                                                           |
        }                                                                               |
    }                                                                                   |
                                                                                        |
    if (EP_STATUS[0] == EP_RX)          // See if endpoint should transmit              |
    {                                                                                   |
        // Read control register                                                        |
        POLL_READ_BYTE (E0CSR, ControlReg);                                             |
        if (ControlReg & rbOPRDY)        // Verify packet was received                  |
        {                                                                               |
            ControlReg = rbSOPRDY;                                                      |
            if (DATASIZE >= EP0_PACKET_SIZE)                                            |
            {                                                                           |
                Fifo_Read(FIFO_EP0, EP0_PACKET_SIZE, (unsigned char*)DATAPTR);          |
                // Advance data pointer                                                 |
                DATAPTR  += EP0_PACKET_SIZE;                                            |
                // Decrement data size                                                  |
                DATASIZE -= EP0_PACKET_SIZE;                                            |
                // Increment data sent counter                                          |
                DATASENT += EP0_PACKET_SIZE;                                            |
            }                                                                           |
            else                                                                        |
            {                                                                           |
                // read bytes from FIFO                                                 |
                Fifo_Read (FIFO_EP0, DATASIZE, (unsigned char*) DATAPTR);               |
                                                                                        |
                ControlReg |= rbDATAEND;   // signal end of data                        |
                EP_STATUS[0] = EP_IDLE;    // set Endpoint to IDLE                      |
            }                                                                           |
            if (DATASENT == SETUP.wLength.i)                                            |
            {                                                                           |
                ControlReg |= rbDATAEND;                                                |
                EP_STATUS[0] = EP_IDLE;                                                 |
            }                                                                           |
            // if EP_RX mode was entered through a SET_REPORT request,                  |
            // call the ReportHandler_OUT function and pass the Report                  |
            // ID, which is the first by the of DATAPTR's buffer                        |
            if ( (EP_STATUS[0] == EP_IDLE) && (SETUP.bRequest == SET_REPORT) )          |
            {                                                                           |
                ReportHandler_OUT (*DATAPTR);                                           |
            }                                                                           |
                                                                                        |
            if (EP_STATUS[0] != EP_STALL) POLL_WRITE_BYTE (E0CSR, ControlReg);          |
        }                                                                               |
    }                                                                                   |
                                                                                        |
}                                                                                       |
                                                                                        |
//-----------------------------------------------------------------------------         |
//                                                                                      |
// Return Value - None                                                                  |
// Parameters - None                                                                    |
//                                                                                      |
// Description: Sends a given report type to the host.                                  |
//                                                                                      |
//-----------------------------------------------------------------------------         |
void Get_Report (void)                                   <------------------------------+
{
    // call appropriate handler to prepare buffer
    ReportHandler_IN_ISR(SETUP.wValue.c[LSB]);            --------------------+
    // set DATAPTR to buffer used inside Control Endpoint                     |
    DATAPTR = IN_BUFFER.Ptr;                                                  |
    DATASIZE = IN_BUFFER.Length;                                              |
                                                                              |
    if (EP_STATUS[0] != EP_STALL)                                             |
    {                                                                         |
        // Set serviced SETUP Packet                                          |
        POLL_WRITE_BYTE (E0CSR, rbSOPRDY);                                    |
        EP_STATUS[0] = EP_TX;            // Endpoint 0 in transmit mode       |
        DATASENT = 0;                    // Reset DATASENT counter            |
    }                                                                         |
}                                                                             |
                                                                              |
void ReportHandler_IN_ISR(unsigned char R_ID)            <--------------------+
{
    unsigned char index;

    index = 0;

    while(index <= IN_VECTORTABLESize)
    {
        // check to see if Report ID passed into function
        // matches the Report ID for this entry in the Vector Table
        if(IN_VECTORTABLE[index].ReportID == R_ID)       ---------------------------+
        {                                                                           |
            IN_VECTORTABLE[index].hdlr();                                           |
            break;                                                                  |
        }                                                                           |
                                                                                    |
        // if Report IDs didn't match, increment the index pointer                  |
        index++;                                                                    |
    }                                                                               |
                                                                                    |
}                                                                                   |
                                                                                    |
// ****************************************************************************     |
// Link all Report Handler functions to corresponding Report IDs                    |
// ****************************************************************************     |
                                                                                    |
const VectorTableEntry code IN_VECTORTABLE[IN_VECTORTABLESize] =        <-----------+
{
    // FORMAT: Report ID, Report Handler
    0, IN_Report                                                       ------+
};                                                                           |
                                                                             |
void IN_Report(void){                            <---------------------------+

    // save left mouse button stat to bit 0 of first data byte
    // IN_PACKET[2] = MOUSE_BUTTON1;
    // IN_PACKET[3] = MOUSE_BUTTON2;
    IN_BUFFER.Ptr = IN_PACKET;                   ---------+
    IN_BUFFER.Length = 8;                                 |
                                                          |
}                                                         |
                                                          |
unsigned char IN_PACKET[8] ={0,0,0,0,0,0,0,0};   <--------+
原文地址:https://www.cnblogs.com/zengjfgit/p/6654957.html