Setting up my JVC XP 731

Installing Linux on the JVC XP 731 (a.k.a. Asus S200 N) is not a big deal -- it's a fairly standard Centrino machine. The only thing that may cause you headache is the installation medium. If you don't have a USB cdrom, I recommend netbooting the beast. You can access the setup menu by pressing Alt-F2 while the machine shows its BIOS screen (by default, it's some flashy picture, though there is a BIOS setting that gives you a more informative output). To let the machine netboot, you'll first have to enable the boot rom on the corresponding BIOS page, exit the setup, and the fix the boot priority by entering the BIOS a second time.

You'll find more info on the basic setup on the corresponding pages on TuxMobil.

With Debian Squeeze, everything should run out of the box. If you want to run X servers older than 7.3, you will probably want to refer to an older version of this page.

I run my box with a self-built 2.6.35 kernel (kernel .config). It is possible that you won't get xvideo with 2.6.32 kernels; I'm not sure what the final squeeze kernel will do, so let's see.

Though hotplug/udev do save you quite a bit of hardware detection hassles, I've found it convenient to help it at boot time by having an /etc/modules (in Debian -- other distributions may use different files) with:

# /etc/modules: kernel modules to load at boot time.
#
# This file should contain the names of kernel modules that are
# to be loaded at boot time, one per line.  Comments begin with
# a "#", and everything on the line after them are ignored.

psmouse
pcspkr
e100
rtc
snd_intel8x0
snd_mixer_oss
snd_pcm_oss
asus_laptop
fuse
acpi_cpufreq

File: /etc/modules

(you'll want to replace ipw2200 with ipw2100; I've put in the 2200 after the 2100 started to behave weirdly, and I had a 2200 lying around).

ACPI -- sleep, wake up, hotkey

Note: By now, everything probably works out of the box. So, in all likelihood, you will not want to jump through the hoops described here.

Hotkeys

To make ACPI work, you must have acpid installed. It is usually configured in a bunch of files in /etc/acpid. Your distribution may already have populated that directory. Unless you understand what's happening in there, if you want to run the system proposed here I advise you move that cruft out and give it a fresh start.

Let's first get the hotkeys working. They are handled by the asus_acpi module. Once you have it inserted in your kernel, acpid receives the relevant events. You just need to tell it what to do with them. Creating /etc/acpi/events/hotkeys and putting

event=hotkey.*
action=/etc/acpi/hotkey.sh %e

File: /etc/acpi/events/hotkeys

in there (the syntax for the files in .../event is a bit Debian-specific, so man acpid) tells it to call /etc/acpi/hotkey.sh for each event starting with "hotkey". Some sort of keycode is passed to that script as its third argument. Thus, for the XP 731, hotkey.sh could look like this:

#!/bin/sh
case "$3" in
	0000006c)  # Sleep button
		/etc/acpi/doze.sh
		;;
	0000006d)  # Suspend to disk button
		/etc/acpi/sleep.sh
		;;
	00000031)  # decrease volume
		amixer set Master 2%-
		;;
	00000030)  # increase volume
		amixer set Master 2%+
		;;
	00000032)  # mute
		amixer set Master toggle
		;;
	00000035)  # the key with the screen
		logger "The key with the screen :-)"
		;;
	*)
#		logger "$0: Unknown hotkey: $@"
		;;
esac

File: /etc/acpi/hotkey.sh

I'll give my doze.sh and sleep.sh scripts below. The rest assumes you're running ALSA for sound (you should). What this does is let the volume keys work as advertised. The "key with the screen" is bound to some deadly function by the ACPI bios; without some change to the DSDT it probably can't be used to do useful things.

Software Suspend

We want two ways of sleeping: Suspend to RAM and suspend to disk. Suspend to RAM is far more difficult, so let's look at suspend to disk first. The hotkeys above expect the script in /etc/acpi/sleep.sh:

#!/bin/bash

. /etc/acpi/utils.sh
if [ -z "$stateDir" ]
then
	logger "$0: utils.sh could not be sourced"
	exit 1
fi

getLoadedCriticalModules
unloadCriticalModules

