Random Wisdom

Hardware

ThinkPad E530 Fingerprint Reader on Linux

by on Oct.10, 2013, under Hardware, How To ..., Linux

The E530 comes with a fingerprint reader but getting it working takes some amount of effort — at least on Fedora systems. The only project supporting this particular reader (147e:1002 Upek Biometric Touchchip/Touchstrip Fingerprint Sensor) seems to be Fingerprint GUI.

The first step is getting it to compile. The README for fingerprint-gui-1.05 suggests running:

$ qmake-qt4
$ make

but the build fails on Fedora 19 (x86_64) with these instructions. It is necessary to call qmake-qt4 with a couple of extra defines after cleaning up the previous failed attempt:

$ ./remove-makefiles.sh && ./remove-binaries.sh
$ qmake-qt4 LIBPOLKIT_QT=LIBPOLKIT_QT_1_1 LIB=lib64
$ make

at this point, assuming all of the required devel packages are installed, the build should complete successfully. Install by running:

$ sudo make install
$ sudo make install-upek

The user should also be added to the plugdev group if not already a member. Once installed, nothing much will happen until PAM is configured. In the meanwhile, it should be possible to run ‘fingerprint-gui’ to confirm that the reader is detected and enrol a few fingerprints.

The next step is to modify the PAM stack. Start by creating a backup of ‘/etc/pam.d‘ in case something goes wrong. Then, add the line auth sufficient pam_fingerprint-gui.so -d try_first_identified to a few of the core configuration files:

# diff -uN /root/pam.d /etc/pam.d
diff -uN /root/pam.d/fingerprint-auth /etc/pam.d/fingerprint-auth
--- /root/pam.d/fingerprint-auth	2013-07-12 09:13:16.000000000 +0100
+++ /etc/pam.d/fingerprint-auth	2013-10-09 23:36:29.052893499 +0100
@@ -2,7 +2,8 @@
 # This file is auto-generated.
 # User changes will be destroyed the next time authconfig is run.
 auth        required      pam_env.so
-auth        sufficient    pam_fprintd.so
+#auth        sufficient    pam_fprintd.so
+auth        sufficient    pam_fingerprint-gui.so -d try_first_identified
 auth        required      pam_deny.so
 
 account     required      pam_unix.so
diff -uN /root/pam.d/password-auth /etc/pam.d/password-auth
--- /root/pam.d/password-auth	2013-07-12 09:13:16.000000000 +0100
+++ /etc/pam.d/password-auth	2013-10-09 23:41:50.469049775 +0100
@@ -2,6 +2,7 @@
 # This file is auto-generated.
 # User changes will be destroyed the next time authconfig is run.
 auth        required      pam_env.so
+auth        sufficient    pam_fingerprint-gui.so -d try_first_identified
 auth        sufficient    pam_unix.so try_first_pass nullok
 auth        required      pam_deny.so
 
diff -uN /root/pam.d/system-auth /etc/pam.d/system-auth
--- /root/pam.d/system-auth	2013-07-12 09:13:16.000000000 +0100
+++ /etc/pam.d/system-auth	2013-10-09 23:40:15.343472816 +0100
@@ -2,6 +2,7 @@
 # This file is auto-generated.
 # User changes will be destroyed the next time authconfig is run.
 auth        required      pam_env.so
+auth        sufficient    pam_fingerprint-gui.so -d try_first_identified
 auth        sufficient    pam_unix.so try_first_pass nullok
 auth        required      pam_deny.so

Once the changes have been saved, it should be possible to perform logins and screen unlocks using the fingerprint reader. On Fedora 19 (Gnome 3.8), the fingerprint GUI itself does not appear on login screens but it works nonetheless. More details here.

Leave a Comment :, , , , more...

ThinkPad E530 battery charge threshold on Linux

by on Mar.04, 2013, under Hardware, Linux

