[SR17 running linux]

Stupid Vaio Tricks (on Linux)

This page describes how Linux users can set up the sonypi driver which controls the Jog Dial and function keys on a Sony Vaio laptop, where to get the user-space utilities to talk to the driver, and how to configure them to do whatever you want. I have a Vaio SR17, so this page is oriented toward that machine.

Building the kernel with the driver enabled

The 2.4.7 Linux kernel (and perhaps earlier ones as well) include (under "Character Devices") the "Sony Programmable I/O Control Module" setting in the 2.4.7 kernel. (You might want to read /usr/src/linux-2.4.7/Documentation/sonypi.txt for some background on this driver.) Configure your kernel normally (see my Vaio SR17 Linux page if you want some specific suggestions) and turn on the sonypi driver. If you're on an SR or Picturebook, you'll need to enable the function key driver: see below.

Note: In the past I had heard that sonypi was incompatible with ACPI, but APM was okay. This is no longer entirely true: sonypi can work in an ACPI-enabled kernel, but trying to use ACPI functions can sometimes disable the device. A related question is whether it's possible to get the jog dial working as an ACPI device (which might be important for more recent ACPI-only Sony SR laptops). On my SR17, I don't see any hint of the device using a 2.4.21pre3 ACPI kernel. I'd be interested to hear whether it does show up in the newer ACPI-dependant SR models.

Enable function (Fn) keys

