/************************************************************************************* 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 countif( (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); // ¶ËµãË÷ÒýÖÁ ¶Ëµã0POLL_READ_BYTE (E0CSR, ControlReg); // Read control registerif (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 statePOLL_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 numberWORD wValue; // varies according to requestWORD wIndex; // varies according to requestWORD 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 properlySETUP.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 requestsif( (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 bufferReportHandler_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 Tableif(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 Handler0, 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}; <--------+