Tag editing

From OLPC
Revision as of 22:39, 25 November 2007 by 24.110.145.202 (talk) (New page: 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 th...)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

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
;