T42のボリュームボタンを何とかしたい
ThinkPad T42のキーボードには、Access IBMボタンとかボリュームを上げ下げするボタンがついています。Windowsでボリュームを上げ下げするボタンを押すと、TVでリモコンを押したみたいに現在のボリュームの値が画面上に表示されます。これをNetBSDでも使いたい。
ぐぐってみた結果、どうやらAccess IBMボタンとかボリュームを上げ下げするボタンを押すと不揮発性のメモリ領域(RTCとかを保存しているところ)の値が変更するようです。で、LinuxとかOpenBSDは/dev/nvramというデバイスファイルを用意して、その領域をアクセスできるようにしています。ユーザランドからは、TPB - ThinkPad Buttonsというツールを使って一定時間ごとにその領域に変更がないかポーリングしています。しかしいくら機種依存の機能とはいえ、不揮発性のメモリ領域をそのままユーザランドに見せるのはカーネルのインターフェースとしていかがなものでしょう…
さて、肝心のNetBSDの場合についてですが、NetBSDには/dev/nvramなんてものはありません。仕方がないので、OpenBSDから移植してみました。以下にpatchを添付します。
diff -ruN sys.orig/arch/i386/conf/files.i386 sys/arch/i386/conf/files.i386 --- sys.orig/arch/i386/conf/files.i386 2005-10-15 22:47:19.000000000 +0900 +++ sys/arch/i386/conf/files.i386 2005-10-15 22:47:55.000000000 +0900 @@ -466,4 +466,8 @@ attach vesatext at vesabios file arch/i386/bios/vesa_text.c vesatext +# NVRAM for 'Access IBM' button etc... +defpseudo nvram +file arch/i386/i386/nvram.c nvram + include "arch/i386/conf/majors.i386" diff -ruN sys.orig/arch/i386/conf/majors.i386 sys/arch/i386/conf/majors.i386 --- sys.orig/arch/i386/conf/majors.i386 2005-10-15 22:47:19.000000000 +0900 +++ sys/arch/i386/conf/majors.i386 2005-10-15 22:47:56.000000000 +0900 @@ -107,6 +107,7 @@ device-major rd char 105 block 22 rd device-major ct char 106 block 23 ct device-major mt char 107 block 24 mt +device-major nvram char 108 nvram # Majors up to 143 are reserved for machine-dependant drivers. # New machine-independant driver majors are assigned in diff -ruN sys.orig/arch/i386/i386/nvram.c sys/arch/i386/i386/nvram.c --- sys.orig/arch/i386/i386/nvram.c 1970-01-01 09:00:00.000000000 +0900 +++ sys/arch/i386/i386/nvram.c 2005-10-15 22:47:58.000000000 +0900 @@ -0,0 +1,163 @@ +/* $OpenBSD: nvram.c,v 1.3 2004/11/11 08:28:28 jcs Exp $ */ + +/* + * Copyright (c) 2004 Joshua Stein <jcs@openbsd.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/uio.h> +#include <sys/fcntl.h> +#include <sys/conf.h> +#if defined(__NetBSD__) +#include <sys/event.h> +#endif + +#include <dev/ic/mc146818reg.h> +#include <i386/isa/nvram.h> + +/* checksum is calculated over bytes 2 to 31 and stored in byte 32 */ +#define NVRAM_CSUM_START (MC_NVRAM_START + 2) +#define NVRAM_CSUM_END (MC_NVRAM_START + 31) +#define NVRAM_CSUM_LOC (MC_NVRAM_START + 32) + +#define NVRAM_SIZE (128 - MC_NVRAM_START) + +/* #define NVRAM_DEBUG 1 */ + +void nvramattach(int); + +int nvramopen(dev_t dev, int flag, int mode, struct proc *p); +int nvramclose(dev_t dev, int flag, int mode, struct proc *p); +int nvramread(dev_t dev, struct uio *uio, int flags); + +int nvram_csum_valid(void); +int nvram_get_byte(int byteno); + +#if defined(__NetBSD__) +const struct cdevsw nvram_cdevsw = { + nvramopen, nvramclose, nvramread, nullwrite, nullioctl, + nostop, notty, nopoll, nommap, nokqfilter, +}; +#endif + +static int nvram_initialized; + +void +nvramattach(int num) +{ + if (num > 1) + return; + + if (nvram_initialized || nvram_csum_valid()) { +#ifdef NVRAM_DEBUG + printf("nvram: initialized\n"); +#endif + nvram_initialized = 1; + } else + printf("nvram: invalid checksum\n"); +} + +int +nvramopen(dev_t dev, int flag, int mode, struct proc *p) +{ + /* TODO: re-calc checksum on every open? */ + + if ((minor(dev) != 0) || (!nvram_initialized)) + return (ENXIO); + + if ((flag & FWRITE)) + return (EPERM); + + return (0); +} + +int +nvramclose(dev_t dev, int flag, int mode, struct proc *p) +{ + return (0); +} + +int +nvramread(dev_t dev, struct uio *uio, int flags) +{ + u_char buf[NVRAM_SIZE]; + u_int pos = uio->uio_offset; + u_char *tmp; + int count = min(sizeof(buf), uio->uio_resid); + int ret; + + if (!nvram_initialized) + return (ENXIO); + + if (uio->uio_resid == 0) + return (0); + +#ifdef NVRAM_DEBUG + printf("attempting to read %d bytes at offset %d\n", count, pos); +#endif + + for (tmp = buf; count-- > 0 && pos < NVRAM_SIZE; ++pos, ++tmp) + *tmp = nvram_get_byte(pos); + +#ifdef NVRAM_DEBUG + printf("nvramread read %d bytes (%s)\n", (tmp - buf), tmp); +#endif + + ret = uiomove((caddr_t)buf, (tmp - buf), uio); + + uio->uio_offset += uio->uio_resid; + + return (ret); +} + +int +nvram_get_byte(int byteno) +{ + if (!nvram_initialized) + return (ENXIO); + + return (mc146818_read(NULL, byteno + MC_NVRAM_START) & 0xff); +} + +int +nvram_csum_valid() +{ + u_short csum = 0; + u_short csumexpect; + int nreg; + + for (nreg = NVRAM_CSUM_START; nreg <= NVRAM_CSUM_END; nreg++) + csum += mc146818_read(NULL, nreg); + + csumexpect = mc146818_read(NULL, NVRAM_CSUM_LOC) << 8 | + mc146818_read(NULL, NVRAM_CSUM_LOC + 1); + +#ifdef NVRAM_DEBUG + printf("nvram: checksum is %x, expecting %x\n", (csum & 0xffff), + csumexpect); +#endif + + return ((csum & 0xffff) == csumexpect); +}
使い方は、カーネルの設定ファイルに
pseudo-device nvram
を追加して、普通にカーネルをコンパイルしてください。続いて、
$ sudo mknod /dev/nvram c 108 0
で/dev/nvramを作成してください。
あとはtpbをコンパイルしてインストールすれば、キーボードについてるボリュームボタンなどが使えるようになります。