#pragma NOIV // Do not generate interrupt vectors //----------------------------------------------------------------------------- // File: hid.c // Contents: Interfaces interrupt data w/ PC as a USB keyboard // // Modified: November 2004 by Rokken Like Dokken (Patrick Phelan & Frederick Genthner) // to transmit correct characters over USB to represent button presses. // // Copyright (c) 2001 Cypress Semiconductor, Inc. All rights reserved //----------------------------------------------------------------------------- #include #include #define min(a,b) (((a)<(b))?(a):(b)) #define GD_HID 0x21 #define GD_REPORT 0x22 #define CR_SET_REPORT 0x09 #define GD_IF0 0x00 #define GD_IF1 0x01 #define HID_OUTPUT_REPORT 2 #define BTN_ADDR 0x41 // USB Keyboard scan-codes #define _A 0x04 #define _B 0x05 #define _C 0x06 #define _D 0x07 #define _E 0x08 #define _F 0x09 #define _G 0x0A #define _H 0x0B #define _I 0x0C #define _J 0x0D #define _K 0x0E #define _L 0x0F #define _M 0x10 #define _N 0x11 #define _O 0x12 #define _P 0x13 #define _Q 0x14 #define _R 0x15 #define _S 0x16 #define _T 0x17 #define _U 0x18 #define _V 0x19 #define _W 0x1A #define _X 0x1B #define _Y 0x1C #define _Z 0x1D #define _1 0x1E #define _2 0x1F #define _3 0x20 #define _4 0x21 #define _5 0x22 #define _6 0x23 #define _7 0x24 #define _8 0x25 #define _9 0x26 #define _0 0x27 #define _RTARROW 0x4F #define _LTARROW 0x50 #define _DOWNARROW 0x51 #define _UPARROW 0x52 #define _UPNUMPAD 0x60 #define _ULNUMPAD 0x5F #define _URNUMPAD 0x61 #define _DOWNNUMPAD 0x5A #define _DLNUMPAD 0x59 #define _DRNUMPAD 0x5B #define _RTNUMPAD 0x5E #define _LTNUMPAD 0x5C #define _ERROR 0x55 #define _COMMA 0x36 #define _PERIOD 0x37 // Cypress USB flags - not changed extern BOOL GotSUD; // Received setup data flag extern BOOL Sleep; // HID USB Report Variables WORD pHID1Dscr; WORD pHID1ReportDscr; WORD pHID1ReportDscrEnd; extern code HID1Dscr; extern code HID1ReportDscr; extern code HID1ReportDscrEnd; WORD pHID2Dscr; WORD pHID2ReportDscr; WORD pHID2ReportDscrEnd; extern code HID2Dscr; extern code HID2ReportDscr; extern code HID2ReportDscrEnd; // Function prototype void TD_Poll(void); BYTE Configuration; // Current configuration BYTE AlternateSetting; // Alternate settings // Function prototypes, etc BYTE HID1buttons; BYTE HID1oldbuttons; BYTE HID2buttons; BYTE HID2oldbuttons; BYTE read_buttons (void); BYTE get_arrow(); BYTE get_numpad(); BYTE get_buttons(); void check_start(); void update_buttons(); BYTE advance(BYTE); void set_keys(); // Global variables for decoding of PlayStation controller keys extern BYTE X; BYTE Xkey = _S; extern BYTE CIR; BYTE CIRkey = _O; extern BYTE SQA; BYTE SQAkey = _COMMA; extern BYTE TRI; BYTE TRIkey = _E; extern BYTE L1; BYTE L1key = _D; extern BYTE L2; BYTE L2key = _PERIOD; extern BYTE R1; BYTE R1key = _Q; extern BYTE R2; BYTE R2key = _T; extern BYTE START; extern BYTE SELECT; extern BYTE UP; extern BYTE DOWN; extern BYTE LEFT; extern BYTE RIGHT; BYTE STFLAG = 0; BYTE pins; BYTE test; BYTE ASTATE; BYTE OLDARROW; BYTE tL1,tL2,tR1,tR2,tX,tSQA,tCIR,tTRI,tSEL,tSTART; BYTE adv_flag = 0; BYTE tUP,tDOWN,tLEFT,tRIGHT; //----------------------------------------------------------------------------- // Task Dispatcher hooks // The following hooks are called by the task dispatcher. //----------------------------------------------------------------------------- void TD_Init(void) // Called once at startup { // Enable endpoint 2 IN and endpoint 1 IN IN07VAL |= bmEP1 | bmEP2; // Validate all EP's // Setup breakpoint to trigger on TD_Poll() BPADDR = (WORD)TD_Poll; USBBAV |= bmBPEN; // Enable the breakpoint USBBAV &= ~bmBPPULSE; ASTATE = 0; } // End TD_init(void) /************************************************************* * * read_buttons(void) - Decode buttons - This function not used * by Rokken Like Dokken. * * Parameters - void * * Return - Byte - data from button press * *************************************************************/ BYTE read_buttons (void) { BYTE d; while (I2CS & 0x40); //Wait for stop to be done I2CS = 0x80; //Set start condition I2DAT = BTN_ADDR; //Write button address while (!(I2CS & 0x01)); //Wait for done I2CS = 0x20; //Set last read d = I2DAT; //Dummy read while (!(I2CS & 0x01)); //Wait for done I2CS = 0x40; //Set stop bit return(I2DAT); //Read the data } // End read_buttons(void) void TD_Poll(void) // Called repeatedly while the device is idle { if( !(EPIO[IN2BUF_ID].cntrl & bmEPBUSY) ) // Is the IN2BUF available, { HID1buttons = read_buttons(); if (HID1buttons == read_buttons()) // Debounce { HID1buttons &= 0x0F; IN2BUF[0] = 0x00; // clear button state as seen by the host if ((HID1oldbuttons - HID1buttons) != 0) //Change in button state { // Define IN2BUF[0],[1],[2] as No Event if ( !(HID1buttons & 1) ) // left click { IN2BUF[0] |= 0x01; } if ( !(HID1buttons & 2) ) // right click { IN2BUF[0] |= 0x02; } IN2BUF[1] = 0x00; IN2BUF[2] = 0x00; IN2BC = 3; } HID1oldbuttons = HID1buttons; } } if( !(EPIO[IN1BUF_ID].cntrl & bmEPBUSY) ) // Is the IN1BUF available, { // Button decode code set_keys(); check_start(); update_buttons(); // Define IN1BUF[0],[1],[2] as No Event IN1BUF[0] = 0x00; IN1BUF[1] = 0x00; IN1BUF[2] = 0x00; // Define IN1BUF[3] as either Arrow (STFLAG = 1) keys or NumPad (STFLAG = 0) keys. // STFLAG: Start Flag informs whether start button has been pushed. if(STFLAG) { IN1BUF[3] = get_arrow(); } else { IN1BUF[3] = get_numpad(); } // Define IN1BUF[4] as result of button press (R1, R2, L1, L2, TRI, SQA, CIR, or X). IN1BUF[4] = get_buttons(); // Set IN1BC to number of bytes to be sent - must correspond with descriptor. IN1BC = 5; }// endif }// End TD_Poll(void) void set_keys() { tSTART = !((START>>7)&0x01); tSEL = !((SELECT>>7)&0x01); tL1 = !((L1>>7)&0x01); tL2 = !((L2>>7)&0x01); tR1 = !((R1>>7)&0x01); tR2 = !((R2>>7)&0x01); tSQA = !((SQA>>7)&0x01); tCIR = !((CIR>>7)&0x01); tX = !((X>>7)&0x01); tTRI = !((TRI>>7)&0x01); tUP = !((UP>>7)&0x01); tDOWN = !((DOWN>>7)&0x01); tLEFT = !((LEFT>>7)&0x01); tRIGHT = !((RIGHT>>7)&0x01); } /************************************************************* * * update_buttons() - Update buttons on game pad per user preferences * * Parameters - none * * Return - void * *************************************************************/ void update_buttons() { if(!tSEL) { adv_flag = 1; return; } if(!adv_flag) { return; } if(tL1) { L1key = advance(L1key); adv_flag = 0; } if(tL2) { L2key = advance(L2key); adv_flag = 0; } if(tR1) { R1key = advance(R1key); adv_flag = 0; } if(tR2) { R2key = advance(R2key); adv_flag = 0; } if(tX) { Xkey = advance(Xkey); adv_flag = 0; } if(tTRI) { TRIkey = advance(TRIkey); adv_flag = 0; } if(tSQA) { SQAkey = advance(SQAkey); adv_flag = 0; } if(tCIR) { CIRkey = advance(CIRkey); adv_flag = 0; } } // End update_buttons() /************************************************************* * * advance(BYTE b) - Advance counter to next valid value for possible * user preferred key. * * Parameters - BYTE b - current key(counter) value * * Return - void * *************************************************************/ BYTE advance(BYTE b) { if(b == 0x27) { return 0x2D; } if(b == 0x31) { return 0x33; } if(b == 0x39) { return 0x04; } b++; return b; } // End advance(BYTE b) /************************************************************* * * check_start() - Toggle STFLAG if start button has been pressed * * Parameters - none * * Return - void * *************************************************************/ void check_start() { if(tSTART) { STFLAG = !STFLAG; } } // End check_start() /************************************************************* * * get_buttons() - Decodes pressed button, if any, from data provided * by the timer0 interrupt in psx.c * * Parameters - none * * Return - BYTE - button that has been pressed/decoded. * *************************************************************/ BYTE get_buttons() { if(tL1) { return L1key; } if(tL2) { return L2key; } if(tR1) { return R1key; } if(tR2) { return R2key; } if(tX) { return Xkey; } if(tTRI) { return TRIkey; } if(tSQA) { return SQAkey; } if(tCIR) { return CIRkey; } return 0x00; } // End get_buttons() /************************************************************* * * get_arrow() - Decodes pressed gamepad directional key, if * any, from data provided by the timer0 interrupt in psx.c * * Parameters - none * * Return - BYTE - directional button that has been pressed/decoded. * *************************************************************/ BYTE get_arrow() { if(tUP) { return _UPARROW; } if(tDOWN) { return _DOWNARROW; } if(tLEFT) { return _LTARROW; } if(tRIGHT) { return _RTARROW; } return 0x00; } // End get_arrow() /************************************************************* * * get_numpad() - Decodes directional button, if any, from * data provided by the timer0 interrupt in psx.c * * Parameters - none * * Return - BYTE - directional button that has been pressed/decoded. * *************************************************************/ BYTE get_numpad() { if(tUP) { if(tLEFT) { return _ULNUMPAD; } if(tRIGHT) { return _URNUMPAD; } return _UPNUMPAD; } if(tDOWN) { if(tLEFT) { return _DLNUMPAD; } if(tRIGHT) { return _DRNUMPAD; } return _DOWNNUMPAD; } if(tLEFT) { return _LTNUMPAD; } if(tRIGHT) { return _RTNUMPAD; } return 0x00; }// End get_numpad() /************************************************************* * * The following functions are from the file in the Cypress archive. * They were not modified by us. * *************************************************************/ BOOL TD_Suspend(void) // Called before the device goes into suspend mode { // Turn off breakpoint light before entering suspend USBBAV |= bmBREAK; // Clear the breakpoint return(TRUE); } BOOL TD_Resume(void) // Called after the device resumes { return(TRUE); } //----------------------------------------------------------------------------- // Device Request hooks // The following hooks are called by the end point 0 device request parser. //----------------------------------------------------------------------------- BOOL DR_ClassRequest(void) { return(TRUE); } BOOL DR_GetDescriptor(void) { BYTE HID1length,i; BYTE HID2length,j; pHID1Dscr = (WORD)&HID1Dscr; pHID1ReportDscr = (WORD)&HID1ReportDscr; pHID1ReportDscrEnd = (WORD)&HID1ReportDscrEnd; pHID2Dscr = (WORD)&HID2Dscr; pHID2ReportDscr = (WORD)&HID2ReportDscr; pHID2ReportDscrEnd = (WORD)&HID2ReportDscrEnd; switch (SETUPDAT[3]) { case GD_HID: //HID Descriptor switch (SETUPDAT[4]) { case GD_IF0: SUDPTRH = MSB(pHID1Dscr); SUDPTRL = LSB(pHID1Dscr); break; case GD_IF1: SUDPTRH = MSB(pHID2Dscr); SUDPTRL = LSB(pHID2Dscr); break; default: EZUSB_STALL_EP0(); } return (FALSE); break; case GD_REPORT: //Report Descriptor switch (SETUPDAT[4]) { case GD_IF0: HID1length = pHID1ReportDscrEnd - pHID1ReportDscr; while (HID1length) { for(i=0; i