Leaving a battery charged at 100% for extended periods of time can significantly reduce its service life. Unfortunately, this is quite often the case with laptops that spend a lot of time tethered to an AC power socket. On Windows systems, the Lenovo ThinkVantage power management tools offer a solution that can be used to stop charging before the battery charge level reaches 100%, and re-start charging after it drops below another predefined level. E.g., with the charge thresholds set at 40% and 80%, a laptop connected to the AC adapter will:

  • Start charging when the battery is below 40%
  • Stop charging when the level reaches 80%
  • Do nothing while it is above 40% — even though the AC adapter is connected

According to ThinkWiki, similar functionality can be had on Linux using tp_smapi but unfortunately support for E-series laptops is currently missing.

Searching further finally led me to tpacpi-bat. It is a very young project (about 3 months old at the time of writing) but I am happy to say that it successfully sets both start and stop thresholds on my E530 ThinkPad. The tpacpi-bat Perl script did require one small change to get it working:

diff --git a/tpacpi-bat b/tpacpi-bat
index d9ecf99..2dcdd9d 100755
--- a/tpacpi-bat
+++ b/tpacpi-bat
@@ -39,7 +39,8 @@ use warnings;
 use File::Basename;

 my $acpiCallDev = '/proc/acpi/call';
-my $aslBase = '\_SB.PCI0.LPC.EC.HKEY';
+my $aslBase = '\_SB.PCI0.LPCB.EC0.HKEY';

 sub readPeakShiftState($);
 sub readInhibitCharge($);

… but I’ll chalk it up to the rather immature state of the project. The most important thing is that it works as expected. The $aslBase setting for other ThinkPad models can be found by following these steps taken from the project’s issue tracker:

$ sudo acpidump -b -t DSDT -o /tmp/dsdt.aml
$ iasl -d /tmp/dsdt.aml
$ cat /tmp/dsdt.dsl | grep \\\\_SB\.PCI.*HKEY -o | uniq

If the tpacpi.service file is utilised to automatically set the thresholds at system start, it should also be modified as appropriate (particularly ExecStart=).

Leave a Comment :, , , , more...

Printing to a Windows GDI printer from Linux

by on Feb.20, 2012, under Hardware, How To ..., Linux

Quite a few of the cheaper laser printers are difficult to use directly on Linux due to missing drivers. The reason is that quite a bit of the work is actually done by the (Windows) driver rather than the printer itself. These printers have come be known as GDI or Winprinters. The EPSON AcuLaser C1750 is such a printer. After struggling for a few days, trying to get it to work natively under Linux, I decided to look for an alternative solution [Update: see bottom of article]. Then I found one.

The basic idea is to create a dummy shared PS printer on a Windows host and then also install the physical printer there. The dummy printer accepts PS jobs from Linux clients and then filters them through Ghostscript before feeding them to the physical printer using the native Windows GDI driver. I did need to change some of the steps compared to the guide above, so I’ll provide a short guide here for others who may be looking to get their Winprinter working with Linux.

This is only a rough guide meant to give an idea of the steps required. You may need to figure out any appropriate intermediate steps and install the necessary software dependencies (e.g., samba).

Step 1: Find a networked Windows box and install the printer there
I used an instance of Windows XP running in VirtualBox on the print server itself. The networking is set to ‘Bridged’ to allow connection from others on the network.

Step 2: [Windows] Install Ghostscript, GSView and RedMon – in that order
All of the above can be found at: http://pages.cs.wisc.edu/~ghost/. I used GPL Ghostscript 9.02, GSview 5.0 and RedMon 1.7 on the Windows guest VM.

Step 3: [Windows] Configure GSprint for non-interactive printing
This is done by creating a configuration file (gsprint.cfg) in the same directory as the gsprint.exe executable. This should be in “$PATH_TO_GSVIEW”. I put the following in gsprint.cfg:

-noquery
-color
-printer
EPSON AL-C1750N

Note that each option must go on a separate line and “EPSON AL-C1750N” is the name of the printer as it appears in the Windows Control Panel. Again, note that the printer name is specified without quotes. The original guide also specifies the -ghostscript option but I found that it fails to work with that. It was best to let gsprint choose the correct Ghostscript binary automatically.

