📄 usbmain.asm
字号:
;========================================================================
; This is the Cypress USB Keyboard + PS2 Mouse demonstration firmware.
; It supports the following features:
; - Ch. 9 and HIDView compliance
; - String Descriptors
; - Suspend / Resume / Remote Wakeup
; - Send keys on change
; - N-Key rollover
; - Debounce
; - Phantom keys
; - Boot protocol
; - Plug and Play PS/2 Mouse Port
;
;REVISIONS:
;08/17/99 bth rewrote endpoint 0 ISR
;02/02/99
; bth added set idle, get idle for mouse/power keys
; added boot protocol switching on 2nd endpoint (mouse/power)
; added get_report for mouse and power key packets
; altered mechanism for maintaining idle period
; by removing it from ISR and placing it in SendKeyboardReport
;11/09/98 bth added power management support
CPU 63413
;label: XPAGEON
;========================================================================
; data variable assignments
;========================================================================
; control endpoint 0 fifo
endpoint_0: equ F8h ; control endpoint
; definitions for SETUP packets
bmRequestType: equ F8h
bRequest: equ F9h
wValue: equ FAh ; default wValue (8-bits)
wValueHi: equ FBh
wIndex: equ FCh ; default wIndex (8-bits)
wIndexHi: equ FDh
wLength: equ FEh ; default wLength (8-bits)
wLengthHi: equ FFh
; definition for OUT packets
outbyte: equ F8h
; interrupt endpoint 1 fifo
endpoint_1: equ F0h ; keyboard endpoint
modifiers: equ F0h
; interrupt endpoint 2 fifo
endpoint_2: equ E8h ; power/media keys endpoint
datastack_start: equ E0h ; start of data stack
; data memory variables
;------------------------------------------------------------------------
; To support the USB specification.
remote_wakeup_status: equ usbmain_ram_base
; remote wakeup request
; zero is disabled
; two is enabled
configuration_status: equ (usbmain_ram_base+1)
; configuration status
; zero is unconfigured
; one is configured
ep1_stall_status: equ (usbmain_ram_base+2) ; zero is not stalled
ep2_stall_status: equ (usbmain_ram_base+3) ; one is stalled
protocol_status: equ (usbmain_ram_base+4) ; zero is boot protocol
; one is report protocol
; support SetIdle and GetIdle
kbd_idle_period: equ (usbmain_ram_base+5) ; keyboard idle period
kbd_idle_period_ctr: equ (usbmain_ram_base+6) ; keyboard idle period
mouse_idle_period: equ (usbmain_ram_base+7) ; mouse idle period
mouse_idle_period_ctr: equ (usbmain_ram_base+8) ; mouse idle period
consumer_idle_period: equ (usbmain_ram_base+9) ; consumer keys idle period
consumer_idle_period_ctr:equ (usbmain_ram_base+10) ; consumer keys idle period
power_idle_period: equ (usbmain_ram_base+11) ; power idle period
power_idle_period_ctr: equ (usbmain_ram_base+12) ; power idle period
1ms_counter: equ (usbmain_ram_base+13) ; 4ms counter
data_start: equ (usbmain_ram_base+14) ; points to start of descriptor
data_count: equ (usbmain_ram_base+15) ; current length of descriptor
byte_count: equ (usbmain_ram_base+16) ; current size of transmission
temp: equ (usbmain_ram_base+17)
;--------------------------------------------------------------------------
suspend_counter: equ (usbmain_ram_base+18) ; contains number of idle bus msecs
;------------------------------------------------------------------------
; application support
;------------------------------------------------------------------------
page: equ (usbmain_ram_base+19) ; page location of descriptor(RAM,
; ROM page 1, ROM page 2
EP0_mode_shadow: equ (usbmain_ram_base+20) ; variable to store ep0 mode
; used by set_ep0_mode
ps2_tmp: equ (usbmain_ram_base+21) ; temporary variable for port 3 write by PS/2
background_flags: equ (usbmain_ram_base+22) ; signal flags for background
usb_leds: equ (usbmain_ram_base+23) ; overcurrent debounce counter
last_key_report: equ (usbmain_ram_base+24)
EP0_fifo_shadow: equ (usbmain_ram_base+25)
EP_A0_counter_shadow: equ (usbmain_ram_base+26)
EP0_Next_Mode: equ (usbmain_ram_base+27)
EP0_FLAG: equ (usbmain_ram_base+28)
USBMAIN_RAM_SIZE: equ 29
SUSPEND_FLAG: equ 1
SCAN_FLAG: equ 2
;========================================================================
; program listing
;========================================================================
;========================================================================
; The 128 uSec interrupt is not used by the keyboard code. The keyboard
; only does not require the DAC or GPIO port in this version of
; firmware. It may be necessary to enable GPIO interrupts when the
; keyboard enters a power down suspend mode.
DoNothing_ISR:
reti ; return from interrupt
;========================================================================
; Suspend
;
; This routine is invoked from the main loop when bus activity has ceased for
; 3 msec or more. This routine prepares the keyboard for suspension, suspends
; the part, and restores the keyboard upon a subsequent resume.
;========================================================================
; Suspend
;
; This routine is invoked from the main loop when bus activity has ceased for
; 3 msec or more. This routine prepares the keyboard for suspension, suspends
; the part, and restores the keyboard upon a subsequent resume.
Suspend:
push A
; (since all pins are guaranteed to not float)
call mouse_suspend ; put PS/2 mouse in stream mode
di ; disable interrupts
mov A, RESISTIVE_NEG ; all ports resistive neg so that
iowr GPIO_Config ; we stay within suspend current budget (500uA)
mov A, 0 ; pull down the column lines
iowr Port0_Data
iowr Port1_Data
mov A, [ksc_p3out]
or A, P3_LED_MASK ; turn LEDs off
and A, ~P3_KEY_MASK ; don't touch bit 6 & 7 (PS/2 mouse interface)
iowr Port3_Data
mov A, FFh
iowr Port2_Interrupt ; enable port 2 GPIO interrupt for keyboard
mov A, GPIO_ONLY_MASK ; enable GPIO interrupt only
iowr Global_Interrupt
mov A, [remote_wakeup_status] ; is remote wakeup feature enabled?
cmp A, ENABLE_REMOTE_WAKEUP
jnz Suspend_controller
ei
Suspend_controller:
iord Status_Control ; set the suspend bit causing suspend
or A, 08h
iowr Status_Control ; we are suspended here
; resume !!!!!!
nop ; execute a nop after resuming
di
iowr Watchdog
iord USB_Status_Control ; check if there is no bus activity
and A, 08h
cmp A, 00h
jnz GPIO_disable_interrupts ; if there is bus activity,
; disable interrupts and exit
mov A, TIMER_ONLY_MASK ; enable 1ms interrupt
iowr Global_Interrupt
ei
mov A, [1ms_counter] ; clear wakeup counter
add A,5
wakeup_delay: ; wait 5ms before we send the wakeup signal
iowr Watchdog
cmp A, [1ms_counter]
jnz wakeup_delay
di ; disable interrupts
iord USB_Status_Control ; check again if there is no bus activity
and A, 08h ; after 5ms
cmp A, 00h
jnz GPIO_disable_interrupts ; if there is bus activity,
; disable interrupts and exit
mov A, FORCE_J ; force J state to correct cross-over voltage
iowr USB_Status_Control ; problem during resume signalling
mov A, FORCE_K ; start sending resume signal
iowr USB_Status_Control
ei ; enable 1ms interrupt again
mov A, [1ms_counter] ; clear wakeup counter
add A,0ah
wakeup_duration: ; send resume signal for 10ms
iowr Watchdog
cmp A, [1ms_counter]
jnz wakeup_duration
di ; disable interrupts
mov A, NOT_FORCING ; let SIE control D+/D-
iowr USB_Status_Control
GPIO_disable_interrupts: ;
;interrupts are off when we get here
iord USB_Status_Control
and A, F7h ; clear Bus Activity bit
iowr USB_Status_Control
mov A, 0
iowr Port2_Interrupt ; disable GPIO interrupt for keyboard
mov A, GPIO_TIMER_RESET_MASK ; enable GPIO and 1ms interrupts
iowr Global_Interrupt
ei
call mouse_resume ; put PS/2 mouse into polling mode
di
Skip_suspend:
mov A, NORMAL ; restore original GPIO configuration
iowr GPIO_Config
mov A,0
mov [suspend_counter],A
call ksc_restore_ports ; restore column ports to pre-suspend values
ei
pop A
ret
check_activity:
iord USB_Status_Control ; check if there is bus activity
and A, 08h
ret
;========================================================================
; The 1 msec interrupt is used to clear the watchdog timer, to maintain
; all timers with a 1msec granularity
;========================================================================
One_mSec_ISR:
inc [1ms_counter] ;increment 1msec timer
mov A,[1ms_counter]
and A,3
jnz check_bus_activity_status ;every 4 msec, do the following:
mov A,[background_flags] ; set the flag to scan the keyboard
or A,SCAN_FLAG
mov [background_flags],A
check_bus_activity_status:
iord USB_Status_Control ; check if there is no bus activity
and A, 08h
cmp A,0h
jz Inc_counter ; if there was bus activity
iord USB_Status_Control ; clear the bus activity bit
and A, 0F7h
iowr USB_Status_Control
mov A, 0h ; clear the suspend counter
mov [suspend_counter], A ;
jmp Exit_1ms
Inc_counter: ;there was no bus activity,
inc [suspend_counter] ;so increment the bus activity counter
mov A,[suspend_counter]
cmp A, 03h ;if 3msecs of bus inactivity passed
jc Exit_1ms
mov A,[background_flags] ; set the suspend flag
or A,SUSPEND_FLAG
mov [background_flags],A ;
Exit_1ms:
call mouse_1mS_int ; call the mouse 1msec ISR code.
pop A
reti ; return from interrupt
;========================================================================
; Endpoint one is used to send keyboard data to the host. This interrupt
; occurs if the USB serial interface engine has transferred a packet
; to the host (including NAKs).
;
; This routine disables another transfer until valid data has been loaded
; into the endpoint. This routine is also responsible for toggling the
; data 0/1 bit for endpoint one after every successful transfer.
USB_EP1_ISR:
push A ; save accumulator on stack
iord EP_A1_Mode ; test whether we have an ACK bit
and A, ACK_BIT
jz doneEP1 ; do nothing if we don't have an ACK bit
mov A, NAKIN ; clear ACK bit
iowr EP_A1_Mode
iord EP_A1_Counter ; flip data 0/1 bit after
xor A, DATATOGGLE ; a successful data transfer
iowr EP_A1_Counter
doneEP1:
pop A ; restore accumulator from stack
reti ; return from interrupt
;========================================================================
; Endpoint two is used to consumer/power key data to the host. This interrupt
; occurs if the USB serial interface engine has transferred a packet
; to the host (including NAKs).
;
; This routine disables another transfer until valid data has been loaded
; into the endpoint. This routine is also responsible for toggling the
; data 0/1 bit for endpoint one after every successful transfer.
USB_EP2_ISR:
push A ; save accumulator on stack
iord EP_A2_Mode ; test whether we have an ACK bit
and A, ACK_BIT
jz doneEP2 ; do nothing if we don't have an ACK bit
mov A, NAKIN ; clear ACK bit
iowr EP_A2_Mode
iord EP_A2_Counter ; flip data 0/1 bit after
xor A, DATATOGGLE ; a successful data transfer
iowr EP_A2_Counter
doneEP2:
pop A ; restore accumulator from stack
reti ; return from interrupt
;========================================================================
; The DAC interrupt is unused
DAC_ISR:
reti ; return from interrupt
;========================================================================
; The GPIO interrupt normally occurs as a result of the mouse clock transitioning.
; This happens during normal operation.
;
;
; GPIO interrupts can also occur if the keyboard is in suspend and a key is pressed
; or the mouse is moved. In this case, this GPIO interrupt will wake up the keyboard
; and control will return to the code executing just after the suspend bit was set.
; Note that this routine calls mouse_int, even if the keyboard might have generated
; the interrupt. This is OK because mouse_int is internally protected from doing
; anything rash during a suspend operation. So, rather than incur overhead to determine
; if the keyboard is the source of an interrupt during suspend, we let the call
; to mouse_int go through anyway.
GPIO_ISR:
ei ;allow nesting
iowr Watchdog ; clear Watchdog timer
call mouse_int ;call mouse interrupt stuff
reti
;========================================================================
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -