Saturday, January 26, 2008

Finally got a clean way to boot from the internal MMC on the N810!

The next step for me was to get the N810 to boot from the internal MMC. Following the instructions on the maemo.org wiki, I got something half working. After going through a few hoops I eventually got it right, with no side effects that I could see (besides the faster load times ;). Another problem was that the literature available so far doesn't really apply to the latest OS2000 version (2.2007.50-2). I'll write a more complete how-to later, but here's a quick outline of the steps:
  1. The first thing is to setup a boot menu. One of the problems I had here was that the initfs was seeing the internal card as mmcblk1 whilst the OS once booted sees it as mmcblk0. Well, actually once booted the kernel still sees the internal as mmcblk1:
    ~ $ cat /proc/partitions
    major minor #blocks name

    254 0 7977472 mmcblk0
    254 1 7973376 mmcblk0p1
    254 8 1966080 mmcblk1
    254 9 1441791 mmcblk1p1
    254 10 524288 mmcblk1p2
    But udev seems to swap them when creating the entries in /dev:
    ~ $ ls -l /dev/mmcblk*
    brw-rw---- 1 root floppy 254, 8 Jan 26 14:44 /dev/mmcblk0
    brw-rw---- 1 root floppy 254, 9 Jan 26 14:55 /dev/mmcblk0p1
    brw-rw---- 1 root floppy 254, 10 Jan 1 1970 /dev/mmcblk0p2
    brw-rw---- 1 root floppy 254, 0 Jan 26 14:44 /dev/mmcblk1
    brw-rw---- 1 root floppy 254, 1 Jan 26 14:56 /dev/mmcblk1p1
    It's very likely a kernel bug and seems to occur only on N810. When trying to boot from MMC, this causes two problems:

    • With no external SD card plugged in, the boot menu sees the internal one as mmcblk0, which is fine. But as soon as there's an external card plugged in, the internal one becomes mmcblk1. The obvious problem here is that the boot menu won't behave in a consistent manner depending on the card configuration.

    • Once booted, and with an external card plugged in, the root of the file system will be mounted on mmcblk1p2, which doesn't exist.

    I initially tried to fix the second problem (which seems purely cosmetic) by rewriting the mmcblk* nodes in the initfs and completely ignored the more serious issues caused by the inconsistent behaviour of the boot menu.

    Graham Cobb came up with a very elegant way to make the boot menu always boot from the internal card, regardless of the presence of an external one.

  2. Now that the boot menu is patched, let's move on to partitioning and copying the root file system. And reboot from MMC!

  3. Now we need to fix USB mounting. It'll break at some point because the system tries to unmount every mmcblk*p*, including the root filesystem (mounted on /dev/mmcblk1p2....) and bails out as soon as there's an error. The fix is to edit /usr/sbin/osso-mmc-umount.sh so that it doesn't try to unmount "/". Changing
    if [ $? = 0 ]
    to
    if [ $? = 0 -a "$MP" != "/" ]
    should to the trick.

  4. Alright, got the USB working but a Linux host will mount the root partition as well! This time the problem is that the whole disk is shared over USB. i.e. it shares mmcblk0 and mmcblk1, not individual partitions. This time the fix is to edit /usr/sbin/osso-usb-mass-storage-enable.sh so that it shares only the first partition of a device instead of the whole device. Basically, add something like DEVICE=${1}p1 near the beginning of the file and replace all instances of $1 with $DEVICE.
Now I can flash the N810 back to the original firmware and poke around some more :)

References:

[1] http://fanoush.wz.cz/maemo/#initfs
[2] http://maemo.org/community/wiki/howto_easily_boot_from_mmc_card/
[3] http://www.internettablettalk.com/forums/showthread.php?t=11703
[4] http://www.internettablettalk.com/forums/showpost.php?p=124657&postcount=73

Thursday, January 24, 2008

IP Over Bluetooth and Connection Manager Integration

