;**************************************************************************** ; ; file: rdk_keyboard.asm ; Description: This file contains Keyboard application functionality ; External Functions: ; app_data_received_a ; app_idle ; ; Target: Cypress CY7C63723 Encore Chip ; $Header: /WirelessUSB/WUSB Kits/CY4632 LS KBM RDK/DocSrc/CD_Root/Firmware/Source Code/RDK Bridge/rdk_keyboard.asm 12 7/02/04 3:42p13 10/01/04 2:52p Ary $ ; Version: 1.3.0000 ; ;**************************************************************************** ; Copyright (2003), Cypress Semiconductor Corporation ; This software is owned by Cypress Semiconductor Corporation (Cypress) and is ; protected by United States copyright laws and international treaty provisions. ; Cypress hereby grants to Licensee a personal, non-exclusive, non-transferable ; license to copy, use, modify, create derivative works of, and compile the ; Cypress Source Code and derivative works for the sole purpose of creating ; custom software in support of Licensee product ("Licensee Product") to be used ; only in conjunction with a Cypress integrated circuit. Any reproduction, ; modification, translation, compilation, or representation of this software ; except as specified above is prohibited without the express written permission ; of Cypress. ; Disclaimer: Cypress makes no warranty of any kind, express or implied, with ; regard to this material, including, but not limited to, the implied warranties ; of merchantability and fitness for a particular purpose. Cypress reserves the ; right to make changes without further notice to the materials described herein. ; Cypress does not assume any liability arising out of the application or use of ; any product or circuit described herein. Cypress’ products described herein are ; not authorized for use as components in life-support devices. ; This software is protected by and subject to worldwide patent coverage, ; including U.S. and foreign patents. Use may be limited by and subject to the ; Cypress Software License Agreement. ; ;**************************************************************************** ;**************************************************************************** ; Global Variables AND Frameworks Related Variables ;**************************************************************************** null_packet_data: equ C0h byte_len_report: equ C1h kb_offset: equ C2h kb_temp: equ C4h upkey_timer_a: equ C6h STD_KEY_STATE: equ 01h ; bit position defs for key_down_state MM_KEY_STATE: equ 02h PWR_KEY_STATE: equ 04h key_down_state: equ C7h UP_KEY_TIMEOUT: equ 04h APP_IDLE_TIMEOUT: equ 30h IFDEF ENCRYPT_DATA_A DEFINE ENCRYPT_FILLER ENDIF ; ENCRYPT_DATA_A ;**************************************************************************** ; app_data_received_a ; Input: ; X Reg = byte_len_report = Byte length of input report (-2 for hdr, chksum) ; A Reg = null_packet_data = additional info ; 0x00 => UpKey (up_key_standard only) ; 0x02 => KeepAlive ; Keyboard Report bytes in rx_buffer[], app_buffer[] ; ; Background: ; rx_buffer[] contains the input bytes from the radio including the header. ; app_buffer[] points to the first data byte. ; app_buffer is currently 1 byte offset from rx_buffer to skip the 1 byte ; header, but app_buffer[] should be used to allow changes in the length ; of the header (i.e. to allow it to use A two byte header). ; ; Note: hdr=HeaderByte sc=ScanCode mod=modifier chk=checksum res=reserved ; ReptType = report type, consumer_keys = Multimedia Keys ; ; Input Examples: (character "A" = "0x04", see Hid Usage Tables) ; rx_buffer[]= 40 04 ; "A" ; app_buffer[]= 04 ; "A" ; ; More app_buffer examples: ; ReptType/sc1 ; Scan Code 1 OR RptType consumer_keys=0xFF power_keys=0xFE ; | mod ; Modifier keys (in StandardKeys reports only) ; | | sc2 ; Scan Code 2 ... ; | | | ; 04 ; "A" ; 04 20 ; "<RightShift>A" ; 04 00 20 ; "A" AND "3" ; 04 20 20 ; "<RightShift>" AND "A" AND "3" ; FF 00 E2 ; consumer_keys "<mute>" ; FE 82 ; power_keys "<sleep>" ; 04 20 05 06 07 08 ; "A" "B" "C" "D" "E" ; ; Note that the second byte, if present is the modifier keys, AND it always ; gets sent when there is more than A single key in the packet (even if there ; are no modifier keys pressed AND the value is zero). ; This is based on the assumption that the most common report will contain ; A single key press AND no modifiers. ; Note that not more than 5 data bytes + modifier should be sent over the air ; since the 6th will not make it to the PC (1 byte is displaced by Report ID) ; ; Processing: ; Forms the USB report (swap modifier, ADD res byte, ReportID) ; AND sends data to USB. ; ; Upkey detection - certain values identify Upkeys (don't use header byte) ; if (byte_len_report == 0) AND (null_packet_data == 0) then up_key_standard ; if (byte_len_report == 1) AND (RptType == 0xFF) then UpKeyconsumer_keys ; if (byte_len_report == 1) AND (RptType == 0xFE) then UpKeypower_keys ; ; ReportTypebattery_voltage - ; if (byte_len_report == 2) AND (RptType == 0xFD) then ReportTypebattery_voltage ; ; So A sequence would be: ; byte_len_report null_packet_data app_buffer: ; 1 0 04 ; "A" ; 0 0 ; up_key_standard ; 3 0 FF 00 E2 ; consumer_keys "<mute>" ; 1 0 FF ; UpKeyconsumer_keys ; 3 0 FE 82 ; power_keys "<sleep>" ; 1 0 FE ; UpKeypower_keys ; ; A KeepAlive sequence would be: ; 1 0 04 ; "A" ; 0 2 ; KeepAlive ; 0 2 ; KeepAlive ... ; 0 0 ; up_key_standard ; ; Output: ; Sends USB packet out EP1. ; ep1_dmabuff = data to USB ; ; Output Examples: ; RptId mod res key ; 01 00 00 04 00 00 00 00 ; "A" ; 01 00 00 00 00 00 00 00 ; up_key_standard ; 01 00 00 59 00 00 00 00 ; "1" (keypad 1) ; 01 00 00 00 00 00 00 00 ; up_key_standard ; 01 00 00 16 5B 00 00 00 ; "s" AND "3" ; 01 00 00 00 00 00 00 00 ; up_key_standard ; 01 20 00 04 05 06 07 08 ; "<RightShift>" AND "A" "B" "C" "D" "E" ; 01 00 00 00 00 00 00 00 ; up_key_standard ; 02 E2 00 ; consumer_keys "<mute>" ; 02 00 00 ; UpKeyconsumer_keys ; 03 82 ; power_keys "<sleep>" ; 03 00 ; UpKeypower_keys ; ;**************************************************************************** app_init_a: MOV A, 00h MOV [battery_a],A MOV [key_down_state],A MOV A, 01h ; At startup, request the battery level MOV [batt_report_req_a],A RET app_data_received_a: DI ; Disable USB Interrupts MOV [null_packet_data],A ; null_packet_data = AC; SWAP A,X ; byte_len_report = IX; MOV [byte_len_report],A SWAP A,X MOV A,UP_KEY_TIMEOUT ; Set upkey_timer_a MOV [upkey_timer_a],A MOV A, [byte_len_report] ; skip decryption of the packet if it's a NULL packet CMP A, 08h JNZ wait_ep1_clear IFDEF ENCRYPT_DATA_A CALL decrypt_packet CALL remove_filler CMP A, 0 JZ ep1_send_end MOV [byte_len_report], A ENDIF ; ENCRYPT_DATA_A wait_ep1_clear: ; do IOWR watchdog ; WATCHDOG = AC; IORD ep1_mode ; If still waiting for USB to ACK last data, fail AND A, 0Fh CMP A, ACK_IN JZ ep1_send_end init_ep1_out: MOV A,00h ; ep1_dmabuff[0] = 0x00; MOV [ep1_dmabuff],A MOV [ep1_dmabuff+1],A ; ep1_dmabuff[1] = 0x00; MOV [ep1_dmabuff+2],A ; ep1_dmabuff[2] = 0x00; MOV [ep1_dmabuff+3],A ; ep1_dmabuff[3] = 0x00; MOV [ep1_dmabuff+4],A ; ep1_dmabuff[4] = 0x00; MOV [ep1_dmabuff+5],A ; ep1_dmabuff[5] = 0x00; MOV [ep1_dmabuff+6],A ; ep1_dmabuff[6] = 0x00; MOV [ep1_dmabuff+7],A ; ep1_dmabuff[7] = 0x00; MOV A,[byte_len_report] ; Check report length CMP A,00h JZ up_key_standard_null MOV A,[app_buffer+0] ; Check for Multimedia report CMP A,FFh JZ consumer_report CMP A,FEh ; Check for Power report JZ power_report CMP A,FDh ; Check for Battery report JZ battery_report CMP A,FCh ; Check for Keep Alive report JZ ep1_send_end CMP A,00h ; Must be Standard 101 key report JZ up_key_standard ; Check for Standard up key MOV A,STD_KEY_STATE OR [key_down_state],A ; Must be Standard down key so set appropriate bit JMP standard_keys up_key_standard_null: MOV A,00h MOV [app_buffer+0],A ; app_buffer[0] = 0x00; INC A ; byte_len_report=1; ; generate upkey MOV [byte_len_report],A up_key_standard: MOV A,~STD_KEY_STATE AND [key_down_state],A ; Clear appropriate bit JMP standard_keys consumer_report: MOV A,[pc_has_desc] CMP A,00h JZ ep1_send_end MOV A,[byte_len_report] ; Check for Multimedia up key CMP A,01h JZ up_key_consumer MOV A,MM_KEY_STATE OR [key_down_state],A ; Must be Multimedia down key so set appropriate bit JMP consumer_keys up_key_consumer: MOV A,~MM_KEY_STATE AND [key_down_state],A ; Clear appropriate bit MOV A,00h ; app_buffer[1] = 0x00; MOV [app_buffer+1],A MOV [app_buffer+2],A ; app_buffer[2] = 0x00; consumer_keys: MOV A,02h ; ep1_dmabuff[0] = 0x02; ; consumer_keys Report ID MOV [ep1_dmabuff],A MOV A,[app_buffer+2] ; ep1_dmabuff[1] = app_buffer[2]; ; Lo byte MOV [ep1_dmabuff+1],A MOV A,[app_buffer+1] ; ep1_dmabuff[2] = app_buffer[1]; ; Hi byte MOV [ep1_dmabuff+2],A MOV A,03h ; byte_len_report = 0x03; ; Report Length MOV [byte_len_report],A JMP ep1_send ; else if(app_buffer[0] == 0xFE) power_report: MOV A,[pc_has_desc] CMP A,00h JZ ep1_send_end MOV A,[byte_len_report] ; Check for Multimedia up key CMP A,01h JZ up_key_power MOV A,PWR_KEY_STATE OR [key_down_state],A ; Must be Power down key so set appropriate bit JMP power_keys up_key_power: MOV A,~PWR_KEY_STATE AND [key_down_state],A ; Clear appropriate bit MOV A,00h ; app_buffer[1] = 0x00; MOV [app_buffer+1],A power_keys: MOV A,03h ; ep1_dmabuff[0] = 0x03; ; power_keys Report ID MOV [ep1_dmabuff],A MOV A,[app_buffer+1] ; ep1_dmabuff[1] = app_buffer[1]; ; Lo byte MOV [ep1_dmabuff+1],A MOV A,02h ; byte_len_report = 0x02; ; Report Length MOV [byte_len_report],A JMP ep1_send ; else if(app_buffer[0] == 0xFD) battery_report: MOV A,[app_buffer+1] ; ep1_dmabuff[1] = app_buffer[1] Battery Level AND A, 0fh ; mask-off high-order nibble MOV [battery_a],A ; remember the battery level JMP ep1_send_end standard_keys: ; kb_offset = (pc_has_desc && protocol); ; use ReportID in ReportMode set_report_id_offset: MOV A,[pc_has_desc] CMP A,00h JZ set_offset MOV A,[protocol] CMP A,00h JZ set_offset MOV A,01h set_offset: MOV [kb_offset],A CMP A,00h ; if((kb_offset) && (byte_len_report == 7)) JZ set_standard_keys_report_id MOV A,[byte_len_report] CMP A,07h JNZ set_standard_keys_report_id DEC [byte_len_report] ; throw away 1 key if it is displaced by report ID set_standard_keys_report_id: MOV A,[kb_offset] ; if(kb_offset) CMP A,00h JZ place_first_byte MOV A,01h ; ep1_dmabuff[0] = 0x01; ; Standard Keys Report ID MOV [ep1_dmabuff],A place_first_byte: MOV A,[app_buffer+0] ; ep1_dmabuff[kb_offset+2] = app_buffer[0]; ; place first byte MOV X,[kb_offset] MOV [X+ep1_dmabuff+2],A MOV A,01h ; if(byte_len_report>1) CMP A,[byte_len_report] JNC ep1_send MOV X,[kb_offset] ; ep1_dmabuff[kb_offset+0] = app_buffer[1]; ; place modifier MOV A,[app_buffer+1] MOV [X+ep1_dmabuff+0],A ; while(byte_len_report>2) load_loop_a: MOV A,02h CMP A,[byte_len_report] ; kb_temp = app_buffer[byte_len_report-1]; JNC ep1_send MOV X,[byte_len_report] MOV A,[X+rx_buffer+0] MOV [kb_temp],A MOV A,[kb_offset] ; ep1_dmabuff[kb_offset+byte_len_report] = kb_temp; ADD A,[byte_len_report] MOV X,A MOV A,[kb_temp] MOV [X+ep1_dmabuff+0],A DEC [byte_len_report] ; byte_len_report--; JMP load_loop_a ep1_send: MOV A,[configuration] ; if(configuration && (ep1_stall != 0xFF)) CMP A,00h JZ ep1_send_end MOV A,[ep1_stall] INC A JZ ep1_send_end MOV A,80h ; ep1_data_toggle ^= 0x80; XOR [ep1_data_toggle],A MOV A,[ep1_data_toggle] OR A, 08h ; the report length IOWR ep1_count MOV A,ACK_IN ; EP_A1_MODE = USB_MODE_ACK_IN; IOWR ep1_mode ep1_send_end: MOV A,0h ; led_timer = 0x01; ; BLINK_BIND diag LED MOV [led_timer],A MOV A,[key_down_state] ; Clear upkey timer if no keys are down CMP A,00h JNZ exit_app_data_received_a MOV [upkey_timer_a],A ; upkey_timer_a = 0x00; ; Reset upkey_timer_a exit_app_data_received_a: EI RET ;------------------------------------------------------- ; app_verify_packet_a ; ;------------------------------------------------------- app_verify_packet_a: SWAP A, X ; A = packet length IFDEF ENCRYPT_DATA_A CMP A, 09h ELSE CMP A, 07h ENDIF ENCRYPT_DATA_A JNC app_verify_packet_a_failed IORD ep1_mode ; If still waiting for USB to ACK last data, fail AND A, 0Fh CMP A, ACK_IN JZ app_verify_packet_a_failed MOV A, 1 RET app_verify_packet_a_failed: MOV A, 0 RET ;**************************************************************************** ; app_idle ; ; Input: ; upkey_timer_a = Count down timer for sending UpKeyKeyboard ; upkey_timer_b = Count down timer for sending UpKeyMouse ; ; Processing: ; upkey_timer_a counts down from UP_KEY_TIMEOUT to 1 ; if(upkey_timer_a == 0) timer is idle ; if(upkey_timer_a == 1) timer triggers Upkey to be sent ; if(upkey_timer_a > 1) timer is active (decrement it) ; ; Background: ; app_idle gets called ~= 50ms ; UP_KEY_TIMEOUT == 0x07 per design ; upkey_timer_a set to UP_KEY_TIMEOUT ~= 300ms Upkey timeout period ; upkey_timer_a set to UP_KEY_TIMEOUT when A DownKey is received (elsewhere) ; upkey_timer_a set to UP_KEY_TIMEOUT when A KeepAlive received (elsewhere) ; upkey_timer_a cleared when an UpKey is received (elsewhere) ; ; Output: ; Sends USB packet out EP1. ; ep1_dmabuff = Keyboard data to USB ; ep2_dmabuff = Mouse data to USB ; ; Output Example: ; RptId mod res key ; 01 00 00 00 00 00 00 00 ; up_key_standard ; Button mod res key ; 00 00 00 00 ; UpKeyMouse ; ;**************************************************************************** app_idle_a: MOV A,[pc_has_desc] CMP A,00h JNZ if_up_key_idle MOV A,[upkey_timer_a] CMP A,00h JNZ if_up_key_idle IORD ep1_mode AND A, 0Fh CMP A, ACK_IN JZ if_up_key_idle CALL ep1_send if_up_key_idle: MOV A,[upkey_timer_a] ; if((upkey_timer_a == 0)&&(upkey_timer_b == 0)) DEC A JNC if_up_key_timer_active RET ; return if timers idle if_up_key_timer_active: MOV A,01h ; if(upkey_timer_a > 1) CMP A,[upkey_timer_a] JNC if_up_key_timer_a_timeout DEC [upkey_timer_a] ; upkey_timer_a--; if_up_key_timer_a_timeout: MOV A,[upkey_timer_a] ; if(upkey_timer_a == 1) DEC A JNZ app_idle_ret send_up_keys: MOV A,00h ; AC = 0x00; MOV [upkey_timer_a],A ; reset upkey_timer_a MOV [ep1_dmabuff+1],A ; ep1_dmabuff[1] = 0x00; MOV [ep1_dmabuff+2],A ; ep1_dmabuff[2] = 0x00; MOV [ep1_dmabuff+3],A ; ep1_dmabuff[3] = 0x00; MOV [ep1_dmabuff+4],A ; ep1_dmabuff[4] = 0x00; MOV [ep1_dmabuff+5],A ; ep1_dmabuff[5] = 0x00; MOV [ep1_dmabuff+6],A ; ep1_dmabuff[6] = 0x00; MOV [ep1_dmabuff+7],A ; ep1_dmabuff[7] = 0x00; ; Send upkey for appropriate kbd HID report types, check_standard_up_key: MOV A,STD_KEY_STATE ; Check for Standard Keys report AND A,[key_down_state] CMP A,00h JZ check_consumer_up_key CALL up_key_standard_null CALL wait_usb check_consumer_up_key: MOV A,MM_KEY_STATE ; Check for Multimedia Keys report AND A,[key_down_state] CMP A,00h JZ check_power_up_key MOV A,02h ; Consumer Keys Report ID MOV [ep1_dmabuff],A CALL ep1_send CALL wait_usb check_power_up_key: MOV A,PWR_KEY_STATE ; Check for Power Keys report AND A,[key_down_state] CMP A,00h JZ reset_key_down_state MOV A,03h ; Power Keys Report ID MOV [ep1_dmabuff],A CALL ep1_send CALL wait_usb reset_key_down_state: MOV A,00h MOV [key_down_state],A ; reset key_down_state app_idle_ret: RET ;**************************************************************************** ; app_disconnect_a ;**************************************************************************** app_disconnect_a: MOV A,01h ; AC = 0x00; MOV [upkey_timer_a],A ; reset upkey_timer_a JMP app_idle_a ;**************************************************************************** ; wait_usb ;**************************************************************************** wait_usb: IOWR watchdog IORD ep1_mode ; If still waiting for USB to ACK last data, fail AND A, 0Fh CMP A, ACK_IN JZ wait_usb RET ;**************************************************************************** ; endfile: rdk_Keyboard.asm ;****************************************************************************