After creating the configuration file for gsprint, it is prudent to check that it functions as expected by running the following from a Windows command line:

> cd $PATH_TO_GSPRINT
> gsprint sample_ps_file.ps

The printer should now produce the sample PS file without any further input/intervention from the user.

Step 4: [Windows] Create dummy PostScript printer(s)
Use the “Add new printer” to create dummy PS printers. I created two of them — one for grayscale output and one for color. When creating the printers, choose “Local printer” and then “FILE:” as the port type. I chose the “Canon PS-IPU Color Laser Copier v52.3” as the printer model because it is a PostScript color laser printer that would allow both color and grayscale printing. The guide suggests something like the “Apple LaserWriter II NT” but that only produces grayscale output. I named the first printer “PSPrinter_BW” and the other “PSPrinter_Color”. The properties of the printer were set such that jobs sent to PSPrinter_BW are printed in grayscale while those sent to PSPrinter_Color are printed in color. Sharing is also turned on for both printers.

Step 5: [Windows] Set dummy printers to use RedMon
For each of the printers, go to “Printer properties” -> “Ports” -> “Add port”. Select “Redirected port” and click “New port”. Specify a name for the port, e.g., “RPT1:”. After adding the port, go to “Configure port” and fill out the necessary settings. For PSPrinter_Color, I have:

Redirect to program: $PATH_TO_GSPRINT.EXE
Arguments for program: -
Output: "Program handles output"
Run as user: [ ] (i.e., unchecked)

For PSPrinter_BW, I have:

Redirect to program: $PATH_TO_GSPRINT.EXE
Arguments for program: -mono -
Output: "Program handles output"
Run as user: [ ] (i.e., unchecked)

Click “OK” and close the printer properties dialog. Check that the port redirection works by printing something to PSPrinter_* and collecting the output from the physical printer.

Step 6: [Linux] Add share dummy printers to Linux
Using the printer administration module, add the shared PS printer(s) as “Windows Printer via SAMBA”. For the printer model/driver, I chose “Generic” -> “PostScript Printer”.

That’s it! It should now be possible to print to the physical printer from Linux by sending the job to the printer created in Step 6.

Update [18 July, 2012]: The EPSON AL-C1750N appears to work with the Linux drivers for the Xerox Phaser 6000. On 64bit Centos 6 it was also necessary to install the 32bit version of cups-libs. This was pointed out by Lathrop in the comments.

13 Comments :, , , , , , , , , more...

Fine grained system control with custom udev rules

by on Feb.16, 2012, under Hardware, How To ..., Linux

When a new hardware device is plugged into a Linux system, udev handles the creation of device nodes and symbolic links under ‘/dev’. Certain aspects of this process, such as initial file permissions, can be controlled using custom udev rules placed in the appropriate configuration file directory (e.g. ‘/etc/udev/rules.d/’). Recently, I found myself looking into custom udev rules for two reasons: setting the default device permissions on a USB scanner and setting a unique name for an external disk.

udev rules always start with directives that tell udev how to match a device of interest. E.g.

ACTION=="add", KERNEL=="sg[0-9]*", BUS=="scsi", SYSFS{type}=="8", \
        SYMLINK+="changer changer-%k", MODE="0660", GROUP="disk"

In this particular example, if the keys ACTION, KERNEL, BUS and SYSFS{type} for the new device match the given values, then the values specified for SYMLINK, MODE and GROUP are applied to each of those attributes when creating the device node. A list of the valid test and assignment operators for udev rules can be found in the man page for udev.

The key/value pairs necessary to match a given device can be discovered by using the ‘udevadm‘ tool. For a USB device, ‘lsusb‘ can be used first to determine the generic device node after plugging in the hardware:

