Tag editing
In rare cases, especially on prototype hardware, the manufacturing data may be wrong or otherwise annoying. It is somewhat risky to modify the data, though the laptop will boot with the data missing. The instructions given here assume that you can boot to an "OK" prompt, often by booting while holding down the game-X button. See the cheat codes documentation for details.
As described in "checking the Layout configuration", have a look around.
An example walk-through
In this example, it will be assumed that you wish to have the US International keyboard setting. You are not satisfied with changes made purely at the OS level, because you want US International to work 100% of the time: at the OpenFirmware prompt, at the Linux kernel console, and when starting a fresh OS install. The keyboard setting starts in the manufacturing data, might be copied to the CMOS RAM, and then is picked up by the OS.
Start by fixing the CMOS RAM data. At the ok prompt, issue the following command:
" us_INTL" set-kb-name
Note the space before the "u" character. This is required because FORTH uses a dreadful hack to implement strings. The first quote character is actually a command. (the quote character is not special to FORTH, as it is in nearly any other programming language) It must be followed by whitespace. This command has been given a special property; it executes immediately. It scans for the next quote character, which is not a command. It then creates a string, pushes a length and pointer onto the stack, and lets parsing continue on. Eeeeew...
So now the keyboard is set to us_INTL. It will soon be wiped out, probably either when OpenFirmware starts up or when OpenFirmware boots Linux. To prevent this, the language-related tags must be removed.
You need a big chunk of FORTH code for this. Some firmware versions come with it built-in. Usually the code is left out so that you will have to do extra work, risking a typo of course. If the FORTH command sifting $delete-tag does not reveal anything, then you are missing the code. It's at the bottom of this page. You can save it on a USB stick as mfg.fth, then do fload u:\mfg.fth to load it from the ok prompt. Alternately, you can just type the whole thing.
Prototype hardware like the B4 will have just one language-related tag called LA. Newer hardware will have more. See the manufacturing data page for details. Deleting a tag is done like so:
" LA" $delete-tag
At this point, your keyboard will die. Sorry. It's a hardware bug. Wait a moment, pull out the battery, disconnect the power cord, wait 10 to 30 seconds, put the battery back in, and reconnect the power cord. If you have more tags to delete, go back to the ok prompt. It is possible that you may need to fix the CMOS RAM data again if you didn't delete LA first.
For this example, there is also a Linux component. Be sure to do rm ~olpc/.olpc-configured to clear out the old settings from Linux. For old OS images which do not use that file, just do a clean install to get new settings.
mfg.fth
: ?tagname-valid ( tagname$ -- tagname$ ) dup 2 <> abort" Tag name must be 2 characters long" ; : tag-setup ( tagname$ -- ram-value$ ) ?tagname-valid get-mfg-data 2dup find-tag 0= if ." No " type ." tag" cr abort then ( tagname$ value$ ) 2nip ( value$ ) tuck tag>ram-adr swap ( ram-value$ ) ; : value-mismatch? ( new-value$ old-value$ -- flag ) dup if \ non-empty old value string 2dup + 1- c@ 0= if ( new-value$ old-value$ ) \ Old value ends in null character; subtract that from the count 1- ( new-value$ old-value$' ) then ( new-value$ old-value$ ) rot <> ( new-adr old-adr flag ) nip nip ( old-len new-value$ ) else ( new-value$ old-value$ ) \ empty old value string; new one had better be empty too 2drop 0<> nip ( flag ) then ; : $change-tag ( value$ tagname$ -- ) tag-setup ( new-value$ old-value$ ) 2over 2over value-mismatch? abort" New value and old value have different lengths" drop swap move ( ) put-mfg-data ; : change-tag ( "tagname" "new-value" -- ) safe-parse-word ( tagname$ ) 0 parse ( tagname$ new-value$ ) 2swap $change-tag ; : ram-last-mfg-data ( -- adr ) mfg-data-buf /flash-block + last-mfg-data ; : $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 ) \ 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 ) \ 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 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 ;