logger "$0: Putting machine in software suspend"

sync; sync

echo shutdown > /sys/power/disk
echo disk > /sys/power/state

logger "$0: Coming back from software suspend"

reloadCriticalModules

File: /etc/acpi/sleep.sh

with the following /etc/acpi/utils.sh:

# This script defines a few functions useful for all things acpi-related


criticalModules="ohci1394 ehci_hcd uhci_hcd"
stateDir=/var/run/sleep
sleepLockFile=$stateDir/lock
lastWakeupFile=$stateDir/lastWakeup


dieNoSuspend() {
	reloadCriticalModules
	if [ -f /etc/acpi/nosleep.wav ]
	then
		amixer set Master 100
		amixer set PCM 100
		play /etc/acpi/nosleep.wav
	fi
	logger "$0: Won't suspend: $*"
	exit 1
}

reloadCriticalModules() {
# This only works if unloadCriticalModules has been called before.
	for modName in $unloadedModules
	do
		modprobe $modName
	done
}

unloadCriticalModules() {
# You need to call getLoadedCriticalModules first, it sets the global
# loadedCriticalModules
	modStatus="ok"
	unloadedModules=""
	for modName in $loadedCriticalModules
	do
		rmmod $modName || modStatus="fail"
		unloadedModules=`echo $unloadedModules $modName`
	done
	# first attempt may have failed because someone was looking at
	# some bad file for an instant, try again once
	if [ $modStatus == "fail" ]
	then
		logger "$1: Unload modules failed, retrying once."
		reloadCriticalModules
		for modName in $loadedCriticalModules
		do
			rmmod $modName  2> /var/run/sleep/rmmod.prot || dieNoSuspend "$modName in use:" `cat /var/run/sleep/rmmod.prot`
			unloadedModules=`echo $unloadedModules $modName`
		done
	fi
}


filterLoadedModules() {
	for modname in $*
	do
		lsmod | grep "^$modname " | awk '{print $1}'
	done 
}

getLoadedCriticalModules() {
	loadedCriticalModules=`filterLoadedModules $criticalModules`
}


dieIfSleepLocked() {
	if lockfile -! -r 0 $sleepLockFile
	then
		logger "$0: Sleep processing in progress, ignoring request"
		exit 1
	fi
	trap unlockSleep EXIT
}


unlockSleep() {
	rm -f $sleepLockFile
}

File: /etc/acpi/utils.sh

The functions in utils use crude locking to keep multiple instances of sleep scripts from running. I believe acpid serializes event handlers anyway, so this kind of locking may not be necessary, but I wouldn't bet. Make sure /var/run/sleep exists and is only writable by root.

There are also functions to identify which modules out of a predefined set are loaded, to remove them, and to reload removed modules. These exchange information through global variables. Yikes. Feel free to amend the list of critical modules or take some out. You shouldn't remove the usb modules from this list, though. Under certain circumstances they'll go mad on wakeup, enticing the kernel to disable all kinds of interrupts. This then basically kills most of the PCI I/O the machine does (e.g., network).