[root@localhost ~]# lsusb
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 002 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 003 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 004 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 005 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 001 Device 003: ID 0644:0200 TEAC Corp. All-In-One Multi-Card Reader CA200/B/S
Bus 004 Device 003: ID 04b8:010f Seiko Epson Corp. Perfection 1250
Bus 002 Device 003: ID 0665:5161 Cypress Semiconductor USB to Serial
Bus 001 Device 007: ID 0bc2:5071 Seagate RSS LLC 

In this list, ‘Bus 004 Device 003: ID 04b8:010f Seiko Epson Corp. Perfection 1250‘ is the scanner and it is at device node ‘/dev/bus/usb/004/003’. Armed with that information, it is now possible to use ‘udevadm’ to get the key/value pairs:

[root@localhost ~]# udevadm info --attribute-walk --path \
                    $(udevadm info --query path --name /dev/bus/usb/004/003)

Udevadm info starts with the device specified by the devpath and then
walks up the chain of parent devices. It prints for every device
found, all possible attributes in the udev rules key format.
A rule to match, can be composed by the attributes of the device
and the attributes from one single parent device.

  looking at device '/devices/pci0000:00/0000:00:1d.2/usb4/4-2':
    KERNEL=="4-2"
    SUBSYSTEM=="usb"
    DRIVER=="usb"
    ATTR{configuration}==""
    ATTR{bNumInterfaces}==" 1"
    ATTR{bConfigurationValue}=="1"
    ATTR{bmAttributes}=="c0"
    ATTR{bMaxPower}=="  2mA"
    ATTR{urbnum}=="282"
    ATTR{idVendor}=="04b8"
    ATTR{idProduct}=="010f"
    ATTR{bcdDevice}=="0100"
    ATTR{bDeviceClass}=="ff"
    ATTR{bDeviceSubClass}=="00"
    ATTR{bDeviceProtocol}=="ff"
    ATTR{bNumConfigurations}=="1"
    ATTR{bMaxPacketSize0}=="8"
    ATTR{speed}=="12"
    ATTR{busnum}=="4"
    ATTR{devnum}=="3"
    ATTR{version}==" 1.10"
    ATTR{maxchild}=="0"
    ATTR{quirks}=="0x0"
    ATTR{authorized}=="1"
    ATTR{manufacturer}=="EPSON"
    ATTR{product}=="EPSON Scanner 010F"

  looking at parent device '/devices/pci0000:00/0000:00:1d.2/usb4':
    KERNELS=="usb4"
    SUBSYSTEMS=="usb"
    DRIVERS=="usb"
    ATTRS{configuration}==""
    ...
    ...
    [output trimmed]

Using this information from ‘udevadm‘ the following rule was created:

[root@localhost ~]# cat /etc/udev/rules.d/60-scanner.rules 
# UDEV rules for Epson scanner

ACTION!="add", GOTO="epson_rules_end"
SUBSYSTEM!="usb", GOTO="epson_rules_end"

SUBSYSTEM=="usb", DRIVER=="usb", ATTR{idVendor}=="04b8", ATTR{idProduct}=="010f", \
 MODE="0666", SYMLINK+="scanner" LABEL="epson_rules_end"

LABEL="epson_rules_end"

This rule instructs udev to create an additional device node at ‘/dev/scanner’ and set the access permissions to ‘rw-rw-rw-‘. After saving the rules file, it is necessary to apply the changes using:

[root@localhost ~]# udevadm trigger

Useful resources: “Writing udev rules“, udev and udevadm man pages.

1 Comment :, , , more...

Replacing broken laptop displays

by on Feb.02, 2007, under Hardware

Notebook LCD replacement need not be a costly affair:

How To Replace A Broken Laptop or Notebook Display

ScreenTek is apparently a leading manufacturer.

Leave a Comment :, , , more...

Return of DARKWORLD

by on Jan.15, 2006, under Hardware, Software

Yup! My favorite PC just regained Net connectivity today. I moved into the new apartment this morning and was up and running by the evening. The guy who I share the place with wasn’t around and so I would have had to wait till I got the info about the wireless network. So, instead of waiting, I just decided to see what kind of a WLAN he has … and oh my oh my … there were 5 freakin’ access points around — and 3 of them completely unsecured! As it turned out, one belonged to the dude I share the place with …

