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}; <--------+