The script will refuse to suspend if any of the modules cannot be removed (e.g., because you've still mounted a file system from a usb disk). So, always check that the machine is really sleeping before you put it into bags or tight spaces with insufficient ventilation. You can drop a wav file named nosleep.wav into /etc/acpi. It will be played at full volume if the machine can't sleep, which may help warn you.

The sleep.sh itself uses the Linux software suspend rather than the ACPI one -- it's much less hassle and about as fast. Just compile support for that into your kernel. Software suspend works by writing out the RAM to a swap partition before turning the box off and then passing a kernel option when booting. The kernel option tells the machine to restore the RAM from the swap partition.

Suspend to RAM

To let the machine sleep when you close the lid, add /etc/acpi/events/lid with the contents

event=button/lid.*
action=/etc/acpi/lid.sh

File: /etc/acpi/events/lid

and then say something like

#!/bin/bash

if [ -f /var/lock/ignorelid ]; then
	exit 0
fi

. /etc/acpi/utils.sh
if [ -z "$stateDir" ]
then
  looger "$0: utils.sh could not be sourced"
  exit 1
fi

if [ ! -f $sleepLockFile ]
then
  /etc/acpi/doze.sh
else
  logger "$0: Lid event while sleep in progress -- ignoring."
fi

File: /etc/acpi/lid.sh

in /etc/acpi/lid.sh. With kernels starting with 2.6.20, you need the primitive state mangagement built in above -- there is a deadtime in which requests to put the machine to sleep are ignored. Otherwise, the lid event generated by opening the box would put your machine to sleep again, and that's not so nice:-).

You could also bind the software suspend to the power button in an analogous fashion.

Video

As of Debian Squeeze, don't configure anything for the default X. I do this by giving an empty file /etc/X11/xorg-internal.conf:


File: /etc/X11/xorg-internal.conf

Now say

command=/usr/X11R6/bin/X -audit 0 -config xorg-internal.conf

in the [server-Standard]-Section of /etc/gdm/gdm.conf. This makes gdm use the no-dri config for its servers, so that's what you get when you log in. Other login managers should have similar options, and it's trivial to figure out what to do if you're using startx.

In squeeze, it seems for the intel driver the default will be to have Shadow on. This inhibits direct rendering (and thus GPU usage). To have fast 3D, you'll need to turn shadow off. You can do this in a special /etc/X11/xorg.conf that could look like this:

# xorg.conf (Xorg X Window System server configuration file)
# This is MD's "special" config for the JVC XP731.  Note that you really
# want to run your "standard" server without any xorg.conf and use this
# only when you really need directly rendered 3D.  This *will* lead
# to GPU lockups on Debian squeeze sooner or later.

Section "Files"
  FontPath        "unix/:7100"                        # local font server
  # if the local font server has problems, we can fall back on these
  FontPath  "/usr/share/fonts/X11/misc"
  FontPath  "/usr/share/fonts/X11/Type1"
  FontPath  "/usr/share/fonts/X11/100dpi"
  FontPath  "/usr/share/fonts/X11/75dpi"
EndSection

Section "Module"
        Load        "bitmap"
        Load        "dbe"
        Load        "ddc"
        Load        "dri"
        Load        "extmod"
        Load        "freetype"
        Load        "glx"
        Load        "int10"
        Load        "record"
        Load        "vbe"
        Load        "evdev"
EndSection

Section "ServerFlags"
   Option "DefaultServerLayout" "Default Layout"
   Option "AllowMouseOpenFail"
   Option "RandR" "on"
   Option "DontVTSwitch" "off"
   Option "DontZap" "off"
   Option "AllowClosedownGrabs" "on"
   Option "AllowDeactivateGrabs" "on"
   Option "HandleSpecialKeys" "always"
EndSection

Section "InputDevice"
  Identifier  "Generic Keyboard"
  Driver      "kbd"
  Option      "CoreKeyboard"
  Option     "XkbRules"       "xorg"
  Option     "XkbModel"       "pc105"
  Option     "XkbLayout"      "de"
  Option     "XkbOptions"     "nodeadkeys"
  Option     "XkbOptions" "ctrl:nocaps"
EndSection

Section "InputDevice"
  Identifier  "Configured Mouse"
  Driver      "mouse"
  Option      "CorePointer"
  Option      "Device"             "/dev/input/mice"
  Option      "Protocol"           "ImPS/2"
  Option      "ZAxisMapping"       "4 5"
EndSection

Section "Device"
# Internal display only
  Identifier    "i-LCD"
  Driver        "intel"
  BusID         "PCI:0:2:0"
  Option "Shadow" "off"
EndSection

Section "Monitor"
  Identifier      "InternalLCD"
  Option          "DPMS"
  HorizSync       28-50
  VertRefresh     43-75
	DisplaySize 196 144
  Modeline        "1024x600" 50 1024 1104 1176 1248 600 603 619 630
  Modeline        "320x240"  12.588 320 336 384 400 240 245 246 262 Doublescan
EndSection


Section "Screen"
  Identifier        "BuiltinLCD"
  Device            "i-LCD"
  Monitor           "InternalLCD"
  DefaultDepth      24
  SubSection "Display"
    Depth                16
    Modes                "1024x600" "800x600" "640x480"
  EndSubSection
  SubSection "Display"
    Depth                24
    Modes                "1024x600" "800x600" "640x480"
  EndSubSection
EndSection


Section "ServerLayout"
# Just GL accelerated internal screen
  Identifier      "Default Layout"
  Screen          "BuiltinLCD"
  InputDevice     "Generic Keyboard"
  InputDevice     "Configured Mouse"
EndSection

Section "DRI"
        Mode        0666
EndSection

Section "Extensions"
    Option "Composite" "Enable"
EndSection
# vi:et:

File: /etc/X11/xorg.conf

So, if you actually need 3D, you start another server, e.g., like this (I'm using sawfish, so this is cheap):

# The following gives you a GL server on vt 8
startx -- :1 

Usually, you're not allowed to start servers from within an X session, which causes this to bomb out. To enable it, in Debian you have to dpkg-reconfigure xserver-common (or edit /etc/X11/Xwrapper.config by hand, saying allowed_users=anybody).

Instead of the plethora of screens and layouts I used to have in the xorg.conf, you can now use xrandr. I use this within a script that caters to a few scenarios I need now and then:

#!/bin/sh

. ~/.alias

case $1 in
	dual)
		export XSTARTUP=dualscreen
		startx -- :1
		xrandr --output LVDS1 --auto --output VGA1 --off
		;;
	dualbeamer)
		export XSTARTUP=dualbeamer
		startx -- :1
		xrandr --output LVDS1 --auto --output VGA1 --off
		;;
	beamer)
		export XSTARTUP=beamer
		startx -- :1
		xrandr --output LVDS1 --auto --output VGA1 --off
		;;
	demo)
		export XSTARTUP=demo
		startx -- :1
		xrandr --output LVDS1 --auto --output VGA1 --off
		;;
	single)
		killall xlogo
		xrandr --output VGA1 --off
		lid
		xset +dpms
		;;
	clone)
		xrandr --addmode VGA1 "1024x600"
		xrandr --output VGA1 --mode 1024x600 --same-as LVDS1
		xset -dpms
		nolid
		;;
	extend)
		xset -dpms
		xrandr --output LVDS1 --auto --pos 0x0 --output VGA1 --auto --above LVDS1
		xrandr --dpi 72
		/home/msdemlei/mybin/blotch&
		;;
	bigscreen)
		export XSTARTUP=bigscreen
		startx -- :1
		xrandr --output LVDS1 --auto
		;;
	video)
		cp ~/.mplayer/config.narrow ~/.mplayer/config
		export XSTARTUP=video
		startx -- :1
		xrandr --output VGA1 --off
		cp ~/.mplayer/config.normal ~/.mplayer/config
		;;
	dri)
		export XSTARTUP=local
		startx -- :1
		;;
	ag)
		xrandr --output VGA1 --mode 1280x800 --above LVDS1
		;;
	*)
		echo "Unknown video configuration: $1"
		exit 1
esac

File: /home/msdemlei/mybin/confscreen

ACPI viewing

The JVC has two batteries, which is something most applets don't really provide for. That's why I started hacking wmacpimon. My current result is available here. I'll do a proper release some day, and I'll give it a name of its own, because it doesn't have that terribly much in common with wmacpimon any more. Do let me know if you use it. It would definitely be a motivation to develop this thing into some well-behaved nice, cpu-saving monitor applet.

Note that at least on my machine, the calibration of the external battery is way off. If claims to have about three times the capacity it really has. In consequence, the applet right now estimates the power consumption of the machine way too high while running from the external battery (about 30 Watts instead of about 12 Watts). This, in turn, means that the running time from the internal battery is grossly underestimated. When the machine switches from external to internal battery you'll note that the power drain drops and the remaining run time increases dramatically (you should get about one hour out of the internal battery). If anyone has a good suggestion on how to fix this, please let me know (I wonder how Windows copes with shit like that -- if it does at all, that is).


If you've got stuff to contribute: msdemlei@ari.uni-heidelberg.de