If you have a 505, you probably don't need this section. But those of us with the micro-laptops (SR and picturebook) have software function keys which don't do anything unless you enable function key mode in the sonypi driver. (Note, I'm talking about keys like Fn-F5, which changes screen brightness on Windows and is labelled as such on the Sony keyboard.) However: it turns out that enabling fcnkeys also (most of the time) disables the power switch, so you can no longer suspend. I really like being able to suspend the machine (can't do it with apm -- both apm -S and apm -s hang the machine on resume, regardless of what apm options I select in the kernel. The function keys don't show up in /proc/acpi with an ACPI kernel, so that's no help. I just leave function keys disabled -- don't need them.

Module, or compiled in? It's better to build sonypi as a module if you can get away with it. It means that the module isn't loaded until you actually use it, and you can turn on options like fnkeysinit (see Documentation/sonypi.txt for the lines to add to modules.conf, but be sure to change them for the minor device number used by your system, or use modprobe to insert the module).

Make the device

Once your kernel is built, make the device. You have to figure out the right minor device number. If you compile as a module, you might be able to set it in /etc/modules.conf (see sonypi.txt for details). Otherwise, run dmesg and look for a line like:
sonypi: device allocated minor is 61
(I see 61 on my SR17 when sonypi is a module, 63 when it's built in; I think the 505 series uses 250.) Now, substituting the right minor device number:
  mknod /dev/sonypi c 10 61

Getting and building the user-space programs

If your kernel is 2.6.9 and all you want is for the jogdial to emulate a mousewheel (scroll and press), then you're done! The sonypi driver now, by default, forwards events to the input driver to make jogdial events look like mousewheel events. Tres cool!

If you're running an older kernel, you'll need a user-space driver to monitor the sonypi device and turn jogdial events into simulated mouse events (or whatever else you want to do with them). Go to Stelian Pop's site to get the user-space drivers; pick up both sonypid and spicctrl, as they're small and there's useful stuff in both.

Type make to build the utilities. I had to #ifdef out the SONYPI_EVENT_PKEY* events in the switch statement in sonypid.c, because those symbols aren't defined in the 2.4.7 kernel. Now run sonypid in your X initialization script (.xinitrc on most systems, .Xclients on Redhat 7.1) and the jog dial will scroll like a mouse wheel, assuming you've set up X to handle that.

Setting up XFree86 for mouse scrolling

To make X pay attention to mousewheel events, you need to add this line to /usr/lib/X11/XF86Config:
    ZAxisMapping 4 5
(thanks to Colas Nahaboo X mouse wheel scroll page for that tip). Do that and make sure the appropriate kernel modules are loaded, and add "sonypid &" or "jog_scroll &" or whatever to your X startup script (.Xclients on Redhat, .xinitrc everywhere else) and you'll be all set.

Changing screen brightness

The sonypi driver also controls screen brightness. That's what spicctrl does. spicctrl -B gets the current screen brightness; spicctrl -b brightness sets it. If you want your Fn keys to do it, see below.

Volume control

You don't need sonypid for changing volume, but it's a useful thing to add to your jogdial handler. Tip: aumix -v -6 and aumix -v +6 lower and raise the volume by 6 points (out of 100).

Adding functionality to sonypid

Wheel scrolling is cool, and in fact is the most important thing I wanted the jog dial to do. But once I had that working, I couldn't resist playing with other features. This describes how to modify sonypid.c to do some other nifty tricks.

If you aren't comfortable making modifications to the programs yourself (or just want something that works), you can download a tarball of the programs I use here. Extract the tarball (tar xzvf akkjog.tgz), cd into the directory and type make. It will make two programs, called bright and sonypid. Copy these programs to some directory that's in your path (/usr/local/bin, $HOME/bin or somewhere like that).

Bright just changes the arguments to the spicctrl program; I could never keep -b and -B straight, so typing "bright" tells me the screen brightness while "bright nn" sets the screen brightness. With my version of sonypid, clicking the wheel is like a middle mouse push, rolling the wheel does scrolling (simulating a mouse wheel), and rolling the wheel while pushing adjusts screen brightness. The F4 and F5 keys also control screen brightness, if you have them enabled in the driver (which I don't since it interferes with power management). Also, if you're not sure the driver is working, you can run with -d to get debug messages.

(Note that if sonypid is running, running bright at the same time will shut out sonypid's access to the device; don't mix them. I run sonypid from my .Xclients, and only use bright when I'm in the console.)

My customizations in bright and sonypid

(and how to add your own customizations):

First, it sounded like a fun idea to have jog-dial-press be like middle-mouse press (i.e., paste the selection). That's easy:

			case SONYPI_EVENT_JOGDIAL_RELEASED:
				simulateButton(disp, 2);
				verboseEvent("Jogdial Released");
				break;

Then I noticed SONYPI_EVENT_JOGDIAL_DOWN_PRESSED, and had the idea that it would be neat if pressing the jog dial brought up a context menu in whatever app I was in, and turning it while pressed moved the selection in the context menu. This was also pretty easy:

        static int ctxtMenuUp = 0;
        static int ctxtMenuChanged = 0;
[ ... ]
			case SONYPI_EVENT_JOGDIAL_DOWN_PRESSED:
                                ctxtMenuChanged = 1;
				simulateKeyPress(disp, "Down");
				verboseEvent("Jogdial Down & Pressed");
				break;
			case SONYPI_EVENT_JOGDIAL_UP_PRESSED:
                                ctxtMenuChanged = 1;
				simulateKeyPress(disp, "Up");
				verboseEvent("Jogdial Up & Pressed");
				break;
			case SONYPI_EVENT_JOGDIAL_PRESSED:
                                ctxtMenuUp = 1;
                                simulateButton(disp, 3);
				//simulateKeyRelease(disp, "Return");
				verboseEvent("Jogdial Pressed");
				break;
			case SONYPI_EVENT_JOGDIAL_RELEASED:
                                if (ctxtMenuUp) {
                                    if (ctxtMenuChanged)
                                        simulateKeyPress(disp, "Return");
                                    else
                                        simulateButton(disp, 3);
                                    ctxtMenuUp = 0;
                                    ctxtMenuChanged = 0;
                                } else {
                                    simulateButton(disp, 2);
                                }
				verboseEvent("Jogdial Released");
				break;
(The theory is that if you just press, it'll still paste, but if you turn it while it's pressed, it'll navigate the menu and so won't paste.) But it turned out I didn't like this much. It works great in apps that have context menus and allow up/down arrows to navigate them, but lots of Linux apps don't, and I don't like what it does in rxvt (I middlemouse paste in rxvt a lot more than I use context menus in any app) so I gave up on this idea.

Finally, wouldn't it be nice if your Fn keys controlled brightness like they do on Windows? The following code goes brighter when you press Fn-F5, dimmer when you press Fn-F6. (But I'm not running this myself; I leave my function keys disabled because they interfere with power management, i.e. the machine won't sleep when I toggle the power key, and that's more important to me.)

#include <sys/ioctl.h>
[ ... ]
static int spic_ioctl(int, __u8 *);
void changeBrightness(int incr);
[ ... ]
			case SONYPI_EVENT_FNKEY_F5:
                                changeBrightness(15);
				verboseEvent("Fn-F5 Pressed");
				break;
			case SONYPI_EVENT_FNKEY_F6:
                                changeBrightness(-15);
				verboseEvent("Fn-F6 Pressed");
				break;
[ ... ]
void changeBrightness(int incr)
{
    __u8 value8;
    if (spic_ioctl(SONYPI_IOCGBRT, &value8) < 0)
        return;
    value8 += incr;
    spic_ioctl(SONYPI_IOCSBRT, &value8);
}

/*
 * Sends a ioctl command to the SPIC driver.
 *
 * Return: 0 if success, -1 if an error occured.
 */
static int spic_ioctl(int ioctlno, __u8 *param) {
	int fd;

	if ( (fd = open("/dev/sonypi", O_RDWR)) == -1) {
		fprintf(stderr, "Failed to open /dev/sonypi: %s\n", 
			strerror(errno));
		return -1;
	}
	if (ioctl(fd, ioctlno, param) < 0) {
		fprintf(stderr, "ioctl failed: %s\n", strerror(errno));
		return -1;
	}
	close(fd);
	return 0;
}
(Note, spic_ioctl and the knowledge of how to do this is lifted from the spicctrl.c program, by the nice people at Alcove Labs.)

But after I disabled my function keys, I needed another way to do that (command line is fine with me, but running a command-line program that opens sonypi disturbs sonypid so it stops working). So now I have brightness on the wheel-move-when-pressed:

		static int pressed = 0;
		[ ... ]
			case SONYPI_EVENT_JOGDIAL_DOWN_PRESSED:
			    changeBrightness(-12);
			    pressed = 1;
			    break;
			case SONYPI_EVENT_JOGDIAL_UP_PRESSED:
			    changeBrightness(12);
			    pressed = 1;
			    break;
			[ ... ]
			case SONYPI_EVENT_JOGDIAL_RELEASED:
			    if (!pressed)
				simulateButton(disp, 2);
			    pressed = 0;

These ideas should get you started making your own sonypid configuration -- have fun!

Stay tuned for other hacks! I'll be updating this page as I discover new things I can do.

Other Jog Dial Drivers

jogdiald looks like a nifty, highly configurable way to make your jogdial do virtually whatever you want it to. It may make all my hacks obsolete. I haven't checked it out yet, but I will. Also check out the S-Jog project at Sourceforge for another more jog dial controller, or see the SJog home page)

Before I discovered that sonypi was built in to 2.4.7, I was using Takaya Kinjo's spicdriver driver for the Jog Dial wheel on his PictureBook. (I suspect the spicdriver code was later folded into the sonypi code.) It works fine with the SR17, though it was written for a 505, and was very easy to install. John Heidemann has written a program which uses Kinjo's driver to emulate a mouse scroll wheel. Heidemann's tarball includes the basic driver as well as the jog_scroll control. It can drive other things besides just mouse scrolling. The README file explains how to compile and install it.


Linux on the Vaio SR17k
My Linux links page
Shallow Sky home
...Akkana (I'd love to share experiences with other people running linux on laptops)