Anyway, then I decided to catch up on my TV eps (Stargate SG1/Atlantis, Threshold, Supernatural, Doctor Who) and f*** the speed sux! It’s a bloody T-Online DSL1000 Flat deal. Anyway, the IP I got was “192.168.0.5”, so I deduced that the router should be at “192.168.0.1” or “192.168.0.254”. And sure enough there it was in the first address. Obviously, it asked me for a password that I didn’t know. So, I just tried “admin:1234” .. and nope, no go .. Then I thought I’d just do a little net search. The router was NETGEAR (deduced from the WLAN SSID), so I just googled “netgear default password” and the 4th hit came up with “admin:password”. Turns out the guy didn’t even change that password 😀 So, I got in, fiddled around with the NAT settings and Azureus was NAT free in no time. This has got to be the prime example of an unsecured network …

Anyway, once the guy got back, I explained everything to him and changed the router password and setup a WEP-key. It seems there was a machine leeching off of this net and things improved a little once that dude got kicked out. It turns out DSL6000 costs just as much as he pays right now — but he has no use for so much bandwidth when I’m gone — so we’ll just change to DSL2000 with 384k upload for now. That should be enough for me to download the occasional SG1 / Doctor Who episode 😀

Leave a Comment :, , more...

Addressing Individual Audio Channels of a Multichannel ALSA System

by on Oct.03, 2005, under Hardware, How To ..., Linux, Software

At first I thought I could just use one of the audio editors to create a 5.1 channel sound file and blank all the channels that I don’t want. Sweep claims to be a multichannel audio editor but at the moment it’s not possible to edit the individual audio channels. So, I tried out Audacity. Although Audacity allows the editing of the individual channels, it’s not possible to save the edited file in a multichannel format – it’s invariably down-mixed to stereo. So, custom sound files were no longer an option ..

At this point, I started looking at the ALSA PCM plugins. The route plugin seemed like the perfect candidate. In order to use the plugin I had to create the plugin definitions in the file ~/.asoundrc:

[darkknight@darkworld ~]$ cat .asoundrc
pcm_slave.rt {
        pcm surround50
        channels 5
}

pcm.front_l {           #Front Left
        type route
        slave rt
        ttable.0.0 1
}

pcm.front_r {           #Front Right
        type route
        slave rt
        ttable.0.1 1
}

pcm.front_c {           #Front Center
        type route
        slave rt
        ttable.0.4 1
}

pcm.rear_l {            #Rear Left
        type route
        slave rt
        ttable.0.3 1
}

pcm.rear_r {            #Rear Right
        type route
        slave rt
        ttable.0.2 1
}

pcm.front_both {        #Front - Both
        type route
        slave rt
        ttable.0.0 1
        ttable.0.1 1
}

pcm.rear_both {         #Rear - Both
        type route
        slave rt
        ttable.0.2 1
        ttable.0.3 1
}

The plugins can be used with the aplay utility:

[darkknight@darkworld ~]$ aplay -D front_c /usr/share/sounds/alsa/Front_Center.wav
Playing WAVE '/usr/share/sounds/alsa/Front_Center.wav' : Signed 16 bit Little Endian, Rate 48000 Hz, Mono

Of course it makes sense to use only Mono files with the plugins since the mappings are always carried out from channel 1. It’s the ttable entry that’s responsible for the mapping. The first value is the source channel (0 = channel 1, 1 = channel 2, etc.). The second value is the channel to route to. The third value controls the volume; a value of 0 means 0% volume and a value of 1.0 means 100% volume.

With the new plugin definitions, it’s even easier to balance the speaker levels. The following command will alternate between the front speakers and the center speaker until interrupted:

[darkknight@darkworld ~]$ while [ 1 ]; do /usr/bin/aplay -D front_both -q /usr/share/sounds/alsa/Noise.wav;
/usr/bin/aplay -D front_c /usr/share/sounds/alsa/Noise.wav; done
1 Comment :, , , , , more...

Turn on 800DPI mode for the Logitech MX-510 Mouse

by on Aug.27, 2005, under Hardware, How To ..., Linux, Software

5 easy steps:

1. Get and install the Logitech Applet from here or directly from here

2. Install the poper udev rules:
Create a file logitech-mice.rules under /etc/udev/rules.d/ with the following contents:

[darkknight@darkworld rules.d]$ cat logitech-mice.rules
BUS="usb", SYSFS{idVendor}="046d", SYSFS{idProduct}="c00e", PROGRAM="/usr/local/bin/logitech_applet -e -s 800"
BUS="usb", SYSFS{idVendor}="046d", SYSFS{idProduct}="c00f", PROGRAM="/usr/local/bin/logitech_applet -e -s 800"
BUS="usb", SYSFS{idVendor}="046d", SYSFS{idProduct}="c012", PROGRAM="/usr/local/bin/logitech_applet -e -s 800"
BUS="usb", SYSFS{idVendor}="046d", SYSFS{idProduct}="c024", PROGRAM="/usr/local/bin/logitech_applet -e -s 800"
BUS="usb", SYSFS{idVendor}="046d", SYSFS{idProduct}="c01b", PROGRAM="/usr/local/bin/logitech_applet -e -s 800"
BUS="usb", SYSFS{idVendor}="046d", SYSFS{idProduct}="c025", PROGRAM="/usr/local/bin/logitech_applet -e -s 800"
BUS="usb", SYSFS{idVendor}="046d", SYSFS{idProduct}="c01d", PROGRAM="/usr/local/bin/logitech_applet -e -s 800"
BUS="usb", SYSFS{idVendor}="046d", SYSFS{idProduct}="c031", PROGRAM="/usr/local/bin/logitech_applet -e -s 800"

Change the file permissions:

[darkknight@darkworld rules.d]$ sudo chown root.root logitech-mice.rules
[darkknight@darkworld rules.d]$ sudo chmod 644 logitech-mice.rules && ls -l
total 24
-rw-r--r--  1 root root  146 Apr 13 20:30 10-wacom.rules
-rw-r--r--  1 root root 7406 May 21 05:45 50-udev.rules
-rw-r--r--  1 root root  888 Sep  6 23:12 logitech-mice.rules

3. Modify /etc/X11/xorg.conf as follows to support the thumb buttons:

Section "InputDevice"
    Identifier  "Mouse0"
    Driver      "mouse"
    Option      "Protocol" "ExplorerPS/2"
    Option      "Device" "/dev/input/mice"
    Option      "ZAxisMapping" "6 7"
    Option      "Buttons" "7"
    Option      "Emulate3Buttons" "no"
EndSection

4. Create a script xmouse.sh under /etc/X11/xinit/xinitrc.d with the following contents:

[darkknight@darkworld xinitrc.d]$ cat xmouse.sh
#!/bin/bash

/usr/X11R6/bin/xmodmap -e "pointer = 1 2 3 6 7 4 5"

This ensures that the scrolling funtion is correctly assigned to the wheel and not to the thumb buttons.

Make sure that the file permissions are correct:

[darkknight@darkworld xinitrc.d]$ sudo chmod 755 xmouse.sh && ls -l
total 16
-rwxr-xr-x  1 root root 1579 Apr 11 13:43 xinput.sh
-rwxr-xr-x  1 root root   81 Sep  2 17:36 xmbind.sh
-rwxr-xr-x  1 root root   66 Sep  6 23:41 xmouse.sh

5. Reboot (Or simply unplug/re-plug mouse and restart X)

Happy surfing! Got the udev rules from the Ubuntu Forum (modified the PROGRAM line to use logitech_applet instead of lmctl).

Edit [July 30, 2007]: It has been a while since the steps above were posted. The syntax of UDEV rules have changed much since then. The updated rule is (for my MX-510):

