Setting up my JVC XP 731

If you'd be interested in joining a mailing list on running linux on JVC's subnotebooks, do drop me a line -- I'd set up one once I've got, say, five people asking.

The JVC being such a fine machine, I'm looking for spare parts and complete systems (if mine breaks down, I want minimal downtime :-). So, if you want to sell yours, I'm offering 150 Euros for a standard 40 GB 256 MB machine, more if there's goodies added (email below).

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.

However, as usual, power management and video issues remain. This is somewhat leaning towards Debian Lenny (since this is what I'm running), but distributions running X.org 7.3 should behave quite similar. If you have an older X server, you will probably want to refer to an older version of this page.

I run my box with a self-built 2.6.27.20 kernel (kernel .config). I don't see why a fairly recent distribution kernel shouldn't work, though I'd recommend trying a similar kernel if you experience suspend/resume problems; depending on the kernel version, this may be severely broken.

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

ACPI -- sleep, wake up, hotkey

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 these guys have been doing, 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 5%-
		;;
	00000030)  # increase volume
		amixer set Master 5%+
		;;
	00000032)  # mute
		amixer set Master toggle
		;;
	00000035)  # the key with the screen
		if [ -f /var/run/video_off ]
		then
			vbetool dpms on
			rm -f /var/run/video_off
		else
			vbetool dpms off
			touch /var/run/video_off
		fi
		;;
	*)
#		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 (you should) and that you have vbetools installed (you should as well, otherwise suspend to ram won't work).

What this does is let the volume keys work as advertised. Also, the silly key supposed to switch internal lcd and external crt is used to toggle power to the internal screen. Unfortunately, the ACPI bios has some function on that key already. This causes the screen to turn on an off several times and also gives video ACPI events. I'll check the DSDT some day -- maybe this can be turned off.

If you need the key to toggle the video signal for the external video port, you could look into i855crt and run that instead of vbetool. I, however, do that differently (see below).

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"
cp /boot/grub/menu.lst.resume /boot/grub/menu.lst

sync; sync

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

logger "$0: Coming back from software suspend"

# Waking up, make sure we don't resume if we crash or reboot
cp /boot/grub/menu.lst.noresume /boot/grub/menu.lst

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 video"
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
		sox /etc/acpi/nosleep.wav -t ossdsp /dev/dsp &
	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.

Though, as far as I know, the machine will not attempt resumption unless it sees the proper signature on the swap partition, I like to play it safe and keep two copies of grub's menu.lst around, one for resuming (which is activated by the first cp) and one for normal rebooting (which is activated by the second cp).

