?? ps2_io.asm
字號:
;-------------------------------------------------------------------------
; For CKHub, While these routine is executed, interrupt should be disabled.
;-------------------------------------------------------------------------
;========================================================================
; FILE: ps2_io.asm
;
;8/25/98 Added a 50 usec delay prior to sending commands.
;Some PC's did not like it without this delay.
;
;
;========================================================================
;========================================================================
; FUNCTION: ps2_send
;
; Sends a byte
;
;
; Returns:
; C= 0 if transmission was successful
; C= 1 if not
;
;========================================================================
ps2_send:
push A ; save our data byte
push X ; save X register
MOV X, A ; save data byte momentarily in X
iord PS2_PORT ; get clock/data pair
and A, (PS2_CONNECT+PS2_CLOCK_BIT+PS2_DATA_BIT) ; mask off other bits in port
cmp A, (PS2_CONNECT+PS2_CLOCK_BIT+PS2_DATA_BIT) ; if both are not high,
jz .l1
SETC
JMP .error ; exit this routine with carry set
.l1:
DELAY 50 ; allow some spacing between bytes for
; some PC's.
call send_0 ; clock out start bit
jc .error ; if a problem, quit now
MOV A, 1
MOV [ps2_temp0], A ; keep track of parity
MOV A, X ; get back our data byte
MOV X, 8 ; count 8 bits
.l2:
asr A ; shift bit to send into carry
jc .one ; if carry is zero
call send_0 ; send a zero
jc .error ; problem, quit now
JMP .next ;
.one: ; else
call send_1 ; send a 1
jc .error ; problem, quit now
inc [ps2_temp0] ; keep track of parity
.next: ;
dec X ; decrement counter
jz .parity ; if at zero do parity
jnc .l2 ; if -1, exit
.stopbit:
call send_1 ; clock out stop bit
CLEARC
JMP .exit
.parity:
MOV A, [ps2_temp0] ; now send parity too
JMP .l2
.exit:
MOV A, [p3_shadow]
OR A, (PS2_CONNECT+PS2_CLOCK_BIT+PS2_DATA_BIT) ; make sure PS2 bus is left idle
MOV [p3_shadow], A
iowr PS2_PORT
JMP .return
.error:
MOV A, [p3_shadow]
OR A, (PS2_CONNECT+PS2_CLOCK_BIT+PS2_DATA_BIT) ; make sure PS2 bus is left idle
MOV [p3_shadow], A
iowr PS2_PORT
SETC
.return:
POP X
POP A
ret ;return
;========================================================================
; FUNCTION: send_0,send_1
;
; Sends bit out the ps2 port
;
;
; Returns:
; C= 0 if transmission was successful
; C= 1 if not
;
;========================================================================
send_1:
PUSH A
MOV A, [p3_shadow]
OR A, (PS2_CONNECT+PS2_CLOCK_BIT+PS2_DATA_BIT)
JMP clock
send_0:
PUSH A
MOV A, [p3_shadow]
OR A, (PS2_CLOCK_BIT)
and A, ~(PS2_DATA_BIT)
clock:
PUSH A ; prior to sending a bit
iord PS2_PORT
and A, PS2_CLOCK_BIT ; check for clock inhibit
POP A ;
jnz .l1 ; if there is an inhibit
SETC ; quit right now
POP A
ret
.l1:
iowr PS2_PORT ; set up register
DELAY 5
AND A, ~(PS2_CLOCK_BIT)
iowr PS2_PORT ; write it out
DELAY 35 ; delay as per spec
OR A,(PS2_CLOCK_BIT)
iowr PS2_PORT
DELAY 30 ; wait as per spec
CLEARC
POP A
ret
;========================================================================
; FUNCTION: getbit
;
; Receives a bit
;
;
; Returns:
; C = state of bit clocked in
;
;========================================================================
getbit:
PUSH A ; PUSH A
iord PS2_PORT ; host inhibit, skip this nonsense
and A, PS2_CLOCK_BIT
jz .error
MOV A, [p3_shadow]
OR A, (PS2_DATA_BIT)
AND A, ~(PS2_CLOCK_BIT) ; start with clock low, data high
iowr PS2_PORT
DELAY 35 ; wait 35 usec
OR A, (PS2_CLOCK_BIT)
iowr PS2_PORT ;
IFDEF CombiKB
DELAY 12 ; JUK
iord PS2_PORT ;
DELAY 14 ;
ELSE
DELAY 5 ; wait 5 usec
iord PS2_PORT ; read the data line
DELAY 21 ; wait 25 usec
ENDIF
; (total time clock high should be
; around 40 us per logitech.
; actual clock high can be affected
; by 1ms interrupt plus jitter
; in this code and in ps2_receive.
; empirical calculation gives the minimum
; delay time here as 25 us, which
; still satisfies the minimum allowed
; clock high time of 30 us. while
; giving us an average time of around
; 37-38 us.
AND A, PS2_DATA_BIT ; mask off all but data bit
JZ .low ; if data bit high,
SETC ; set the carry
.low:
POP A ; POP acc and rotate carry into msb
rrc A
CLEARC ; clear carry indicating success
ret ; return
.error:
POP A
SETC
ret
;========================================================================
; FUNCTION: ps2_receive
;
; Receives a byte
;
;
; Returns:
; C= 0 if reception was successful
; C= 1 if not
;
;========================================================================
ps2_receive:
PUSH X ; save X, we'll wipe it out
MOV X, 18 ; do the following 18 times:
.wait: ;
DELAY 7 ; kill time for 7 us
iord PS2_PORT ; get port 3 data
and A, PS2_DATA_BIT ; make sure data bit low
jnz .exitearly ; out now if not
dec X ; wait again
jnz .wait ;
; above loop consumes approx 180 us.
.start:
; DELAY 5 ; wait prior to anything
MOV X, 8 ; count 9 bits (8 data, 1 parity)
MOV A, 0 ; clear parity count
MOV [ps2_temp0], A
.l1:
call getbit
jc .inhibit ; if not inhibiting
cmp A, 80h ; see if msbit = 1
jc .next ; yup,
inc [ps2_temp0] ; increment parity count
.next:
dec X ; decrement counter
jc .done ; if at -1, done
jnz .l1
PUSH A ; else save partial result
JMP .l1
.inhibit: ; we were inhibited in
dec X ; the middle of getting stuff,
jc .done ; adjust stack appropriately
PUSH A
.done:
;arrive here with data byte on the stack and the received parity bit in the msb
;of the accumulator. the calculated parity bit is in the lsb of ps2_temp0.
;if we arrived here due to host inhibit, both parity and data byte are
;garbage but that's ok -- we'll abort out of this routine anyway.
MOV A, [ps2_temp0]
and A, 1
MOV X, A
; X should be 1 if ok
call getbit ; get stop bit
jc .error ; if no problem getting it
rlc a
jc .ack ; if it's not a 1
MOV X, 0 ; X= 0 indicates an error
.badstop: ;
call getbit ; keep looking for it
jc .error
rlc a
jnc .badstop
.ack:
; arrive here with x = 0 if no errors
call send_0 ; send a 0 to ack the transaction
MOV A, X
cmp A, 0
jz .error
.exit:
MOV A, [p3_shadow]
OR A, (PS2_CONNECT+PS2_CLOCK_BIT+PS2_DATA_BIT) ; make sure PS2 bus is left idle
MOV [p3_shadow], A
iowr PS2_PORT
JMP .return
.error:
MOV A, [p3_shadow]
OR A, (PS2_CONNECT+PS2_CLOCK_BIT+PS2_DATA_BIT) ; make sure PS2 bus is left idle
MOV [p3_shadow], A
iowr PS2_PORT
SETC ; set carry indicating a problem
.return:
POP A ; POP result into ACC
POP X ; restore X
ret
.exitearly:
SETC
POP X
ret
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -