Author: wmb Date: 2007-10-12 11:00:06 +0200 (Fri, 12 Oct 2007) New Revision: 676
Added: cpu/x86/pc/olpc/keymap.fth cpu/x86/pc/olpc/parsekbd.py Modified: cpu/x86/pc/olpc/mfgdata.fth cpu/x86/pc/olpc/setwp.fth dev/pckbd.fth Log: OLPC trac #3985 - ASCII keymaps from the KA manufacturing data tag.
Added: cpu/x86/pc/olpc/keymap.fth =================================================================== --- cpu/x86/pc/olpc/keymap.fth (rev 0) +++ cpu/x86/pc/olpc/keymap.fth 2007-10-12 09:00:06 UTC (rev 676) @@ -0,0 +1,90 @@ +purpose: Populate keymaps from the KA manufacturing data tag +\ See license at end of file + +\ Per http://wiki.laptop.org/Manufacturing_Data#Keyboard_ASCII_Map + +h# 60 constant /submap + +\ Special hack for the OLPC keyboard multiply/divide key, which is +\ sometimes used for ASCII punctuation +: ?multkey ( scancode -- scancode' ) + \ Translate down to the range that fits in the ASCII keymaps + dup h# 73 = if drop h# 5f then +; + +: !map ( scancode ascii submap# -- ) + /submap * rot ?multkey + oem-keymap + 1+ c! +; + +\ Clear out a range of map entries +: zap ( first last -- ) + 1+ swap ?do i 0 0 !map i 0 1 !map loop +; + +: punctuation " 0123456789!""#$%&'()*+,-./:;<=>?@[]^_`{|}~" drop ; +: fill-keymap ( value$ -- ) + oem-keymap /keymap 0 fill ( adr len ) + 3 oem-keymap c! ( adr len ) \ #submaps + \ Prime the shift and unshift maps with special characters + [ also keyboards ] us [ previous ] 3 + oem-keymap 1+ /submap 2* move + + \ Clear out some the map entries for the alphanumeric/punctuation stations, + \ so we don't have confusing leftovers from the US map + 2 h# d zap h# 10 h# 1b zap h# 1e h# 29 zap h# 2b h# 35 zap + + \ Set the a-z entries - assume unshifted and infer shifted + 2dup d# 26 min 0 ?do ( value$ adr ) + dup i + c@ ( value$ adr scancode ) + [char] a i + ( value$ adr scancode ascii ) + 2dup 0 !map ( value$ adr scancode ascii ) \ Unshifted + h# 20 xor 1 !map ( value$ adr ) \ Shifted + loop ( value$ adr ) + drop ( value$ ) + dup d# 26 min /string ( value$' ) + + \ Set the 0-9 and punctuation entries in specifed maps + d# 42 min 0 ?do ( adr ) + dup i 2* + ( adr adr' ) + dup c@ ( adr adr' scancode ) + punctuation i + c@ ( adr adr' scancode ascii ) + rot 1+ c@ !map ( adr ) + loop ( adr ) + drop +; + +\ If a KA tag is present, parse it into a keymap +: olpc-keymap? ( -- got? ) + " KA" " find-tag" eval if ( value$ ) + ?free-keymap + /keymap alloc-mem to oem-keymap ( adr' len' ) + fill-keymap + oem-keymap to keymap + true + else + false + then +; + +\ LICENSE_BEGIN +\ Copyright (c) 2007 FirmWorks +\ +\ Permission is hereby granted, free of charge, to any person obtaining +\ a copy of this software and associated documentation files (the +\ "Software"), to deal in the Software without restriction, including +\ without limitation the rights to use, copy, modify, merge, publish, +\ distribute, sublicense, and/or sell copies of the Software, and to +\ permit persons to whom the Software is furnished to do so, subject to +\ the following conditions: +\ +\ The above copyright notice and this permission notice shall be +\ included in all copies or substantial portions of the Software. +\ +\ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +\ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +\ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +\ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +\ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +\ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +\ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +\ +\ LICENSE_END
Modified: cpu/x86/pc/olpc/mfgdata.fth =================================================================== --- cpu/x86/pc/olpc/mfgdata.fth 2007-10-12 00:11:50 UTC (rev 675) +++ cpu/x86/pc/olpc/mfgdata.fth 2007-10-12 09:00:06 UTC (rev 676) @@ -9,23 +9,39 @@ : invalid-tag? ( adr -- data-adr flag ) -1 hibit? if true exit then \ Name char must be 7-bit ASCII -2 hibit? if true exit then \ Name char must be 7-bit ASCII - -3 hibit? if true exit then \ Length must be 7 bits - dup 3 - c@ ( adr len ) - over 4 - c@ ( adr len ~len ) - xor h# ff <> if true exit then ( adr ) - dup 3 - c@ - 4 - ( adr' ) + -3 hibit? if \ Long (5-byte tag) format ( adr ) + dup 4 - c@ dup h# 80 and if drop true exit then ( adr low ) + over 5 - c@ dup h# 80 and if 2drop true exit then ( adr low high ) + 2dup xor h# ff xor ( adr low high check ) + 3 pick 3 - c@ <> if 3drop true exit then ( adr low high ) + 7 << + ( adr length ) + - 5 - ( data-adr ) + else \ Short (4-byte tag) format + dup 3 - c@ ( adr len ) + over 4 - c@ ( adr len ~len ) + xor h# ff <> if true exit then ( adr ) + dup 3 - c@ - 4 - ( data-adr ) + then + false ;
: last-mfg-data ( top-adr -- adr ) begin invalid-tag? until ;
: another-tag? ( adr -- adr false | adr' data$ name-adr true ) - dup invalid-tag? if ( adr data-adr ) + dup invalid-tag? if ( adr data-adr ) drop false exit - then ( adr data-adr ) - dup rot ( data-adr data-adr adr ) - 2dup swap - 4 - ( data-adr data-adr adr data-len ) - swap 2- true ( adr' data$ adr ) + then ( adr data-adr ) + >r 2- ( name-adr r: data-adr ) + dup 1- c@ h# 80 and if ( name-adr r: data-adr ) \ 5-byte format + dup 2- c@ ( name-adr lowlen r: data-adr ) + over 3 - c@ 7 lshift + ( name-adr len r: data-adr ) + else ( name-adr r: data-adr ) \ 4-byte format + dup 1- c@ ( name-adr len r: data-adr ) + then ( name-adr len r: data-adr ) + r> rot >r ( len data-adr r: name-adr ) + dup rot r> ( adr data$ name-adr ) + true ( adr data$ name-adr true ) ;
\ Mfg data used to be at the end of the EC erase block, but
Added: cpu/x86/pc/olpc/parsekbd.py =================================================================== --- cpu/x86/pc/olpc/parsekbd.py (rev 0) +++ cpu/x86/pc/olpc/parsekbd.py 2007-10-12 09:00:06 UTC (rev 676) @@ -0,0 +1,219 @@ +#!/usr/bin/python +# parsekbd.py +# Usage: python parsekbd.py OLPC_Nigeria_Keyboard +# +# Gets the wiki page (e.g.) http://wiki.laptop.org/go/OLPC_Nigeria_Keyboard +# Parses the keyboard table contained therein and converts it to a KA +# tag per http://wiki.laptop.org/go/Manufacturing_Data#Keyboard_ASCII_Map. +# +# The output is stored in a file named (e.g.) OLPC_Nigeria_Keyboard.ka +# +# Warnings on standard output tell you if duplicate entries are discarded +# or if some ASCII characters are not present. +# +# In a few cases, this program substitutes dead_{grave,circumflex,tilde} +# for {grave,asciicircumflex,asciitilde} because the ascii versions are +# in inaccessible locations (the firmware has only shift, unshift, AltGr +# maps, so a Shift-AltGr symbol is inaccessible). + +from sys import * +from urllib import * +from HTMLParser import HTMLParser + +state = 0 +keys = 128*[0] +modifiers = 128*[0] +column = 0 +keyid = 0 + +# Convert from textual names of punctuation characters to the ASCII character +punctuation = { + 'exclam':ord('!'), + 'at':ord('@'), + 'numbersign':ord('#'), + 'dollar':ord('$'), + 'percent':ord('%'), + 'asciicircum':ord('^'), + 'dead_circumflex':ord('^'), + 'ampersand':ord('&'), + 'asterisk':ord('*'), + 'parenleft':ord('('), + 'parenright':ord(')'), + 'underscore':ord('_'), + 'plus':ord('+'), + 'minus':ord('-'), + 'equal':ord('='), + 'semicolon':ord(';'), + 'colon':ord(':'), + 'apostrophe':ord('''), + 'grave':ord('`'), + 'dead_grave':ord('`'), + 'quotedbl':ord('"'), + 'dblquote':ord('"'), + 'bar':ord('|'), + 'less':ord('<'), + 'greater':ord('>'), + 'period':ord('.'), + 'slash':ord('/'), + 'backslash':ord('\'), + 'question':ord('?'), + 'comma':ord(','), + 'bracketleft':ord('['), + 'bracketright':ord(']'), + 'braceleft':ord('{'), + 'braceright':ord('}'), + 'asciitilde':ord('~') , + 'dead_tilde':ord('~') , + 'backspace':8, + 'space':32, + 'tab':9, + 'linefeed':10, + 'enter':13, + 'esc':27, + 'escape':27, + 'del':127, + 'delete':127, + '&':ord('&'), + '<':ord('<'), + '>':ord('>'), +} + +def string_to_ascii(s): + if len(s) == 0: + return -1 + if len(s) == 1: + return ord(s) + try: + i = punctuation[s] + return i + except: + pass + if (len(s) == 3) & (s[:2] == 'C-'): + return ord(s[2]) & 0x1f + return -1 + +def handle_key(modifier, s): + global keyid + ascii = string_to_ascii(s) + if ascii == -1: + return + if keys[ascii] != 0: + if (ascii >= 0x20) & (((modifier & 1) == 0) & (keys[ascii] != keyid)): + print "Discard",hex(ascii),chr(ascii),modifier,keyid,modifiers[keyid] + return + if ascii < 0x20: + if (modifier & 2) != 0: # ctrl + if keys[ascii + 0x60] == keyid: + return + if keys[ascii + 0x40] == keyid: + return + keys[ascii] = keyid + modifiers[ascii] = modifier + +class MyHTMLParser(HTMLParser): + def handle_starttag(self, tag, attrs): + global state, column, keyid + if tag == 'table': + state = state + 1 + elif tag == 'tr': + column = 0 + keyid = 0 + elif tag == 'td': + column = column + 1; + + def handle_data(self, data): + global state, column, keyid + if state != 1: + return + s = data.strip() + if column == 1: # XKB key + pass + elif column == 2: # HID + pass + elif column == 3: # Key + if s.isdigit(): + keyid = int(s) + elif column == 4: # Unmodified + handle_key(0,s) + elif column == 5: # Shift + handle_key(1,s) + elif column == 6: # AltGR + handle_key(4,s) + elif column == 7: # Shift AltGr + # handle_key(5,s) + pass + elif column == 8: # Ctrl + handle_key(2,s) + elif column == 9: # Fn + handle_key(8,s) + elif column == 10: # comment + pass + + +# This table converts from the IBM physical keystation number to +# the corresponding scancode value in scan set 1. + +# 0 1 3 3 4 5 6 7 8 9 +scan1_map = [ + 0x00, 0x29, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, # 0x + 0x0a, 0x0b, 0x0c, 0x0d, 0x00, 0x0e, 0x0f, 0x10, 0x11, 0x12, # 1x + 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x2b, # 2x + 0x3a, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, # 3x + 0x27, 0x28, 0x2b, 0x1c, 0x2a, 0x56, 0x2c, 0x2d, 0x2e, 0x2f, # 4x + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x73, 0x36, 0x1d, 0x00, # 5x + 0x38, 0x39, 0x38, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00, # 6x + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, # 7x + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, # 8x + 0x45, 0x47, 0x4B, 0x4F, 0x00, 0x00, 0x48, 0x4C, 0x50, 0x52, # 9x + 0x37, 0x49, 0x4D, 0x51, 0x53, 0x4A, 0x4E, 0x00, 0x1c, 0x00, # 10x + 0x01, 0x00, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, # 11x + 0x43, 0x44, 0x57, 0x58, 0x00, 0x46, 0x00, 0x00, 0x00, 0x00, # 12x + 0x79, 0x01, 0x00, 0x5c, 0x73, 0x6e, 0x00, 0x00, 0x00, 0x00, # 13x (analog intermediates) + 0x00, 0x00, 0x00, 0x00, 0x00, # 14x +] + +def put_ka_format(outfile): + global keys, modifiers + # a-z - output scancode only; unshifted map is implied + # and shifted map is derived automatically + for i in range(ord('a'),ord('a')+26): + if (keys[i] == 0): + print "Missing",chr(i) + if modifiers[i] != 0: + print chr(i),"is modified" + outfile.write(chr(scan1_map[keys[i]])) + + # Numbers and punctuation - output scancode and keymap number + for i in '0123456789!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~': + ascii = ord(i) + if (keys[ascii] == 0): + print "Missing",i + if (modifiers[ascii] & 0xa) != 0: + print i,"is Ctrl or Fn" + outfile.write(chr(scan1_map[keys[ascii]])) + + if (modifiers[ascii] & 0x4) != 0: + # modifier & 4 implies AltGr map + outfile.write(chr(2)) + else: + # otherwise it's either the shift (1) or unshift (0) map + outfile.write(chr(modifiers[ascii] & 1)) + + outfile.write(chr(0)) # Null terminator + + outfile.write(chr(111 ^ 0xff)) + outfile.write(chr(111)) + outfile.write('KA') + +if len(argv) != 2: + print "Usage: python parsekbd.py PageName" +else: + infile = urlopen('http://wiki.laptop.org/go/' + argv[1]) + myparser=MyHTMLParser() + myparser.feed(infile.read()) + myparser.close() + infile.close() + + outfile = open(argv[1] + '.ka', 'w') + put_ka_format(outfile) + outfile.close()
Property changes on: cpu/x86/pc/olpc/parsekbd.py ___________________________________________________________________ Name: svn:executable + *
Modified: cpu/x86/pc/olpc/setwp.fth =================================================================== --- cpu/x86/pc/olpc/setwp.fth 2007-10-12 00:11:50 UTC (rev 675) +++ cpu/x86/pc/olpc/setwp.fth 2007-10-12 09:00:06 UTC (rev 676) @@ -117,19 +117,57 @@ : $add-tag ( value$ name$ -- ) ?tagname-valid ( value$ name$ ) 2dup find-tag abort" Tagname already exists" ( value$ name$ ) + get-mfg-data ram-last-mfg-data >r ( value$ name$ r: adr ) - 2 pick 1+ over + 3 + ( value$ name$ record-len r: adr ) + + \ Check for enough space for the new tag + 2 pick ( value$ name$ datalen r: adr ) + dup d# 16383 > abort" Tag data too long" + dup d# 127 > if 4 else 3 then + ( value$ name$ datalen' r: adr ) + over + ( value$ name$ record-len r: adr ) r@ over - mfg-data-buf u<= abort" Not enough space for new tag" + + \ Ensure that the space is not being used for something else r@ over - swap ?erased ( value$ name$ r: adr ) + + \ Copy the tag name r@ 2- swap move ( value$ r: adr ) - dup 1+ dup r@ 3 - c! invert r@ 4 - c! ( value$ r: adr ) - 0 r@ 5 - c! ( value$ r: adr ) - r> 5 - over - ( value$ data-adr ) - swap move - put-mfg-data + + \ Set the length field + dup ( value$ len r: adr ) + dup d# 127 > if ( value$ len r: adr ) + \ 5-byte tag format - (top) check, lowlen, highlen (bottom) + dup 7 rshift swap h# 7f and ( value$ len-high len-low r: adr ) + 2dup xor h# ff xor ( value$ len-high len-low check r: adr ) + r@ 3 - c! r@ 4 - c! r@ 5 - c! ( value$ r: adr ) + r> 5 - ( value$ end-adr ) + else ( value$ len' r: adr ) + \ 4-byte tag format - (top) len, ~len (bottom) + dup r@ 3 - c! invert r@ 4 - c! ( value$ r: adr ) + r> 4 - ( value$ end-adr ) + then ( value$ end-adr ) + + \ Copy the value data + over - swap move ( ) + + put-mfg-data ( ) ;
+: add-null ( adr len -- adr' len' ) $cstr cscount 1+ ; + : add-tag ( "name$" "value$" -- ) - safe-parse-word 0 parse 2swap $add-tag + safe-parse-word 0 parse add-null 2swap $add-tag ; + +: $delete-tag ( name$ -- ) + tag-setup ( ram-value$ ) + 2dup + c@ h# 80 and ( ram-value$ tag-style ) + if 4 else 5 then + >r ( tag-adr tag-len ) + ram-last-mfg-data >r ( tag-adr r: len bot-adr ) + r@ 2r@ + ( tag-adr src-adr dst-adr r: len bot-adr ) + rot r@ - ( src-adr dst-adr copy-len r: len bot-adr ) + move ( r: len bot-adr ) + r> r> h# ff fill ( ) + put-mfg-data +;
Modified: dev/pckbd.fth =================================================================== --- dev/pckbd.fth 2007-10-12 00:11:50 UTC (rev 675) +++ dev/pckbd.fth 2007-10-12 09:00:06 UTC (rev 676) @@ -211,6 +211,21 @@ oem-keymap if oem-keymap /keymap free-mem then 0 to oem-keymap ; +[ifdef] olpc +: ?olpc-keyboard ( -- ) + " enable-intf" $call-parent + begin get-data? while + drop + true to keyboard-present? + 5 ms + repeat + keyboard-present? if exit then + kbd-reset 0= to keyboard-present? +; + +fload ${BP}/cpu/x86/pc/olpc/keymap.fth +[then] + : choose-type ( -- ) my-args dup if [char] , left-parse-string 2swap 2drop ( $ ) @@ -231,6 +246,10 @@ exit then
+[ifdef] olpc-keymap? + olpc-keymap? if exit then +[then] + " us" set-keyboard \ pc-keyboard-type set-keyboard ; @@ -335,21 +354,10 @@ false ;
-: ?olpc-keyboard ( -- ) - " enable-intf" $call-parent - begin get-data? while - drop - true to keyboard-present? - 5 ms - repeat - keyboard-present? if exit then - kbd-reset 0= to keyboard-present? -; - : reset ( -- ) init-data clear-state -[ifdef] olpc +[ifdef] ?olpc-keyboard ?olpc-keyboard [else] get-initial-state @@ -677,6 +685,8 @@ \ Split the scancode into the up/down indicator and the key identifier h# 80 /mod 0= swap ( down? scan ) +[ifdef] ?multkey ?multkey [then] + \ Exit if the scancode is one that is never used for ASCII characters dup h# 60 >= if 2drop false exit then ( down? scan )