If you roll your own kernel, bypassing the debian kernel build system (which I don't recommend but practise myself), you could have (in addition to whatever global settings you need)

title		Debian GNU/Linux, default kernel no resume
root		(hd0,0)
kernel		/vmlinux root=/dev/hda1 ro noresume
savedefault
boot

in /boot/grub/menu.lst.noresume and accordingly

title		Debian GNU/Linux, default kernel resuming
root		(hd0,0)
kernel		/vmlinuz root=/dev/hda1 ro resume=/dev/hda5 
savedefault
boot

in /boot/grub/menu.lst.resume. Of course, you must adapt the values of root and resume, with the latter pointing to your swap partition. There are probably better ways to do this -- in particular, doing this immediately locks you out of any kernel management your distribution might do.

Suspend to RAM

While software suspend needs very little of the built-in ACPI machinery, suspend to RAM critically depends on it. Unfortunately, there's much that can and will go wrong in the cooperation between ACPI and the kernel, there are oodles of possible race conditions and deadlocks and other nasty software monsters.

In other words: it's quite possible that your machine may freeze on wakeup. Have a pin or paper clip ready for the hardware reset button on the XP's left side. Having said that: If you don't try crazy stunts, suspend to RAM should work nicely, and you have your machine up and down within a couple of seconds. I'm regularly seeing hundreds of suspend/resume cycles without a glitch. Just don't touch anything and, more importantly, don't plug anything in while the machine is waking up.

The main problem with Linux and ACPI usually is Video (see Documentation/power/video.txt in your kernel tree). vbetool lets you get around this to some extent (also, kernels newer than 2.6.25 supposedly do much better here, but I haven't found time to experiment here as yet). So, here's my /etc/acpi/doze.sh:

#!/bin/bash

VIDEOHACK=false

criticalModules="ohci1394 ehci_hcd uhci_hcd video pcmcia battery"
# ignore suspend requests for this many seconds after wakeup.
deadtime=5 

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

if test -f $lastWakeupFile && 
   test $((`date +"%s"` - `date -r $lastWakeupFile +"%s"`)) -lt $deadtime
then
   logger "$0: suppressing suspend request (deadtime not over)"
	 exit 1
fi

dieIfSleepLocked


logger "$0: Putting machine in memory suspend"
cp /boot/grub/menu.lst.noresume /boot/grub/menu.lst

getLoadedCriticalModules
unloadCriticalModules

if [ t$VIDEOHACK != tfalse ]; then
	chvt 1
	vbetool vbestate save > $stateDir/vbe_saved
fi

sync; sync

echo -n mem > /sys/power/state

logger "$0: Waking up from memory suspend"

touch $lastWakeupFile

if [ t$VIDEOHACK != tfalse ]; then
#	vbetool post
	vbetool vbestate restore < $stateDir/vbe_saved
	chvt 7
fi

reloadCriticalModules


# A little gimmick: Dump a file wakeup.wav into /etc/acpi,
# have sox and oss (emulation), and the thing should play the sound
# on wakeup
if [ -f /etc/acpi/wakeup.wav ]
then
	sox /etc/acpi/wakeup.wav -t ossdsp /dev/dsp &
fi

File: /etc/acpi/doze.sh

Basically, I do the same module magic as for software suspend. In addition, I switch to a text screen (otherwise Xorg notices we've been sleeping, doesn't really know what to do and gets horribly confused), save the video bios state and sleep. After waking up, I restore the state saved when going to sleep. Finally, I switch back to the X screen. If you're not always in X, you may want to change things here.

As I said, the thing is a bit sensitive to fiddling with the machine while it's waking up. I believe there are problems that can only be fixed in the DSDT. If I find some more time, I'll look into this. For now, just make sure you've written out all important data before putting the machine to sleep and relax until the machine is up.

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

I used to give fairly elaborate xorg.confs here. Starting with xorg 7.3 with recent kernels, I believe the best strategy is to leave almost everything as it is.

Still, I believe it's a good idea to let the default X server run without 3D or anything requiring dri. This is much more stable over suspends, and I guess it uses less memory and probably power than with all the fancy stuff.

The way this works is that I have an /etc/X11/xorg-internal.conf like this:

# xorg.conf (Xorg X Window System server configuration file)
# This is MD's default configuration.  It runs without GL acceleration.

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/cyrillic"
  FontPath  "/usr/share/fonts/X11/100dpi/:unscaled"
  FontPath  "/usr/share/fonts/X11/75dpi/:unscaled"
  FontPath  "/usr/share/fonts/X11/Type1"
  FontPath  "/usr/share/fonts/X11/CID"
  FontPath  "/usr/share/fonts/X11/100dpi"
  FontPath  "/usr/share/fonts/X11/75dpi"
  FontPath  "/usr/share/fonts/X11/local"
EndSection

Section "Module"
  Disable  "GLcore"   # Right!
  Disable  "dri"
  Disable  "glx"      # don't want no stinkin' GL here.
  Disable "composite"
  Disable "damage"
EndSection

Section "ServerFlags"
  Option "AllowMouseOpenFail"
  Option "HandleSpecialKeys" "WhenNeeded"
EndSection

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

Section "InputDevice"
# This will work for the built-in stick as well as for usb mice
# with wheels you could plug in.
  Identifier  "Configured Mouse"
  Driver    "mouse"
  Option    "CorePointer"
  Option    "Device"    "/dev/input/mice"
  Option    "Protocol"    "ImPS/2"
  Option    "ZAxisMapping"    "4 5"
EndSection

Section "Device"
  Identifier  "i-LCD"
  Driver      "intel"
  Option      "DRI" "off"
  Option      "RenderAccel" "off"
  Option      "AccelMethod" "XAA"
  Option      "NoAccel"     "off"
  Option      "UseFbDev"    "true"
EndSection

Section "Monitor"
  Identifier  "LCD"
EndSection

Section "Screen"
  Identifier  "Builtin LCD"
  Device    "i-LCD"
  Monitor    "LCD"
EndSection

Section "Extensions"
  Option "Composite" "Disable"
EndSection

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

The new EXA architecture definitely doesn't work very well in 7.3, so you'll probably want to keep XAA with NoAccel off. NoAccel may be necessary in some situations.

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.

The /etc/X11/xorg.conf basically is what Debian gives you with Xorg 7.3, so it has 3D and fancy stuff. For me, this currently looks like this:

# xorg.conf (X.Org X Window System server configuration file)
#
# This file was generated by dexconf, the Debian X Configuration tool, using
# values from the debconf database.
#
# Edit this file with caution, and see the xorg.conf manual page.
# (Type "man xorg.conf" at the shell prompt.)
#
# This file is automatically updated on xserver-xorg package upgrades *only*
# if it has not been modified since the last upgrade of the xserver-xorg
# package.
#
# If you have edited this file but would like it to be automatically updated
# again, run the following command:
#   sudo dpkg-reconfigure -phigh xserver-xorg

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

Section "InputDevice"
	Identifier	"Configured Mouse"
	Driver		"mouse"
EndSection

Section "Device"
	Identifier	"Configured Video Device"
	Option    "AccelMethod"  "XAA"
	Option		"UseFBDev"		"true"
EndSection

Section "Monitor"
	Identifier	"Configured Monitor"
EndSection

Section "Screen"
	Identifier	"Default Screen"
	Monitor		"Configured Monitor"
EndSection

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. For example, this little script clones your current display:

#!/bin/sh
xrandr --addmode VGA "1024x600"
xrandr --output VGA --mode 1024x600 --same-as LVDS

File: /home/msdemlei/mybin/clonescreen

This one does a dual screen setup with a 1680x1650 external monitor, with the internal LCD below the big one (this will not work with an xorg-internal server, since its virtual size is too small:

xrandr -fb 1680x1650
xrandr --addmode VGA "1680x1050" 147.54 1680 1752 2112 2256 1050 1052 1064 1090
xrandr --output VGA --auto  --output LVDS --auto --below VGA
xrandr --dpi 72

I believe the whole thing is more stable if you add the following quirk in xserver-xorg-video-intel:

--- xserver-xorg-video-intel-2.3.2.orig/src/i830_memory.c
+++ xserver-xorg-video-intel-2.3.2/src/i830_memory.c
@@ -302,6 +318,9 @@
     /* Littlebit Sepia X35 (rebranded Asus Z37E) (See LP: #201257) */
     { PCI_CHIP_I965_GM, 0x1043, 0x8265, quirk_ignore_tv },
 
+		/* JVC XP731 does better with reset modes */
+		{ PCI_CHIP_I855_GM, 0x1043, 0x1712, quirk_reset_modes },
+
     { 0, 0, 0, NULL },
 };

Here is a Debian package with this patch applied

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@cl.uni-heidelberg.de