blob: c811542882dd08633beb55c701c86b7e21dcddbb [file] [log] [blame]
\ *****************************************************************************
\ * Copyright (c) 2004, 2008 IBM Corporation
\ * All rights reserved.
\ * This program and the accompanying materials
\ * are made available under the terms of the BSD License
\ * which accompanies this distribution, and is available at
\ * http://www.opensource.org/licenses/bsd-license.php
\ *
\ * Contributors:
\ * IBM Corporation - initial implementation
\ ****************************************************************************/
s" keyboard" device-name
s" keyboard" device-type
." USB Keyboard" cr
3 encode-int s" assigned-addresses" property
1 encode-int s" reg" property
1 encode-int s" configuration#" property
s" EN" encode-string s" language" property
1 constant NumLk
2 constant CapsLk
4 constant ScrLk
TRUE VALUE use-interrupt-transfers?
\ Check whether we're running on QEMU - in this case we disable the
\ interrupt transfers since they are not working very well there yet.
s" model" s" /" find-node get-property 0= IF
2dup s" qemu" find-substr = TO use-interrupt-transfers?
drop
THEN
00 value kbd-addr
to kbd-addr \ save speed bit
8 value mps-dcp
8 constant DEFAULT-CONTROL-MPS
0 value multi-key
0 value led-state
0 value temp1
0 value temp2
0 value temp3
0 value ret
0 value scancode
0 value kbd-shift
0 value kbd-scan
0 value key-old
0 value expire-ms
0 value mps-int-in
0 value int-in-ep
0 value int-in-toggle
\ Buffers which must be capable of DMA:
STRUCT
80 FIELD kb>cfg \ For config descriptors etc, size 0x80
8 FIELD kb>report \ For keyboard report, size 8
8 FIELD kb>setup-packet \ For setup-packet, size 8
4 FIELD kb>data \ Various data, size 4
CONSTANT /kbd-buf
0 VALUE kbd-buf
0 VALUE kbd-buf-dma
: (kbd-buf-init) ( -- )
/kbd-buf s" dma-alloc" $call-parent TO kbd-buf
kbd-buf /kbd-buf 0 s" dma-map-in" $call-parent TO kbd-buf-dma
s" kbd-buf = " kbd-buf usb-debug-print-val
;
: (kbd-buf-free) ( -- )
kbd-buf kbd-buf-dma /kbd-buf s" dma-map-out" $call-parent
kbd-buf /kbd-buf s" dma-free" $call-parent
0 TO kbd-buf
0 TO kbd-buf-dma
;
s" usb-kbd-device-support.fs" included
: control-cls-set-report ( reportvalue FuncAddr -- TRUE|FALSE )
to temp1
to temp2
2109000200000100 kbd-buf kb>setup-packet !
temp2 kbd-buf kb>data l!-le
1 kbd-buf kb>data 1 kbd-buf kb>setup-packet
DEFAULT-CONTROL-MPS temp1 controlxfer
;
: control-cls-get-report ( data-buffer data-len MPS FuncAddr -- TRUE|FALSE )
to temp1
to temp2
to temp3
a101000100000000 kbd-buf kb>setup-packet !
temp3 kbd-buf kb>setup-packet 6 + w!-le
0 swap temp3 kbd-buf kb>setup-packet
temp2 temp1 controlxfer
;
: int-get-report ( -- ) \ get report for interrupt transfer
0 2 int-in-toggle kbd-buf kb>report 8 mps-int-in
kbd-addr int-in-ep 7 lshift or rw-endpoint \ get report
swap to int-in-toggle IF
kbd-buf kb>report @
ff00000000000000 and 38 rshift to kbd-shift \ store shift status
kbd-buf kb>report @
0000ffffffffffff and to kbd-scan \ store scan codes
ELSE
0 to kbd-shift \ clear shift status
0 to kbd-scan \ clear scan code buffer
THEN
;
: ctl-get-report ( -- ) \ get report for control transfer
kbd-buf kb>report 8 8 kbd-addr
control-cls-get-report IF \ get report
kbd-buf kb>report @
ff00000000000000 and 38 rshift to kbd-shift \ store shift status
kbd-buf kb>report @
0000ffffffffffff and to kbd-scan \ store scan codes
ELSE
0 to kbd-shift \ clear shift status
0 to kbd-scan \ clear scan code buffer
THEN
;
: kbd-get-report ( -- )
use-interrupt-transfers? IF
int-get-report
ELSE
ctl-get-report
THEN
;
: set-led ( led -- )
dup to led-state
kbd-addr control-cls-set-report drop
;
: is-shift ( -- true|false )
kbd-shift 22 and if
true
else
false
then
;
: is-alt ( -- true|false )
kbd-shift 44 and if
true
else
false
then
;
: is-ctrl ( -- true|false )
kbd-shift 11 and if
true
else
false
then
;
: ctrl_alt_del_key ( char -- )
is-ctrl if \ ctrl is pressed?
is-alt if \ alt is pressed?
4c = if \ del is pressed?
s" reboot.... " usb-debug-print
\ reset-all \ reboot
drop false \ invalidate del key on top of stack
then
false \ dummy for last drop
then
then
drop \ clear stack
;
: get-ukbd-char ( ScanCode -- char|false )
dup ctrl_alt_del_key \ check ctrl+alt+del
dup to scancode \ store scan code
case \ translate scan code --> char
04 of [char] a endof
05 of [char] b endof
06 of [char] c endof
07 of [char] d endof
08 of [char] e endof
09 of [char] f endof
0a of [char] g endof
0b of [char] h endof
0c of [char] i endof
0d of [char] j endof
0e of [char] k endof
0f of [char] l endof
10 of [char] m endof
11 of [char] n endof
12 of [char] o endof
13 of [char] p endof
14 of [char] q endof
15 of [char] r endof
16 of [char] s endof
17 of [char] t endof
18 of [char] u endof
19 of [char] v endof
1a of [char] w endof
1b of [char] x endof
1c of [char] y endof
1d of [char] z endof
1e of [char] 1 endof
1f of [char] 2 endof
20 of [char] 3 endof
21 of [char] 4 endof
22 of [char] 5 endof
23 of [char] 6 endof
24 of [char] 7 endof
25 of [char] 8 endof
26 of [char] 9 endof
27 of [char] 0 endof
28 of 0d endof \ Enter
29 of 1b endof \ ESC
2a of 08 endof \ Backsace
2b of 09 endof \ Tab
2c of 20 endof \ Space
2d of [char] - endof
2e of [char] = endof
2f of [char] [ endof
30 of [char] ] endof
31 of [char] \ endof
33 of [char] ; endof
34 of [char] ' endof
35 of [char] ` endof
36 of [char] , endof
37 of [char] . endof
38 of [char] / endof
39 of led-state CapsLk xor set-led false endof \ CapsLk
3a of 1b 7e31315b to multi-key endof \ F1
3b of 1b 7e32315b to multi-key endof \ F2
3c of 1b 7e33315b to multi-key endof \ F3
3d of 1b 7e34315b to multi-key endof \ F4
3e of 1b 7e35315b to multi-key endof \ F5
3f of 1b 7e37315b to multi-key endof \ F6
40 of 1b 7e38315b to multi-key endof \ F7
41 of 1b 7e39315b to multi-key endof \ F8
42 of 1b 7e30315b to multi-key endof \ F9
43 of 1b 7e31315b to multi-key endof \ F10
44 of 1b 7e33315b to multi-key endof \ F11
45 of 1b 7e34315b to multi-key endof \ F12
47 of led-state ScrLk xor set-led false endof \ ScrLk
49 of 1b 7e315b to multi-key endof \ Ins
4a of 1b 7e325b to multi-key endof \ Home
4b of 1b 7e335b to multi-key endof \ PgUp
4c of 1b 7e345b to multi-key endof \ Del
4d of 1b 7e355b to multi-key endof \ End
4e of 1b 7e365b to multi-key endof \ PgDn
4f of 1b 435b to multi-key endof \ R-arrow
50 of 1b 445b to multi-key endof \ L-arrow
51 of 1b 425b to multi-key endof \ D-arrow
52 of 1b 415b to multi-key endof \ U-arrow
53 of led-state NumLk xor set-led false endof \ NumLk
54 of [char] / endof \ keypad /
55 of [char] * endof \ keypad *
56 of [char] - endof \ keypad -
57 of [char] + endof \ keypad +
58 of 0d endof \ keypad Enter
89 of [char] \ endof \ japanese yen
dup of false endof \ other keys are false
endcase
to ret \ store char
led-state CapsLk and 0 <> if \ if CapsLk is on
scancode 03 > if \ from a to z ?
scancode 1e < if
ret 20 - to ret \ to Upper case
then
then
then
is-shift if \ if shift is on
scancode 03 > if \ from a to z ?
scancode 1e < if
ret 20 - to ret \ to Upper case
else
scancode
case \ translate scan code --> char
1e of [char] ! endof
1f of [char] @ endof
20 of [char] # endof
21 of [char] $ endof
22 of [char] % endof
23 of [char] ^ endof
24 of [char] & endof
25 of [char] * endof
26 of [char] ( endof
27 of [char] ) endof
2d of [char] _ endof
2e of [char] + endof
2f of [char] { endof
30 of [char] } endof
31 of [char] | endof
33 of [char] : endof
34 of [char] " endof
35 of [char] ~ endof
36 of [char] < endof
37 of [char] > endof
38 of [char] ? endof
dup of ret endof \ other keys are no change
endcase
to ret \ overwrite new char
then
then
then
led-state NumLk and 0 <> if \ if NumLk is on
scancode
case \ translate scan code --> char
59 of [char] 1 endof
5a of [char] 2 endof
5b of [char] 3 endof
5c of [char] 4 endof
5d of [char] 5 endof
5e of [char] 6 endof
5f of [char] 7 endof
60 of [char] 8 endof
61 of [char] 9 endof
62 of [char] 0 endof
63 of [char] . endof \ keypad .
dup of ret endof \ other keys are no change
endcase
to ret \ overwrite new char
then
ret \ return char
;
: key-available? ( -- true|false )
multi-key 0 <> IF
true \ multi scan code key was pressed... so key is available
EXIT \ done
THEN
kbd-scan 0 = IF \ if no kbd-scan code is currently available
kbd-get-report \ check for new scan codes
THEN
kbd-scan 0 <> \ if a kbd-scan is available, report true, else false
;
: usb-kread ( -- char|false ) \ usb key read for control transfer
multi-key 0 <> if \ if multi scan code key is pressed
multi-key ff and \ read one byte from buffer
multi-key 8 rshift to multi-key \ move to next byte
else \ normal key check
\ check for new scan code only, if kbd-scan is not set, e.g.
\ by a previous call to key-available?
kbd-scan 0 = IF
kbd-get-report \ read scan-code report
THEN
kbd-scan 0 <> if \ scan code exist?
begin kbd-scan ff and dup 00 = while \ get a last scancode in report buffer
kbd-scan 8 rshift to kbd-scan \ This algorithm is wrong --> must be fixed!
drop \ KBD doesn't set scancode in pressed order!!!
repeat
ff and dup to kbd-scan \ we can only digest one key at a time
dup key-old <> if \ if the scancode is new
dup to key-old \ save current scan code
get-ukbd-char \ translate scan code --> char
milliseconds fa + to expire-ms \ set typematic delay 250ms
else \ scan code is not changed
milliseconds expire-ms > if \ if timer is expired ... should be considered timer carry over
get-ukbd-char \ translate scan code --> char
milliseconds 21 + to expire-ms \ set typematic rate 30cps
else \ timer is not expired
drop false \ do nothing
then
then
kbd-scan 8 rshift to kbd-scan \ handled scan-code
else
0 to key-old \ clear privious key
false \ no scan code --> return false
then
then
;
: key-read ( -- char )
0 begin drop usb-kread dup 0 <> until \ read key input (Interrupt transfer)
;
: read ( addr len -- actual )
0= IF drop 0 EXIT THEN
usb-kread ?dup IF swap c! 1 ELSE 0 swap c! -2 THEN
;
(kbd-buf-init)
kbd-init \ keyboard initialize
milliseconds to expire-ms \ Timer initialize
0 to multi-key \ multi key buffer clear
7 set-led \ flash leds
250 ms
0 set-led
(kbd-buf-free)
s" keyboard" get-node node>path set-alias
: open ( -- true )
(kbd-buf-init)
7 set-led
100 ms
3 set-led
100 ms
1 set-led
100 ms
\ read once from keyboard before actually using it
usb-kread drop
0 set-led
true
;
: close
(kbd-buf-free)
;
s" Keyboard init done" usb-debug-print