How do I get Internet access from my Internet Tablet at work with no WiFi access point available? The only solution I have is to use IP over Bluetooth (i.e. L2CAP), and connect through my laptop. After a lot of google-ing I eventually found a solution that works on OS2008 (aka maemo 4 , aka chinook). Well, that sorts out the "getting connected" part of the problem.

For Integration in the connection manager the solution described in the maemo community wiki seemed to fit the bill but the binary provided for the dbus listening daemon won't run on OS2008. Bummer. Digging around I found an enhanced version that can launch scripts based on user defined filters: dbus-scripts written by Graham Cobb.

Now on to the interesting stuff...
  1. For the PC or phone side configuration, refer to the BluetoothNetworking page at maemo.org.

  2. On the N810, you need root access as described in the previous post.

  3. Install the dbus-scrips package from the maemo xtras-devel repository. (thanks Graham for uploading!)

  4. Run X term and login as root:

    sudo su -

  5. Create a dummy access point:

    gconftool-2 -s -t string /system/osso/connectivity/IAP/BluetoothIP/type DUMMY

  6. create the filter for the dbus-scripts daemon. Put the following in a file named for example bluetooth-ip.filter then copy the file on your Tablet in /etc/dbus-scripts.d/

    /usr/local/share/dbus-scripts/bluetooth-ip * * com.nokia.icd status_changed BluetoothIP DUMMY

    This will launch the script /usr/local/share/dbus-scripts/bluetooth-ip as soon as the BluetoothIP connection is brought up or down from the connection manager.

  7. And here's the actual bluetooth-ip script that does all the dbus magic:

    #!/bin/sh

    #BT MAC of PC/phone
    BTADDR='00:19:CC:EB:42:3E' # replace with your own!
    #bluetooth name of PC/phone, not important, just for infoprints
    BTNAME="PC-Bluetooth"
    #desired IP address of your tablet
    IP=192.168.0.2
    #default gateway - IP address of PC/phone
    GW=192.168.0.1
    #DNS server
    NS=123.45.67.89

    # remote PAN role, one of NAP, GN
    PAN_ROLE=NAP

    infoprint(){
    DBUS_SESSION_BUS_ADDRESS='unix:path=/tmp/session_bus_socket' dbus-send --session --print-reply --dest=org.freedesktop.Notifications /org/freedesktop/Notifications org.freedesktop.Notifications.SystemNoteInfoprint "string:$*" &
    }

    dbus_method(){
    local dest=$1
    shift
    DBUS_REPLY=$(dbus-send 2>&1 --system --type=method_call --print-reply --dest="$dest" $* )
    }

    dbus_result(){
    echo $DBUS_REPLY | cut -d ' ' -f 7 | tr -d \"
    }

    find_connection(){
    #find or create connection

    echo "Searching for $BTADDR ..."
    [ -t 1 ] || infoprint "Searching for $BTADDR"

    if dbus_method org.bluez /org/bluez org.bluez.Manager.ActivateService string:network ; then
    NET_BUS=$(dbus_result)
    # echo destination $NET_BUS
    if dbus_method "${NET_BUS}" /org/bluez/network org.bluez.network.Manager.FindConnection string:"${BTADDR}" ; then
    CONN=$(dbus_result)
    else
    if dbus_method "${NET_BUS}" /org/bluez/network org.bluez.network.Manager.CreateConnection string:"${BTADDR}" string:"$PAN_ROLE" ; then
    CONN=$(dbus_result)
    fi
    fi
    fi

    if [ "$CONN" = "" ] ; then
    echo $DBUS_REPLY
    echo "Setting up connection to $BTADDR failed"
    [ -t 1 ] || infoprint "Connection to $BTADDR failed"
    exit
    fi
    }

    bnep_start(){
    find_connection
    if dbus_method "${NET_BUS}" ${CONN} org.bluez.network.Connection.Connect ; then
    BNEPDEV=$(dbus_result)
    echo connected to $BNEPDEV
    ifconfig $BNEPDEV $IP up
    if route -n | grep -q '^0.0.0.0' ; then
    echo "default gateway already set, skipping GW and DNS setting"
    else
    route add default gw $GW
    echo "nameserver $NS" >/tmp/resolv.conf.lo
    fi
    [ -t 1 ] || infoprint "Connected to $BTNAME"
    fi
    }

    bnep_stop(){
    find_connection
    if [ "$CONN" != "" ] ; then
    echo connection $CONN
    if dbus_method "${NET_BUS}" ${CONN} org.bluez.network.Connection.Disconnect ; then
    echo "OK, bringing down"
    echo -n '' >/tmp/resolv.conf.lo
    [ -t 1 ] || infoprint "$BTNAME disconnected"
    fi
    fi
    }

    [ "$3" = "com.nokia.icd" ] || exit 0
    [ "$7" = "CONNECTED" ] && bnep_start
    [ "$7" = "IDLE" ] && bnep_stop

    Place this script in /usr/local/share/dbus-scripts (you may have to create the folder) and make it executable:

    chmod +x /usr/local/share/dbus-scripts/bluetooth-ip

    This is heavily based on this forum thread at InternetTabletTalk.com. You'll find additional info on the various parameters of the script in that thread. And thanks to fanoush for his hard work on this!

  8. Now all you have to do is restart the dbus-scripts daemon:

    /etc/init.d/dbus-scripts restart

  9. Make sure that your N810 and PC or phone have been paired: Settings -> Control Panel -> Bluetooth -> Devices -> New.

  10. Go to the connection manager and select your new BluetoothIP connection..... and cross your fingers!