$ cat /etc/udev/rules.d/60-logitech-mouse.rules
SUBSYSTEMS=="usb", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="c01d", RUN+="/usr/local/bin/logitech_applet -e -s 800"

Device details necessary for writing UDEV rules can be discovered using (substitute /dev/input/mouse1 with path to device of interest):

# udevinfo -a -p $(udevinfo -q path -n /dev/input/mouse1)

Update [19th Nov. 2009]: On Fedora 12 (X.Org X Server 1.7.1), the configuration needed to get the thumb buttons working is:

Section "InputDevice"
        Identifier  "Mouse0"
        Driver      "mouse"
        Option      "Protocol" "ExplorerPS/2"
        Option      "Device" "/dev/input/mice"
        Option      "Emulate3Buttons" "no"
        Option      "Buttons" "9"
        Option      "ZAxisMapping" "4 5"
EndSection

It seems that it is no longer necessary to remap the buttons using xmouse.sh.

Leave a Comment :, , more...

Custom Keybinding (GNOME)

by on Aug.25, 2005, under Hardware, How To ..., Linux, Software

This is useful for multimedia keyboards that aren’t automatically recognized. Also useful when you want actions other that those offered in “gnome-keybinding-properties“. The first step is to check if the buttons are recognized at all. This can be accomplised by running “xev

$ xev

Once the little window pops up, press any of the buttons and see if you get an output like the following:

KeyPress event, serial 29, synthetic NO, window 0x3c00001,
root 0xd6, subw 0x0, time 2073408, (1033,644), root:(1051,745),
state 0x0, keycode 231 (keysym 0x0, NoSymbol), same_screen YES,
XLookupString gives 0 bytes:
XmbLookupString gives 0 bytes:
XFilterEvent returns: False

KeyRelease event, serial 29, synthetic NO, window 0x3c00001,
root 0xd6, subw 0x0, time 2073529, (1033,644), root:(1051,745),
state 0x0, keycode 231 (keysym 0x0, NoSymbol), same_screen YES,
XLookupString gives 0 bytes:

If you do get the output, the important thing to note is the keycode (keycode 231 here). Once you have the keycode for a key, you need to define a Key Symbol for it. To do this, you need a xmodmap file. You can get a copy of it using:

$ xmodmap -pke > ~/.xmodmaprc

Once the current map is dumped, open the file for editing and locate the required keycode:

$ vi ~/.xmodmaprc
[snip]
keycode 231 =
[snip]

As we can see there is no symbol associated with the keycode 231 yet. To get a list of available symbols, look at /usr/X11R6/lib/X11/XKeysymDB. Since the button is marked as Refresh, we can use XF86Refresh as a suitable symbol:

[snip]
keycode 231 = XF86Refresh
[snip]

Once all the required keys have been set, save the file.

To make the new map take effect (in GNOME):

$ gconftool-2 --set "/desktop/gnome/peripherals/keyboard/general/known_file_list" 
  --type list --list-type string "[.xmodmaprc]"

$ gconftool-2 --set "/desktop/gnome/peripherals/keyboard/general/update_handlers"
  --type list --list-type string "[.xmodmaprc]"

At this point you probably need to logout and log back in.

Now, for the case where xev doesn’t already detect the key. Start by tailing the /var/log/messeges file:

$ sudo tail -f /var/log/messages

The last lines of the file will be displayed. Now, press the desired key. Now, you should see something like

Aug 27 13:55:58 darkworld kernel: atkbd.c: Unknown key pressed (translated set 2, code 0x96 on isa0060/serio0).
Aug 27 13:55:58 darkworld kernel: atkbd.c: Use 'setkeycodes e016 <keycode>' to make it known.
Aug 27 13:55:58 darkworld kernel: atkbd.c: Unknown key released (translated set 2, code 0x96 on isa0060/serio0).
Aug 27 13:55:58 darkworld kernel: atkbd.c: Use 'setkeycodes e016 <keycode>' to make it known.

So, as suggested, we make it known by:

$ setkeycodes e016 187

I chose 187 since it doesn’t appear to be used by any key yet. Once all the keycodes have been set, repeat as before to assign the key symbols.

[Edit (Sept. 8, 2005)]
It seems that there is a better way to choose the kernel keycode. We can run getkeycodes to see which keycodes are currently in use. We can use any keycode between 84 and 255 that is not already used.

$ getkeycodes
Plain scancodes xx (hex) versus keycodes (dec)
for 1-83 (0x01-0x53) scancode equals keycode

0x50:   80  81  82  83  99   0  86  87
0x58:   88 117   0   0  95 183 184 185
0x60:    0   0   0   0   0   0   0   0
0x68:    0   0   0   0   0   0   0   0
0x70:   93   0   0  89   0   0  85  91
0x78:   90  92   0  94   0 124 121   0

Escaped scancodes e0 xx (hex)

e0 00:    0 195 196 197 198   0   0   0
e0 08:    0   0   0   0   0   0   0   0
e0 10:  165   0   0   0   0   0   0   0
e0 18:    0 163   0   0  96  97   0   0
e0 20:  113 140 164   0 166   0   0   0
e0 28:    0   0 255   0   0   0 114   0
e0 30:  115   0 150   0   0  98 255  99
e0 38:  100   0   0   0   0   0   0   0
e0 40:    0   0   0   0   0 119 119 102
e0 48:  103 104   0 105 112 106 118 107
e0 50:  108 109 110 111   0   0   0   0
e0 58:    0   0   0 125 126 127 116 142
e0 60:    0   0   0 143   0 217 156 173
e0 68:  128 159 158 157 155 226   0 112
e0 70:    0   0   0   0   0   0   0   0
e0 78:    0   0   0   0   0   0   0   0

It also seems we need to restore the kernel keycode mapping after every reboot. This is easily accomplished by having the required commands in /etc/rc.local:

[darkknight@darkworld ~]$ cat /etc/rc.local
#!/bin/sh
#
# This script will be executed *after* all the other init scripts.
# You can put your own initialization stuff in here if you don't
# want to do the full Sys V style init stuff.

touch /var/lock/subsys/local

setkeycodes e016 187 e015 188 e014 189 e013 190 e005 191
            e01e 192 e009 193 e00b 202 e008 194 e018 199
            e00a 200 e017 201 e03b 203 e03c 204 e03d 205
            e03e 206 e03f 207 e040 208 e041 211 e042 210
            e043 212 e023 213 e057 214 e058 215 e064 216

The kernel keycodes are different from the keycodes used by X. So, we need to run xev again to get the keycodes (as seen by X) of the newly found keys.

Got the hints from here.
[End Edit]

Now that we have KeySymbols, what do we do with them? Open up gconf-editor and browse to the key /apps/metacity/global_keybindings. There, choose any of the run_command_* keys marked as disabled and change the value to the desired KeySymbol (e.g. XF86AudioPrev). Then navigate to the key /apps/metacity/keybinding_commands and find the command_* key with the same number as the run_command_*. Change the value of the key to whatever command you wish to be performed when the Previous key is pressed. If you happen to run out of run_command_* and command_* key pairs, simply create new pairs from the right click menu.

2 Comments :, , , more...

Audigy 2 ZS on FC4

by on Aug.23, 2005, under Hardware, Linux, Software

I’ve finally got a setup that sounds just as good as it does on Windows. I’ve tested the surround system with a DVD and so far it sounds pretty good. I think the trouble was that there wasn’t any signal generator to let me balance the speakers properly. But today I discovered that there is an alsa subdirectory under /usr/share/sounds that contains a noise file. Playing that in a loop:

$ while [ 1 ]; do aplay /usr/share/sounds/alsa/Noise.wav; done

I finally managed to get that elusive speaker balance through alsamixer. Now, all that’s missing is CMSS3D 🙂

This site might be useful.

Leave a Comment :, , more...