Troubleshooting tips:
  • From Xterm you can run the dbus-scripts daemon in debug mode. Stop it first (as root):

    /etc/init.d/dbus-scripts stop

    Now start it manually in debug mode:

    dbus-scripts --system --debug

    Try to connect again and go back to the Xterm window to see if there's any error message (scroll up!)

  • If you get a notification that the connection is established but you can't access any web site, check that the DNS in the bluetooth-ip script is set to the same as on your computer (try ipconfig from the command line). You can also try to ping your computer or phone. If you get a reply, then the problem is very likely on the computer or phone.

  • Make sure that the IP addresses in the bluetooth-ip script match with your computer's or phone. Also make sure you select IP addresses in the same subnet.

  • If you're trying this while you have a WiFi access point nearby and your Tablet is set to automatically connect to it, disable automatic connections, otherwise the connection manager will automatically pick up the access point instead of starting the dummy connection.
Granted, it's not really for the faint of heart. But in the end it's quite rewarding. What would one do to avoid typing a few commands in a terminal? ;)

How to become root on a N810 with the latest OS2008 update

I couldn't be bothered with the earlier versions of the Nokia Internet Tablets which lacked a hardware keyboard, but when Nokia released the N810, I had to get one!

One of first problems get root access. With the latest update of the OS, the root password has changed and the only solution is to enable R&D mode. Despite what the HowDoiBecomeRoot wiki page says, enabling R&D mode with the flasher tool works on the N810 (no idea about N800):
  1. Get the flasher-3.0 tool from the Nokia restricted downloads

  2. Run 'flasher-3.0-static –enable-rd-mode’ using the same process described for firmware updates (plug in the N810 with the power off, run command, power on while holding home key). Thanks to Mike Rowehl for the tip.

  3. On the N810, start Xterm and enter 'sudo gainroot'. You're in business!

  4. Now you need to secure the root account. The following is taken from the HowDoiBecomeRoot wiki page. Needless to say that if you don't understand what you're doing or make any typos during this process, there's a very high chance that you'll turn your tablet into a paperweight.

    1. Set a password for your user account:
      passwd user
    2. Allow "user" to use the su command so that you can actually logon as root (better that the gainroot method). Watch out, it's ">>" not ">"...
      echo "user ALL = PASSWD: /bin/su" >> /etc/sudoers
    3. Now we need to secure the root account, i.e. disable any direct logons as root by disabling its password:
      passwd -l root
    4. Done! From now on, all you have to do to login as root is:
      sudo su -

Happy hacking!