diff -urNp thinkpad/Documentation/Configure.help 2.4.20pre8aa2/Documentation/Configure.help --- thinkpad/Documentation/Configure.help Wed Oct 2 06:40:54 2002 +++ 2.4.20pre8aa2/Documentation/Configure.help Wed Oct 2 06:42:00 2002 @@ -18827,6 +18827,22 @@ CONFIG_I8K Say Y if you intend to run this kernel on a Dell laptop. Say N otherwise. +IBM ThinkPad laptop support +CONFIG_THINKPAD + This adds a driver to safely access the special system management + features of IBM ThinkPad laptops. + + For information on utilities to make use of this driver see the + tpctl project site at http://tpctl.sourceforge.net/ . + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The primary module will be called thinkpad.o, with other modules + as well. If you want to compile this driver as a module, say M here + and read Documentation/modules.txt. If you use modprobe or kmod you + may also want to add the line 'alias char-major-10-170 thinkpad' to + your /etc/modules.conf file. + /dev/cpu/microcode - Intel IA32 CPU microcode support CONFIG_MICROCODE If you say Y here and also to "/dev file system support" in the diff -urNp thinkpad/arch/i386/config.in 2.4.20pre8aa2/arch/i386/config.in --- thinkpad/arch/i386/config.in Wed Oct 2 06:40:54 2002 +++ 2.4.20pre8aa2/arch/i386/config.in Wed Oct 2 06:42:00 2002 @@ -185,6 +185,7 @@ bool 'Machine Check Exception' CONFIG_X8 tristate 'Toshiba Laptop support' CONFIG_TOSHIBA tristate 'Dell laptop support' CONFIG_I8K +tristate 'IBM ThinkPad laptop support' CONFIG_THINKPAD tristate '/dev/cpu/microcode - Intel IA32 CPU microcode support' CONFIG_MICROCODE tristate '/dev/cpu/*/msr - Model-specific register support' CONFIG_X86_MSR diff -urNp thinkpad/char/thinkpad/ChangeLog 2.4.20pre8aa2/char/thinkpad/ChangeLog --- thinkpad/char/thinkpad/ChangeLog Thu Jan 1 01:00:00 1970 +++ 2.4.20pre8aa2/char/thinkpad/ChangeLog Wed Oct 2 06:41:39 2002 @@ -0,0 +1,419 @@ +ChangeLog file for thinkpad device drivers +========================================== + +TODO +---- +- Add /proc interface for some commonly used functions? +- Merge smapi functionality with that in mwave driver +- Submit drivers for inclusion into kernel tree +HELP IS WELCOME + +3.5 changes from 3.3 +-------------------- +13Apr2002 JDTH : Update README + Bump smapi driver version (should have been done in 3.1) + +3.3 changes from 3.2 +-------------------- +27Mar2002 JDTH : Update thinkpad.4 man page + +3.2 changes from 3.1 +-------------------- + 9Mar2002 JDTH : Add thinkpad.4 man page + Update docs + +3.1 changes from 3.0 +-------------------- +28Feb2002 JDTH : Add debian directory + Reduce frequency of reports of differing SMAPI return codes + Include 2.2 directory containing drivers from 1.0 which + work with Linux 2.2 +18Feb2002 JDTH : Add A30 to SUPPORTED-MODELS + +------------------------------------------------------------- +Note that post 3.0 this is the ChangeLog for thinkpad only. +In 3.0 and earlier, tpctl and thinkpad had a common ChangeLog +------------------------------------------------------------- + +3.0 changes from 2.5 +-------------------- +10Feb2002 JDTH : Releases renamed '3.0' + 3Feb2002 JDTH : Release thinkpad 3.0pre7 + 3Feb2002 JDTH : Simplified proc read functions +23Dec2001 JDTH : Release thinkpad 3.0pre6 +23Dec2001 JDTH : Put #ifdefs around MODULE_LICENSE so that the + modules can be used with kernels < 2.4.10 + 7Dec2001 JDTH : Release thinkpad 3.0pre5 + 7Dec2001 JDTH : Change instructions on configuring devfsd in the + README file, to reflect recent changes in devfs +14Nov2001 JDTH : Release tpctl 3.0pre4 +14Nov2001 JDTH : Janitorial work: + Make type of all flags in tpctl flag_t + I hope the janitor didn't break anything + Tweak --pra handling to reflect the fact that + appointments are made either for every day or for + every century. Tweak printf and scanf formats +26Oct2001 JDTH : Release 3.0pre3 +24Oct2001 JDTH : Update thinkpad README file +24Oct2001 JDTH : Change module parameter names to omit "thinkpad" + prefix which isn't necessary if we simply make + the parameter variables static. This reverts a + change made for 2.5. Sorry!! +24Oct2001 JDTH : Sync thinkpadpm code with the apm driver code from + which it was copied +22Oct2001 JDTH : Update TROUBLESHOOTING file again +18Oct2001 JDTH : Release 3.0pre2 +18Oct2001 JDTH : Improve device file handling code; provide more + useful error messages when file not found, etc. +17Oct2001 JDTH : Append TODO to README + 6Oct2001 JDTH : Note in thinkpad README that drivers are compatible + with certain Linux kernels + 5Oct2001 JDTH : Revise TROUBLESHOOTING file + 4Oct2001 JDTH : Release 3.0pre1 +18Sep2001 JDTH : Move proc files under /proc/driver subdirectory + : Add devfs support to superio, thinkpadpm, rtcmosram +28Aug2001 JDTH : Add devfs support to ntpctl as I did to tpctl + : Update TODO +27Jul2001 JDTH : Added devfs support to thinkpad and smapi modules + : Cleaned up driver init and exit functions + : Modified tpctl so it looks for /dev/thinkpad/thinkpad + : Split into two packages: + thinkpad -- device drivers + tpctl -- tpctl and its kindred binaries and lib + : Eliminate Makefile-common + +2.5 changes from 2.4 +-------------------- +25Jul2001 JDTH : Added reference to new ed. of _Linux device drivers_ + : Change module options enable_* -> thinkpad_enable_* + : Introduce a global variable "thinkpad_ppde" so that + other modules will require thinkpad module in order + to load, thus preventing corruption of /proc fs. + This eliminates the needs for "below" statements in + /etc/modules.conf. Updated README accordingly. + : Eliminate *_MOD_USE_COUNT etc. in favour of kernel's + automatic use counting +17Jul2001 JDTH : Change rtcmosram to use rtc_lock spinlock + instead of disabling interrupts. + : Eliminate proc fs optionalness + : Update README for devfs users +27Apr2001 JDTH : Fixed comments in several header files +16Apr2001 JDTH : Add INFO-BIOS file to tarball + +2.4 changes from 2.3 +-------------------- +27Feb2001 JDTH : No changes, except version increased to deal with + FUBAR upload of 2.3 to SourceForge + +2.3 changes from 2.2 +-------------------- +23Feb2001 JDTH : Update TODO, README +23Feb2001 JDTH : Fixed bug in superio PnP mode detection fn +18Feb2001 JDTH : Make tpctl 2.x work nicely with 1.0 modules. +11Feb2001 JDTH : tpctl now does a sync() before sedating +10Feb2001 JDTH : Update man pages for tpctl and ntpctl + +2.2 changes from 2.1 +-------------------- +6Feb2001 JDTH : Make names and version strings "const" variables. +6Feb2001 JDTH : Clean up printouts at init time and in /proc/thinkpad +6Feb2001 JDTH : Copy APM BIOS interface from APM driver to thinkpadpm.c so + that no kernel patch is required. +5Feb2001 JDTH : Correct README, TODO, ChangeLog files. +4Feb2001 JDTH : Remove SUPPORTED-MODELS file. INFO-BIOS does the same job. + +2.1 changes from 2.0 +-------------------- +4Feb2001 JDTH : Eliminate unnecessary explicit dereference of function + variable names in thinkpad.c +2Feb2001 JDTH : Update TECHNOTES, TODO, README, ChangeLog, etc. +31Jan2001 JDTH : Change tpctl --rx print outs, including order of items ... + I hope this doesn't annoy anyone. +27Jan2001 JDTH : Clean up --- use recommended Linux 2.4.x API +27Jan2001 JDTH : Add thinkpadpm module to control subsystem power. +27Jan2001 JDTH : Remove use of global fReady flags -- not needed +23Jan2001 JDTH : Install man in /usr/share/man not /usr/man +23Jan2001 JDTH : Remove cOpen variable from thinkpad.c; use MOD_IN_USE +22Jan2001 JDTH : Change all versions to 2.1 +22Jan2001 JDTH : Rename thinkpad_mod_defines.h to terser "thinkpad_module.h" +22Jan2001 JDTH : Remove VIAGRA #ifdef ... #endif since hw acces seems safe +22Jan2001 JDTH : Remove old proc filesystem code: NEW_PROC is king +22Jan2001 JDTH : Remove POWER_SERIAL code: module will do the work + +2.0 changes from 1.0 +-------------------- +20Jan2001 JDTH : Move tpctlir up out of contrib/ directory +20Jan2001 DS/JDTH : Added apmiser to the package +22Dec2000 JDTH : Use /lib/modules/xyz/build as path to kernel sources +22Dec2000 JDTH : Clean up Makefiles +12Dec2000 JDTH : Install under /usr, not under /usr/local +12Dec2000 JDTH : Port drivers to Linux 2.4 API + +1.0 changes from 0.8.9 +---------------------- +26Oct2000 JDTH : Remove '*' from lcall in smapi_call.s +16Oct2000 JDTH : Create BUGS file +14Oct2000 JDTH : Change --pra code so that selecting a daily app't + does not overwrite the date of the non-daily app't +14Oct2000 JDTH : Standardize date and time display and input formats + (thanks to Marc Joosen for the suggestion) +14Oct2000 JDTH : Add "-Wno-uninitialized" to CFLAGS for compiling tpctl +11Oct2000 JDTH : Update docs +7Oct2000 JDTH : Change tpctl and ntpctl Makefiles to link to smapidev + in the same way +7Oct2000 JDTH : Add SUPPORTED-MODELS file +7Oct2000 JDTH : Update README +7Oct2000 JDTH : Remove tpctlify; config now to be done by hand + because there were too many problems with + automated installation. +7Oct2000 JDTH : Rename VGA_MODES file to "VGA-MODES" +7Oct2000 JDTH : Remove plug-n-play check from superio init + +0.8.9 changes from 0.8.8 +------------------------ +1July2000 JDTH : Add kdist_clean target to Makefile to make make-kpkg happy +6July2000 AB/JDTH : Rename libsmapidev.so to libsmapidev.so.1 and add symlinks +6July2000 JDTH : Update AUTHORS file +17July2000 JDTH : Remove ioctl_thinkpad(), ioctl_superio() and + ioctl_rtcmosram() from smapidev since these have nothing + to do with SMAPI; move them into tpctl.c . +17July2000 JDTH : Change display of parallel port mode so that it is the + same as what you have to input to change the mode. +17July2000 JDTH : Remove some sound-related cruft from the thinkpad driver. +17July2000 JDTH : Add support for switching serial port on and off at the + same time as the port is enabled or disabled. At present + this requires a patch to the kernel: see tpctl/README. +18July2000 JDTH : Display interpretative strings for numerical values + consistently. +18July2000 JDTH : Update TROUBLESHOOTING, README and TODO files + +0.8.8 changes from 0.8.7 +------------------------ +25May2000 JDTH : Add COPYING file +25May2000 JDTH : Streamline some of the tpctl code + +0.8.7 changes from 0.8.6 +------------------------ +28Apr2000 JDTH : Remove other_tools/ubswap + +0.8.6 changes from 0.8.5 +------------------------ +26Apr2000 JDTH : Remove hdparm patch from other_tools/ubswap + since the patch has been incorporated into + the standard hdparm source +13Mar2000 JDTH : Update TODO file + +0.8.5 changes from 0.8.4 +------------------------ +3Mar2000 JDTH : Removed superfluous legacy-mode (i.e., superio + non-pnp mode) config information from tpctl -rx + outputs +17Feb2000 FB/JDTH : create_proc_read_entry() appeared in the + linux-2.3.25 kernel and not in 2.3.0; + changed #if in thinkpad_mod_defines.h +19Jan2000 MF : ntpctl -- open device RDONLY if can't open RDWR +15Jan2000 JDR/JDTH : Call depmod and modprobe by full path name + +0.8.4 changes from 0.8.3 +------------------------ +11Jan2000 AB : Added man pages for ntpctl, ubswap, tpctlir + Thanks to Adrian Bridgett! + +0.8.3 changes from 0.8.2 +------------------------ +9Jan2000 JDTH : (Experimental) Added ability to select SPP/EPP/ECP + +0.8.2 changes from 0.8.1 +------------------------ +6Jan2000 JDTH : Send '/lib/modules/`uname -r`' to tpctlify as module + path argument instead of /lib/modules/`uname -r` + +0.8.1 changes from 0.8.0 +------------------------ +5Jan2000 JDTH : Tested with 2.2.14 kernel. A-OK. +5Jan2000 RB/JDTH : Implemented TP570_KLUDGE +5Jan2000 MS/JDTH : Send path arguments to tpctlify +4Jan2000 HV/JDTH : Kernel path now selectable via a Makefile variable +3Jan2000 JDTH : Improved byte_of_bcd8() error message +3Jan2000 MS/JDTH : Added "install_modules" target to Makefile so that + modules can be installed separately from the + other stuff +3Jan2000 AB/JDTH : tpctlir now fails gracefully if not run by root +3Jan2000 JDTH : Fixed typo in heading for 'tpctl --pdZ' output +3Jan2000 AB/JDTH : Fixed typo in heading for 'tpctl --ip' output + +0.8.0 changes from 0.7.6 +------------------------ +31Dec99 JDTH : Man path now selectable via a Makefile variable +29Dec99 JDTH : Documentation corrections + +0.7.6 changes from 0.7.5 +------------------------ +27Dec99 DD/JDTH : Added tpctl man page. Thanks to Dave Davey! +25Dec99 AG/JDTH : Modified drivers to work with 2.3.x kernels' /proc + filesystem interface. Thanks to Anders Gustafsson! + +0.7.5 changes from 0.7.4 +------------------------ +13Dec99 JDTH : No longer install tpctlify + +0.7.4 changes from 0.7.3 +------------------------ +11Dec99 JDTH : Fixed nasty bug in Makefile that caused /lib/modules + to be wiped out on install. DO NOT INSTALL 0.7.3 ! +11Dec99 JDTH : Eliminated RPM-related stuff. Will release only + tarballs from now on. +11Dec99 JDTH : Changed modules installation directory to: + /lib/modules//thinkpad + +0.7.3 changes from 0.7.2 +------------------------ +8Dec99 JDTH : Added "other_tools" directory with two nifty tools: + tpctlir -- enables/disables infrared subsystem on + ThinkPads with Programmable Option Select + ubswap -- allows hot swapping of UltraBay devices +7Dec99 JDTH : Added IOCTL_SND_REINIT to the thinkpad module + Created the tpreinitsnd program to call the new ioctl +1Dec99 JDTH : Tweaked ntpctl menus for greater consistency with tpctl + +0.7.2 changes from 0.7.1 +------------------------ +30Nov99 JDTH : Integrated ntpctl into the package + Moved files into subdirectories + +0.7.1 changes from 0.7.0 +------------------------ +13Nov99 JDTH : Added GetPowerExpenditureMode and SetPowerExpenditureMode + to libsmapidev +17Oct99 JDTH : Updated my email address + +0.7.0 changes from 0.6.1 +------------------------ +31Jul99 JDTH : Update TROUBLESHOOTING especially re: kernel compatibility +31Jul99 JDTH : Move /proc entries under /proc/thinkpad +31Jul99 JDTH : Fiddled with tpctlify + +0.6.1 changes from 0.6.0 +------------------------ +30Jul99 JDTH : (Build 3) Eliminate some warning messages from byte_of_bcd8() +29Jul99 JDTH : Change handling of error codes so that it does not + rely upon ioctl() returning positive error codes + to the user. Such reliance is not portable. + +0.6.0 changes from 0.5.10 +------------------------- +29Jul99 JDTH : Change highlighting to "bold" and use the curses library + to get the appropriate terminal control strings. + +0.5.10 changes from 0.5.9 +------------------------- +28Jul99 JDTH : (Build 2+) Allow rtcmosram module to load even if ioports are + occupied. +28Jul99 JDTH : Complete modularization: modules are now automatically and + independently loadable and unloadable. When tpctl is run, + thinkpad.o is loaded by the module loader as per instructions + in /etc/modules.conf. The thinkpad module, in turn, requests + the loading of the other modules as they are needed to perform + ioctl requests. Loading of a module is inhibited by setting + "enable_" to zero, which can be done at load time or + via ioctl(). See README. +27Jul99 JDTH : Simplify "SIZE_..._MAX" macros +28Jul99 JDTH : Change '--silent' to '--quiet' since the switch doesn't + make tpctl completely silent. + +0.5.9 changes from 0.5.8 +------------------------ +27Jul99 JDTH : Use more standard error messaging +27Jul99 JDTH : Hive off smapi, superio and rtcmosram as distinctly + loadable modules. +27Jul99 JDTH : Fix bug in smapi:locate_smb_header() +27Jul99 JDTH : Fix bug in --pra output +27Jul99 JDTH : Abandon "variants" idea of 0.5.8 since it doesn't solve + the problem that it was meant to solve +27Jul99 JDTH : Add /proc/* entries for each enabled submodule +27Jul99 JDTH : Add module parameters to thinkpad.o to govern enabling of + the subordinate modules +27Jul99 JDTH : Make superio mod more careful about interrupt cli/restore +27Jul99 JDTH : Clean up module code a lot: make it much more kernelifically + correct and fault tolerant + +0.5.8 changes from 0.5.7 +------------------------- +25Jul99 JDTH : Package rpm with both modversions and non-modversions variants +25Jul99 JDTH : (release 5:) and install these in /lib/modules/thinkpad/thinkpad + and symlink /lib/modules/thinkpad/thinkpad.o to the right one +25Jul99 JDTH : Fix bug in Usage output +25Jul99 JDTH : Require write access for writing to CMOS RAM + +0.5.7 changes from 0.5.6 +------------------------- +24Jul99 JDTH : Added rtcmosram module +24Jul99 JDTH : Added --sst option +24Jul99 JDTH : Added --ic option +24Jul99 JDTH : Renamed --ic option as '--ip' + +0.5.6 changes from 0.5.5 +------------------------- +22Jul99 JDTH : Added "--silent" option +22Jul99 JDTH : Changed highlighting code to make it disablable using + the "--dull" option + +0.5.5 changes from 0.5.4 +------------------------- +22Jul99 JDTH : Added info about confuring serial ports to README +22Jul99 JDTH : Tried to make superio more kosher with its ioport usage +22Jul99 JDTH : Made checking for Super I/O chip a little more careful. + +0.5.4 changes from 0.5.3 +------------------------- +22Jul99 JDTH : Display appointment info all on one line +22Jul99 JDTH : Changed tpctlify to check for perl before invoking it + Also, make it more verbose +22Jul99 JDTH : Changed so that print formatting is nicer when many arguments + are given. Highlighting option improved and enabled for + binary distribution. + Options added: + --pdZh --pdZu + --x --sx --px etc. + Option names changed: + --iu --> --iU + --state-* --> --setup-* + I hope this didn't break anything. +22Jul99 JDTH : Allow thinkpad to initialize even if superio doesn't +22Jul99 JDTH : Update TROUBLESHOOTING file (outdate ref to 10:168 <- wrong) +21Jul99 JDTH : Add PS2.EXE/tpctl comparison to TODO + + +0.5.3 changes from 0.5.2 +------------------------- +21Jul99 JDTH : (build 2) Change Makefile: remove -D switch which + is new to version 4.0 of install and do mkdirs instead +21Jul99 JDTH : (build 2) Change tpctlify to add /usr/local/lib + to the ld path if it's not already there +21Jul99 JDTH : Cleaned up superio.c code +21Jul99 JDTH : Fixed bug in tpctlify script -- didn't abort +21Jul99 JDTH : Removed '--verbose' options from Makefile commands + +0.5.2 changes from 0.5.1 +------------------------- +21Jul99 JDTH : Added 'rpm' target +21Jul99 JDTH : Compiler warning messages ("implicit declaration") eliminated + *This should solve some kernel compatibility problems!* +21Jul99 JDTH : Rest of par and ser configuration options implemented +21Jul99 JDTH : Make module init function a bit safer +20Jul99 JDTH : Changed device number to 10:170 by order of the + device number czar + +0.5.1 changes from 0.5.0 +------------------------- +20Jul99 JDTH : Fixed version printout formatting +20Jul99 JDTH : Print actual IRQs used + +0.5.0 changes from 0.3.7 +------------------------- +20Jul99 JDTH : --rs* functionality augmented +19Jul99 JDTH : --im folded into --ib +19Jul99 JDTH : Install script is now '/usr/local/sbin/tpctlify' +19Jul99 JDTH : Kernel module is now called 'thinkpad' +19Jul99 JDTH : Device file is now called /dev/thinkpad (dev. number 10:168) +19Jul99 JDTH : Widespread changes in the code structure diff -urNp thinkpad/char/thinkpad/Makefile 2.4.20pre8aa2/char/thinkpad/Makefile --- thinkpad/char/thinkpad/Makefile Thu Jan 1 01:00:00 1970 +++ 2.4.20pre8aa2/char/thinkpad/Makefile Wed Oct 2 06:41:39 2002 @@ -0,0 +1,30 @@ +# +# Makefile for IBM ThinkPad control support (tpctl). +# +# See the README file in this directory for more info. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definitions are now inherited from the +# parent makes.. +# + +TPMODS = thinkpad.o smapi.o superio.o rtcmosram.o thinkpadpm.o + +obj-$(CONFIG_THINKPAD) := $(TPMODS) + +ifeq ($(CONFIG_THINKPAD),y) + O_TARGET = thinkpad_all.o +endif + +include $(TOPDIR)/Rules.make + +thinkpad_all.o: $(TPMODS) + rm -f $@ + $(LD) $(EXTRA_LDFLAGS) -r -o $@ $(TPMODS) + +smapi.o: smapi_core.o smapi_call.o + rm -f $@ + $(LD) $(EXTRA_LDFLAGS) -r -o $@ smapi_core.o smapi_call.o diff -urNp thinkpad/char/thinkpad/README 2.4.20pre8aa2/char/thinkpad/README --- thinkpad/char/thinkpad/README Thu Jan 1 01:00:00 1970 +++ 2.4.20pre8aa2/char/thinkpad/README Wed Oct 2 06:41:39 2002 @@ -0,0 +1,162 @@ + README file for + thinkpad device drivers + +Last updated: 13 April 2002 + +Introduction +============ + +thinkpad.o, smapi.o, superio.o, rtcmosram.o and thinkpadpm.o are loadable +kernel modules that serve as interfaces to the IBM System Management +Application Program Interface (SMAPI) BIOS found in some IBM ThinkPad laptop +computers, and as drivers of certain ThinkPad hardware components. Access +to the modules is via the ioctl() system call. Each module adds an entry +under /proc/driver/thinkpad named like itself which contains some information +about the module. + +These drivers were written to be used with the tpctl program. +Please see the README file for that program for more information. + +Requirements +============ + +Hardware +-------- + +IBM ThinkPad laptop computer. See the SUPPORTED-MODELS file for more +information. If this file wasn't included in the thinkpad package, look +for it in the tpctl package. + +Kernel +------ + +The 3.x releases of the drivers support Linux 2.4.0 or later. + + +Installation +============ + +If you are using Debian, install the thinkpad-base package, then +install the thinkpad-source package and use make-kpkg to make a +thinkpad-modules- package for your kernel and install +that. You are finished. + +On distributions that don't set things up for you automatically, +you can install from the source tarball. First make sure that your +kernel source tree is at /lib/modules/`uname -r`/build . Do: + tar zxvf thinkpad-.src.tar.gz + cd thinkpad- + make all + +Once compilation has finished, to install the files do the following +(as root): + make install +This installs the loadable kernel modules under the directory +/lib/modules//thinkpad . + +You may want to follow this with: + make clean +which deletes all compiled binaries from your source directory. + +If you do _not_ use devfs then you must create a device node for the +thinkpad device driver. As root do: + mknod --mode=664 /dev/thinkpad c 10 170 + +If you _do_ use devfs you don't need to make a node; the driver +modules will create nodes under /dev/thinkpad when they are loaded. + +It might be useful to create a "thinkpad" group and add to it users +whom you want to allow to adjust settings. Then the device node's +group should be changed to "thinkpad". Without devfs do this as +root: + chown root.thinkpad /dev/thinkpad +With devfs, to make this change permanent, add the following line to +/etc/devfsd.conf and restart devfsd: + REGISTER ^thinkpad/.*$ PERMISSIONS root.thinkpad 0664 + +The package is now installed. + + +Uninstallation +============== + +To remove all installed thinkpad device driver files: + make uninstall + +Note that this removes /lib/modules//thinkpad +and all its contents and subdirectories! + + +Usage -- modules +================ + +The modules are loaded automatically when they are needed. + +thinkpad.o dispatches requests to the other modules. It can be loaded with +the following parameters: + enable_smapi=(0|1) disable|enable use of smapi module + enable_superio=(0|1) disable|enable use of superio module + enable_rtcmosram=(0|1) disable|enable use of rtcmosram module + enable_thinkpadpm=(0|1) disable|enable use of thinkpadpm module +E.g., + insmod thinkpad enable_superio=0 +loads the thinkpad module while preventing it from using the superio module. +tpctl commands that employ the superio module will then return an error +message. The default value of each parameter is 1. These parameters can be +added to the /etc/modules.conf or /etc/conf.modules file as follows so that +they are in effect whenever thinkpad.o loaded by modprobe. E.g., + options thinkpad enable_smapi=0 enable_superio=0 +These parameters were added so that thinkpad.o can be used "safely" on +ThinkPads which lack some of the supported hardware. + +The file /proc/thinkpad/ contains information about each of +the drivers. + + +Security +======== + +The user requires write permission on the thinkpad device file (normally +/dev/thinkpad or /dev/thinkpad/thinkpad) in order to change settings or +to "sedate" the machine. This means that it is safe to allow an untrusted +user to execute tpctl or ntpctl, so long as he or she doesn't have write +permission on the device file. + + +References +========== + +In writing the code I found the following documentation helpful. +With the advent of kernel 2.4.0 much of their content is out of date. + +------------------------------------------------------------------------ + +IBM. _IBM ThinkPad 560Z Technical Reference_. First ed (October 1998). + _IBM ThinkPad 560 Technical Reference_. + _IBM ThinkPad 600 Technical Reference_. + _IBM ThinkPad 765 Technical Reference_. + _IBM ThinkPad 770 Technical Reference_. + +National Semiconductor. _PC87338/PC97338 data sheet_. November, 1998. + +Pomerantz, Ori. _Linux kernel module programming guide_. Version 1.1.0 + 26 April 1999. + +Rubini, Alessandro. _Linux device drivers_. Cambridge: O'Reilly, 1998. + +Rubini, Alessandro and Jonathan Corbet. _Linux device drivers_. 2nd ed. + Cambridge, O'Reilly, 2001. + http://www.oreilly.com/catalog/linuxdrive2/chapter/book/index.html + +------------------------------------------------------------------------ + +The first of the IBM Technical Reference manuals listed is the most +current and correct that I have found. All are available in the +"support" section of IBM's website www.ibm.com. + +I thank Ori Pomerantz for his contribution. + +The O'Reilly book, now in its second edition, is superb. + +-- +Thomas Hood diff -urNp thinkpad/char/thinkpad/SUPPORTED-MODELS 2.4.20pre8aa2/char/thinkpad/SUPPORTED-MODELS --- thinkpad/char/thinkpad/SUPPORTED-MODELS Thu Jan 1 01:00:00 1970 +++ 2.4.20pre8aa2/char/thinkpad/SUPPORTED-MODELS Wed Oct 2 06:41:39 2002 @@ -0,0 +1,854 @@ +The following is a list of outputs from the "tpctl --info-bios" +command that have been helpfully submitted by tpctl users. + +Because this information is obtained via a SMAPI function, each +of the machines listed below is proved to have some sort of +SMAPI BIOS, and so probably supports most of the functions of +tpctl. The machine may or may not support the "--r*" functions, +which do not use SMAPI. + +I give several outputs on the same line whenever several +users have submitted outputs that differ. The differences +reflect the fact that some people have newer machines than +others and/or have upgraded their BIOS. + +365X (2625-2E9) + system ID: 28 + country code: 1 + system BIOS revision: 0.28 + system management BIOS revision: 1.20 + SMAPI BIOS interface revision: 0.86 + video BIOS revision: 1.00 + slave controller revision: 1.10 + +(--r* options don't work) + +365XD + system ID: 28 + country code: 1 + system BIOS revision: 0.24 + system management BIOS revision: 1.18 + SMAPI BIOS interface revision: 0.86 + video BIOS revision: 1.00 + slave controller revision: 1.10 + +380D + system ID: 37 37 + country code: 1 1 + system BIOS revision: 0.17 0.33 + sys management BIOS revision: 1.10 1.16 + SMAPI BIOS interface revision: 0.88 0.88 + video BIOS revision: 1.22 1.32 + slave controller revision: 1.11 1.11 + +380ED + system ID: 37 + country code: 1 + system BIOS revision: 0.33 + system management BIOS revision: 1.16 + video BIOS revision: 1.32 + slave controller revision: 1.11 + +380XD (Australian model) + system ID: 44 + country code: 1 + system BIOS revision: 1.02 + system management BIOS revision: 1.01 + SMAPI BIOS interface revision: 0.90 + video BIOS revision: 1.12 + slave controller revision: 1.5 + +380Z (2635-HGO) + system ID: 54 + country code: 1 + system BIOS revision: 1.04 + system management BIOS revision: 1.08 + SMAPI BIOS interface revision: 0.90 + video BIOS revision: 1.15 + slave controller revision: 1.5 + +385CD (2635-2EU) + system ID: 37 + country code: 1 + system BIOS revision: 0.35 + system management BIOS revision: 1.18 + SMAPI BIOS interface revision: 0.88 + video BIOS revision: 1.32 + slave controller revision: 1.11 + +385XD (2635-DEU) + system ID: 53 + country code: 1 + system BIOS revision: 1.06 + system management BIOS revision: 1.10 + SMAPI BIOS interface revision: 0.90 + video BIOS revision: 1.16 + slave controller revision: 1.8 + +560 + system ID: 26 + country code: 1 + system BIOS revision: 0.27 + system management BIOS revision: 1.35 + SMAPI BIOS interface revision: 0.86 + video BIOS revision: 1.00 + slave controller revision: 1.2 + +560E + system ID: 38 + country code: 1 + system BIOS revision: 0.09 0.12 + system management BIOS revision: 1.37 1.40 + SMAPI BIOS interface revision: 0.86 + video BIOS revision: 1.00 + slave controller revision: 1.2 + +560X (233MHz MMX) + system ID: 43 + country code: 1 + system BIOS revision: 0.01 + system management BIOS revision: 1.04 + SMAPI BIOS interface revision: 0.90 + video BIOS revision: 1.11 + slave controller revision: 1.10 + +560Z + system ID: 55 + country code: 1 + system BIOS revision: 1.06 + system management BIOS revision: 1.09 + SMAPI BIOS interface revision: 0.90 + video BIOS revision: 1.16 + slave controller revision: 1.6 + +570 + system ID: 60 60 + country code: 1 1 + system BIOS revision: 0.31 0.34 + system management BIOS revision: 255.255 255.255 + SMAPI BIOS interface revision: 2.00 2.00 + video BIOS revision: 1.15 1.15 + slave controller revision: 0.9 1.0 + +570 (2644-3AU) + system ID: 60 + country code: 1 + system BIOS revision: 0.36 + system management BIOS revision: 255.255 + SMAPI BIOS interface revision: 2.00 + video BIOS revision: 1.15 + slave controller revision: 1.0 + +570E + system ID: 88 88 + country code: 1 1 + system BIOS revision: 0.11 0.14 + system management BIOS revision: 255.255 255.255 + SMAPI BIOS interface revision: 2.00 2.00 + video BIOS revision: 1.15 1.15 + slave controller revision: 1.1 1.2 + +600 (21U) + system ID: 45 45 45 + country code: 1 1 1 + system BIOS revision: 1.33 1.36 1.39 + sys management BIOS revision: 2.13 2.15 2.18 + SMAPI BIOS interface revision: 0.90 0.90 0.90 + video BIOS revision: 1.16 1.16 1.28 + slave controller revision: 1.14 1.14 1.15 + +600 (21O) + system ID: 45 + country code: 1 + system BIOS revision: 1.37 + sys management BIOS revision: 2.16 + SMAPI BIOS interface revision: 0.90 + video BIOS revision: 1.16 + slave controller revision: 1.14 + +600 (35U) + system ID: 45 + country code: 1 + system BIOS revision: 1.03 + system management BIOS revision: 1.03 + SMAPI BIOS interface revision: 0.90 + video BIOS revision: 1.14 + slave controller revision: 1.14 + +600 (41A) + system ID: 45 + country code: 1 + system BIOS revision: 1.39 + system management BIOS revision: 2.18 + SMAPI BIOS interface revision: 0.90 + video BIOS revision: 1.28 + slave controller revision: 1.15 + +600 (45O) + system ID: 45 + country code: 1 + system BIOS revision: 1.36 + system management BIOS revision: 2.15 + SMAPI BIOS interface revision: 0.90 + video BIOS revision: 1.16 + slave controller revision: 1.14 + +600 (51U) + system ID: 45 45 45 45 45 + country code: 1 1 1 1 1 + system BIOS revision: 1.38 1.39 1.47 1.48 1.49 + system management BIOS revision: 2.17 2.18 2.24 2.24 2.24 + SMAPI BIOS interface revision: 0.90 0.90 0.90 0.90 0.90 + video BIOS revision: 1.16 1.28 1.28 1.28 1.28 + slave controller revision: 1.14 1.15 1.15 1.15 1.15 + +600 (85U) + system ID: 45 + country code: 1 + system BIOS revision: 1.39 + system management BIOS revision: 2.18 + SMAPI BIOS interface revision: 0.90 + video BIOS revision: 1.28 + slave controller revision: 1.15 + +600E (2645-4AA) + system ID: 68 + country code: 1 + system BIOS revision: 1.03 + system management BIOS revision: 1.00 + SMAPI BIOS interface revision: 0.92 + video BIOS revision: 1.15 + slave controller revision: 1.5 + +600E (2645-4AU) + system ID: 68 + country code: 1 + system BIOS revision: 1.14 + system management BIOS revision: 1.07 + SMAPI BIOS interface revision: 0.92 + video BIOS revision: 1.15 + slave controller revision: 1.8 + +600E (2645-550) + system ID: 57 + country code: 1 + system BIOS revision: 1.04 + system management BIOS revision: 1.04 + SMAPI BIOS interface revision: 0.92 + video BIOS revision: 1.15 + slave controller revision: 1.4 + +600E (2645-5AA) + system ID: 68 + country code: 1 + system BIOS revision: 1.09 + system management BIOS revision: 1.05 + SMAPI BIOS interface revision: 0.92 + video BIOS revision: 1.15 + slave controller revision: 1.5 + +600E (2645-5AO) + system ID: 68 + country code: 1 + system BIOS revision: 1.10 + system management BIOS revision: 1.06 + SMAPI BIOS interface revision: 0.92 + video BIOS revision: 1.15 + slave controller revision: 1.8 + +600E (2645-5BU) + system ID: 68 + country code: 1 + system BIOS revision: 1.21 + system management BIOS revision: 1.11 + SMAPI BIOS interface revision: 0.92 + video BIOS revision: 1.15 + slave controller revision: 1.8 + +600E (2645-5JU) + system ID: 68 + country code: 1 + system BIOS revision: 1.15 + system management BIOS revision: 1.08 + SMAPI BIOS interface revision: 0.92 + video BIOS revision: 1.15 + slave controller revision: 1.8 + +600E (2645-8A0) + system ID: 68 + country code: 1 + system BIOS revision: 1.03 + system management BIOS revision: 1.00 + SMAPI BIOS interface revision: 0.92 + video BIOS revision: 1.15 + slave controller revision: 1.5 + +600E (2645-A5U) + system ID: 57 + country code: 1 + system BIOS revision: 1.06 + system management BIOS revision: 1.05 + SMAPI BIOS interface revision: 0.92 + video BIOS revision: 1.15 + slave controller revision: 1.4 + +600E (2645-UN1) + system ID: 68 + country code: 1 + system BIOS revision: 1.09 + system management BIOS revision: 1.05 + SMAPI BIOS interface revision: 0.92 + video BIOS revision: 1.15 + slave controller revision: 1.5 + +600X (2645-3EU) + system ID: 74 74 + country code: 1 1 + system BIOS revision: 1.10 1.13 + system management BIOS revision: 1.06 1.07 + SMAPI BIOS interface revision: 0.93 0.93 + video BIOS revision: 2.00 2.00 + slave controller revision: 1.10 1.10 + +600X (2645-4EU) + system ID: 74 74 74 + country code: 1 1 1 + system BIOS revision: 1.04 1.10 1.13 + system management BIOS revision: 1.01 1.06 1.07 + SMAPI BIOS interface revision: 0.93 0.93 0.93 + video BIOS revision: 2.00 2.00 2.00 + slave controller revision: 1.10 1.10 1.10 + +600X (2645-5EU) + system ID: 74 + country code: 1 + system BIOS revision: 1.04 + system management BIOS revision: 1.01 + SMAPI BIOS interface revision: 0.93 + video BIOS revision: 2.00 + slave controller revision: 1.10 + +600X (2645-5FU) + + system ID: 74 + country code: 1 + system BIOS revision: 1.18 + system management BIOS revision: 1.11 + SMAPI BIOS interface revision: 0.93 + video BIOS revision: 2.00 + slave controller revision: 1.10 + +600X (2645-7EG) + system ID: 74 + country code: 1 + system BIOS revision: 1.12 + system management BIOS revision: 1.07 + SMAPI BIOS interface revision: 0.93 + video BIOS revision: 2.00 + slave controller revision: 1.10 + +600X (2646-8EU) + system ID: 74 74 + country code: 1 1 + system BIOS revision: 1.13 1.20 + system management BIOS revision: 1.07 1.11 + SMAPI BIOS interface revision: 0.93 0.93 + video BIOS revision: 2.00 2.00 + slave controller revision: 1.10 1.10 + +760C + system ID: 14 + country code: 1 + system BIOS revision: 0.14 0.30 + system management BIOS revision: 1.15 1.22 + SMAPI BIOS interface revision: 0.78 + video BIOS revision: 1.00 + slave controller revision: 2.2 + +760E + system ID: 17 + country code: 1 + system BIOS revision: 0.47 + system management BIOS revision: 1.36 + SMAPI BIOS interface revision: 0.86 + video BIOS revision: 1.00 + slave controller revision: 1.8 + +760ED (9546-U3A) + system ID: 24 + country code: 1 + system BIOS revision: 0.56 0.57 + system management BIOS revision: 1.43 1.44 + SMAPI BIOS interface revision: 0.86 + video BIOS revision: 1.00 + slave controller revision: 1.8 + +"760EL" + system ID: 24 + country code: 1 + system BIOS revision: 0.59 + system management BIOS revision: 1.45 + SMAPI BIOS interface revision: 0.86 + video BIOS revision: 1.00 + slave controller revision: 1.12 + +760EL (9547) + system ID: 17 + country code: 1 + system BIOS revision: 0.45 + system management BIOS revision: 1.35 + SMAPI BIOS interface revision: 0.86 + video BIOS revision: 1.00 + slave controller revision: 1.12 + +760XD (9546) + system ID: 33 + country code: 1 + system BIOS revision: 0.50 + system management BIOS revision: 1.34 + SMAPI BIOS interface revision: 0.86 + video BIOS revision: 1.00 + slave controller revision: 1.12 + +760XL (9547-U9C) + system ID: 24 + country code: 1 + system BIOS revision: 0.57 + system management BIOS revision: 1.44 + SMAPI BIOS interface revision: 0.86 + video BIOS revision: 1.00 + slave controller revision: 1.12 + +765D (9546-U9H) + system ID: 33 + country code: 1 + system BIOS revision: 0.49 + system management BIOS revision: 1.33 + SMAPI BIOS interface revision: 0.86 + video BIOS revision: 1.00 + slave controller revision: 1.12 + +770 (9548) + system ID: 39 + country code: 1 + system BIOS revision: 1.26 + sys management BIOS revision: 2.06 + SMAPI BIOS interface revision: 0.90 + video BIOS revision: 1.21 + slave controller revision: 1.17 + +770 (9549-1A) + system ID: 39 + country code: 1 + system BIOS revision: 1.31 + system management BIOS revision: 2.12 + SMAPI BIOS interface revision: 0.90 + video BIOS revision: 1.22 + slave controller revision: 1.17 + +770 (9549-1AU) + system ID: 39 + country code: 1 + system BIOS revision: 1.32 + system management BIOS revision: 2.13 + SMAPI BIOS interface revision: 0.90 + video BIOS revision: 1.22 + slave controller revision: 1.17 + +770ED + system ID: 46 + country code: 1 + system BIOS revision: 1.31 + sys management BIOS revision: 2.12 + SMAPI BIOS interface revision: 0.90 + video BIOS revision: 1.22 + slave controller revision: 1.8 + +"770E/ED" (9549-5AU) + system ID: 46 + country code: 1 + system BIOS revision: 1.28 + system management BIOS revision: 2.10 + SMAPI BIOS interface revision: 0.90 + video BIOS revision: 1.22 + slave controller revision: 1.8 + +770X (9549-7B0) + system ID: 56 56 + country code: 1 1 + system BIOS revision: 1.01 1.09 + sys management BIOS revision: 1.01 1.07 + SMAPI BIOS interface revision: 0.92 0.92 + video BIOS revision: 1.24 1.27 + slave controller revision: (?) 1.7 + +770X (9549-7BU) + system ID: 56 + country code: 1 + system BIOS revision: 1.10 + sys management BIOS revision: 1.08 + SMAPI BIOS interface revision: 0.92 + video BIOS revision: 1.27 + slave controller revision: 1.7 + +770Z (9549-8AU) + system ID: 67 + country code: 1 + system BIOS revision: 1.01 + system management BIOS revision: 0.13 + SMAPI BIOS interface revision: 0.92 + video BIOS revision: 1.27 + slave controller revision: 1.6 + +770Z (9549-820) + system ID: 67 + country code: 1 + system BIOS revision: 1.03 + system management BIOS revision: 1.01 + SMAPI BIOS interface revision: 0.92 + video BIOS revision: 1.27 + slave controller revision: 1.6 + +A20, A30, T20 (2647-44U), T21, X20 (26621BK) + Many tpctl functions work on these new ThinkPad models, + but "--ib" isn't one of them. :( + +R30 + No SMAPI BIOS or Super I/O chip, so only tpctl -ic works. + + +------------------------------------------------------------------------- +Here is a thorough test of tpctl on an A30. + +(The following work as expected.) +tpctl --hibernate +tpctl --suspend +tpctl --standby +tpctl --pmb=high +tpctl --pmb=auto +tpctl --help + +tpctl --all + tpctl: SMAPI BIOS error 0x86 ("function is not supported") -- exiting. + +tpctl --info-all + tpctl: SMAPI BIOS error 0x86 ("function is not supported") -- exiting. + +tpctl --info-bios + tpctl: SMAPI BIOS error 0x86 ("function is not supported") -- exiting. + +tpctl --info-docking + information about docking station: + docking station ID: (not docked) + security key unlocked?: - + bus connected?: - + +tpctl --info-sensor + is: + the lid closed?: N + the keyboard open?: N + the AC adapter attached?: N + +tpctl --setup-all + setup of display: CMOS current + internal display enabled?: disable enable + crt display: enable disable + tv display: disable disable + 2ual display: enable enable + TV display selected?: N N + monitor detection ignored?: N N + setup of fn hotkey: + sticky Fn key supported?: N + sticky & locked Fn key supported?: Y + fn hotkey state: nonsticky + setup of pointing device: CMOS current + internal pointing device + controllable state?: Y Y + auto control supported?: Y Y + activation mode: auto-disable auto-disable + external pointing device + controllable state?: N N + activation mode: disable disable + setup of: CMOS + daylight saving time: disable + +tpctl --setup-display-all + setup of display: CMOS current + internal display enabled?: disable enable + crt display: enable disable + tv display: disable disable + 2ual display: enable enable + TV display selected?: N N + monitor detection ignored?: N N + +tpctl --setup-display-internal + setup of display: CMOS current + internal display enabled?: disable enable + +tpctl --setup-display-CRT + setup of display: CMOS current + crt display: enable disable + +tpctl --setup-display-TV + setup of display: CMOS current + tv display: disable disable + +tpctl --setup-display-TV-select + setup of display: CMOS current + TV display selected?: N N + +tpctl --setup-display-monitor-detection-ignore + setup of display: CMOS current + monitor detection ignored?: N N + +tpctl --setup-display-dual + setup of display: CMOS current + 2ual display: enable enable + +tpctl --setup-Fn-hotkey + setup of fn hotkey: + sticky Fn key supported?: N + sticky & locked Fn key supported?: Y + fn hotkey state: nonsticky + +tpctl --setup-pointing-device-all + setup of pointing device: CMOS current + internal pointing device + controllable state?: Y Y + auto control supported?: Y Y + activation mode: auto-disable auto-disable + external pointing device + controllable state?: N N + activation mode: disable disable + +tpctl --setup-pointing-device-internal + setup of pointing device: CMOS current + internal pointing device + controllable state?: Y Y + auto control supported?: Y Y + activation mode: auto-disable auto-disable + +tpctl --setup-pointing-device-external + setup of pointing device: CMOS current + external pointing device + controllable state?: N N + activation mode: disable disable + +tpctl --setup-daylight-saving-time + setup of: CMOS + daylight saving time: disable + +tpctl --pm-all + power management modes: + ac power expenditure: high + battery power expenditure: auto + RediSafe global mode overrides non-global mode?: Y + RediSafe globally enabled?: N + power management resume events: capability current + appointment-r.t.clock-initiated?: Y N (daily 00:00:00) + hardware-initiated?: Y Y + lid-opening-initiated?: Y Y + serial-RI-initiated?: Y N + power management sedative events: capability current + (SZRHO) (SZRHO) + hardware-or-software-initiated: SZ-HO SZ-HO + power-switch-initiated: ---HO ----O + lid-closure-initiated: -Z--- -Z--- + Standby-timer-initiated: ----- ----- + Zuspend-or-hibern.-timer-initiated: -Z-H- -Z--- + Hibernate-from-susp.-timer-init'd: ----- ----- + battery-low-initiated: -Z-H- -Z-H- + env'mt-exhausted-initiated: -Z--- -Z--- + power management timer modes: capability current + Standby timer: N N + Zuspend-or-hibernation timer: Y Y + Blank-internal-display timer: Y Y + drive power-down timer: Y Y + power management delay of Hibernate-from-suspend: 30 minutes + power management delays of Zuspend or hibernate: current + (specifiable in each power mode)? + ac power "manual" expenditure mode: Y 5 minutes + tpctl: SMAPI BIOS error 0x81 ("invalid parameter") -- exiting. + +tpctl --pm-mode-all + power management modes: + ac power expenditure: high + battery power expenditure: auto + RediSafe global mode overrides non-global mode?: Y + RediSafe globally enabled?: N + +tpctl --pm-mode-AC + power management modes: + ac power expenditure: high + +tpctl --pm-mode-battery + power management modes: + battery power expenditure: auto + +tpctl --pm-mode-RediSafe + power management modes: + RediSafe global mode overrides non-global mode?: Y + RediSafe globally enabled?: N + +tpctl --pm-mode-safe-suspend + power management modes: + RediSafe global mode overrides non-global mode?: Y + RediSafe globally enabled?: N + +tpctl --pm-resume-all + power management resume events: capability current + appointment-r.t.clock-initiated?: Y N (daily 00:00:00) + hardware-initiated?: Y Y + lid-opening-initiated?: Y Y + serial-RI-initiated?: Y N + +tpctl --pm-resume-appointment + power management resume events: capability current + appointment-r.t.clock-initiated?: Y N (daily 00:00:00) + +tpctl --pm-resume-hardware + power management resume events: capability current + h ardware-initiated?: Y Y + +tpctl --pm-resume-lid + power management resume events: capability current + lid-opening-initiated?: Y Y + +tpctl --pm-resume-serial-RI + power management resume events: capability current + serial-RI-initiated?: Y N + +tpctl --pm-sedation-all + power management sedative events: capability current + (SZRHO) (SZRHO) + hardware-or-software-initiated: SZ-HO SZ-HO + power-switch-initiated: ---HO ----O + lid-closure-initiated: -Z--- -Z--- + Standby-timer-initiated: ----- ----- + Zuspend-or-hibern.-timer-initiated: -Z-H- -Z--- + Hibernate-from-susp.-timer-init'd: ----- ----- + battery-low-initiated: -Z-H- -Z-H- + env'mt-exhausted-initiated: -Z--- -Z--- + +tpctl --pm-sedation-standby-timer + power management sedative events: capability current + (SZRHO) (SZRHO) + S tandby-timer-initiated: ----- ----- + +tpctl --pm-sedation-suspend-or-hibernate-timer + power management sedative events: capability current + (SZRHO) (SZRHO) + Z uspend-or-hibern.-timer-initiated: -Z-H- -Z--- + +tpctl --pm-sedation-hibernate-from-suspend-timer + power management sedative events: capability current + (SZRHO) (SZRHO) + Hibernate-from-susp.-timer-init'd: ----- ----- + +tpctl --pm-sedation-battery-low + power management sedative events: capability current + (SZRHO) (SZRHO) + battery-low-initiated: -Z-H- -Z-H- + +tpctl --pm-sedation-environment-exhausted + power management sedative events: capability current + (SZRHO) (SZRHO) + env'mt-exhausted-initiated: -Z--- -Z--- + +tpctl --pm-sedation-hardware-or-software + power management sedative events: capability current + (SZRHO) (SZRHO) + hardware-or-software-initiated: SZ-HO SZ-HO + +tpctl --pm-sedation-lid-closure + power management sedative events: capability current + (SZRHO) (SZRHO) + lid-closure-initiated: -Z--- -Z--- + +tpctl --pm-sedation-power-switch + power management sedative events: capability current + (SZRHO) (SZRHO) + power-switch-initiated: ---HO ----O + +tpctl --pm-timer-mode-all + power management timer modes: capability current + Standby timer: N N + Zuspend-or-hibernation timer: Y Y + Blank-internal-display timer: Y Y + drive power-down timer: Y Y + +tpctl --pm-timer-mode-blank-display + power management timer modes: capability current + Blank-internal-display timer: Y Y + +tpctl --pm-timer-mode-standby + power management timer modes: capability current + Standby timer: N N + +tpctl --pm-timer-mode-suspend-or-hibernate + power management timer modes: capability current + Zuspend-or-hibernation timer: Y Y + +tpctl --pm-timer-mode-drive-powerdown + power management timer modes: capability current + drive power-down timer: Y Y + +tpctl --pm-delay-all + power management delay of Hibernate-from-suspend: 30 minutes + power management delays of Zuspend or hibernate: current + (specifiable in each power mode)? + ac power "manual" expenditure mode: Y 5 minutes + tpctl: SMAPI BIOS error 0x81 ("invalid parameter") -- exiting. + +tpctl --pm-delay-hibernate-from-suspend + power management delay of Hibernate-from-suspend: 30 minutes + +tpctl --pm-delay-suspend-or-hibernate-all + power management delays of Zuspend or hibernate: current + (specifiable in each power mode)? + ac power "manual" expenditure mode: Y 5 minutes + tpctl: SMAPI BIOS error 0x81 ("invalid parameter") -- exiting. + +tpctl --pm-delay-suspend-or-hibernate-AC-manual + tpctl: unrecognized option `--pm-delay-suspend-or-hibernate-AC-manual' + tpctl: Error scanning options. Try 'tpctl --help'. + +tpctl --pm-delay-suspend-or-hibernate-battery-manual + tpctl: unrecognized option `--pm-delay-suspend-or-hibernate-battery-manual' + tpctl: Error scanning options. Try 'tpctl --help'. + +tpctl --pm-delay-suspend-or-hibernate-high + power management delays of Zuspend or hibernate: current + (specifiable in each power mode)? + "h igh" power expenditure mode: Y 60 minutes + +tpctl --pm-delay-suspend-or-hibernate-auto + power management delays of Zuspend or hibernate: current + (specifiable in each power mode)? + tpctl: SMAPI BIOS error 0x81 ("invalid parameter") -- exiting. + +tpctl --resource-all + resource state: ioaddr irq# able? mode/power + tpctl: module required for request is not loaded. + +tpctl --resource-floppy + resource state: ioaddr irq# able? mode/power + tpctl: module required for request is not loaded. + +tpctl --resource-parallel + resource state: ioaddr irq# able? mode/power + tpctl: module required for request is not loaded. + +tpctl --resource-serial-all + resource state: ioaddr irq# able? mode/power + tpctl: module required for request is not loaded. + +tpctl --resource-serial-1 + resource state: ioaddr irq# able? mode/power + tpctl: module required for request is not loaded. + +tpctl --resource-serial-2 + resource state: ioaddr irq# able? mode/power + tpctl: module required for request is not loaded. + +------------------------------------------------------------------------- diff -urNp thinkpad/char/thinkpad/rtcmosram.c 2.4.20pre8aa2/char/thinkpad/rtcmosram.c --- thinkpad/char/thinkpad/rtcmosram.c Thu Jan 1 01:00:00 1970 +++ 2.4.20pre8aa2/char/thinkpad/rtcmosram.c Wed Oct 2 06:41:39 2002 @@ -0,0 +1,351 @@ + +/********************************************************************* + * + * Filename: rtcmosram.c + * Description: rtcmosram is a kernel module that serves to interface + * with the RT/CMOS RAM in IBM ThinkPads + * Author: Thomas Hood + * Created: 24 July 1999 + * + * Please report bugs to the author ASAP. + * + * Copyright (c) 1999 J.D. Thomas Hood, All rights reserved + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * To receive a copy of the GNU General Public License, please write + * to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA + * + ********************************************************************/ + +#include "thinkpad_driver.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "thinkpad_common.h" +#include "rtcmosram.h" + + +/****** definitions ******/ + + +/****** declarations ******/ + +extern struct proc_dir_entry *thinkpad_ppde; + +#ifdef CONFIG_DEVFS_FS +static int rtcmosram_open( + struct inode * pinodeThe, + struct file * pfileThe +); +static int rtcmosram_release( + struct inode * pinodeThe, + struct file * pfileThe +); +static int rtcmosram_ioctl( + struct inode * pinodeThe, + struct file * pfileThe, + unsigned int uintIoctlNum, + unsigned long ulongIoctlArg +); +#endif + +/****** variables ******/ + +static const char _szMyName[] = "rtcmosram"; +static const char _szImName[] = "rtcmosram_do"; +static const char _szMyVersion[] = "3.0"; +static const char _szProcfile[] = "driver/thinkpad/rtcmosram"; +static struct resource *_presourceRtcmosram; + +MODULE_AUTHOR( "Thomas Hood" ); +MODULE_DESCRIPTION( "Driver for the RT CMOS RAM device on IBM ThinkPads" ); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,10) +MODULE_LICENSE( "GPL" ); +#endif + +#ifdef CONFIG_DEVFS_FS +static struct file_operations _fileopsRtcmosram = { + ioctl: rtcmosram_ioctl, + open: rtcmosram_open, + release: rtcmosram_release, + owner: THIS_MODULE +}; + +static devfs_handle_t _devfs_handleRtcmosram; +#endif + +/****** functions *******/ + +/* + * We use _p variants just for safety. The rtc_lock spinlock keeps us + * from fighting with the rtc driver. + */ +static byte cmos_getb( byte bWhere ) +{ + byte bGot; + unsigned long flags; + + spin_lock_irqsave(&rtc_lock,flags); + outb_p( bWhere, 0x70 ); + bGot = inb_p( 0x71 ); + outb_p( 0x0f, 0x70 ); /* required, according to Tech Ref */ + inb( 0x71 ); + spin_unlock_irqrestore(&rtc_lock,flags); + + return bGot; +} + + +static void cmos_putb( byte bWhat, byte bWhere ) +{ + unsigned long flags; + + spin_lock_irqsave(&rtc_lock,flags); + outb_p( bWhere, 0x70 ); + outb_p( bWhat, 0x71 ); + outb_p( 0x0F, 0x70 ); /* required, according to Tech Ref */ + inb( 0x71 ); + spin_unlock_irqrestore(&rtc_lock,flags); + + return; +} + + +static int rtcmosram_read_proc( + char *pchBuf, + char **ppchStart, + off_t off, + int intCount, + int *pintEof, + void *data +) { + return snprintf( + pchBuf, intCount, + "%s version %s accessing RT CMOS RAM at ioports 0x%x, 0x%x\n", + _szMyName, _szMyVersion, + 0x70, 0x71 + ); +} + + +int rtcmosram_do( + unsigned long ulongIoctlArg, + flag_t fCallerHasWritePerm +) { + rtcmosram_ioparm_t ioparmMy; + unsigned long ulRtnCopy; + + ulRtnCopy = copy_from_user( + (byte *)&ioparmMy, + (byte *)(rtcmosram_ioparm_t *)ulongIoctlArg, + sizeof( ioparmMy ) + ); + if ( ulRtnCopy ) return -EFAULT; + + switch ( ioparmMy.in.wFunc ) { + + case RTCMOSRAM_FUNC_GETDATA: { + rtcmosram_data_t dataThe; + int i; + + for ( i=0; idata), + (byte *)&dataThe, + sizeof(dataThe) + ); + if ( ulRtnCopy ) return -EFAULT; + + return 0; + } + + case RTCMOSRAM_FUNC_DAYLIGHTSAVINGTIME_ABLIFY: + if ( ! fCallerHasWritePerm ) + return -EACCES; + + if ( (flag_t)ioparmMy.in.dwParm1 ) { + cmos_putb( cmos_getb(0xB) | 1, 0xB ); + } else { + cmos_putb( cmos_getb(0xB) & ~1, 0xB ); + } + return 0; + + case RTCMOSRAM_FUNC_DAYLIGHTSAVINGTIME_GET: { + byte bGot; + bGot = cmos_getb( 0xB ); + ioparmMy.out.wRtn = 0; + ioparmMy.out.dwParm1 = (bGot & 1) ? (dword)1 : (dword)0; + ulRtnCopy = copy_to_user( + (byte *)(rtcmosram_ioparm_t *)ulongIoctlArg, + (byte *)&ioparmMy, + sizeof(ioparmMy) + ); + if ( ulRtnCopy ) return -EFAULT; + return 0; + } + + default: + printk(KERN_ERR + "%s: Function %d not recognized\n", + _szMyName, ioparmMy.in.wFunc + ); + return -EINVAL; + } /* switch */ + + return -ETHINKPAD_PROGRAMMING; /* we should not reach here */ +} + + +#ifdef CONFIG_DEVFS_FS +static int rtcmosram_open( + struct inode * pinodeThe, + struct file * pfileThe +) { + + return 0; +} + + +static int rtcmosram_release( + struct inode * pinodeThe, + struct file * pfileThe +) { + + return 0; +} + + +static flag_t caller_has_w( struct file * pfileThe ) +{ + return ((pfileThe->f_mode) & FMODE_WRITE) ? 1 : 0; +} + + +static int rtcmosram_ioctl( + struct inode * pinodeThe, + struct file * pfileThe, + unsigned int uintIoctlNum, + unsigned long ulongIoctlArg +) { + +#ifdef DEBUG_VERBOSE + printk( "%s: Doing ioctl number 0x%x\n", _szMyName, uintIoctlNum ); +#endif + + switch ( uintIoctlNum ) { + /* should return at the end of each case block */ + + case IOCTL_RTCMOSRAM_REQUEST: + return rtcmosram_do( + ulongIoctlArg, + caller_has_w( pfileThe ) + ); + + default: + /* ioctl number not recognized -- do nothing */ + return -ENOTTY; + + } /* switch */ + + return -ETHINKPAD_PROGRAMMING; /* We should never arrive here */ +} +#endif /* defined(CONFIG_DEVFS_FS) */ + +static int __init rtcmosram_init( void ) +{ + + _presourceRtcmosram = request_region( 0x70, 2, _szMyName ); + if ( _presourceRtcmosram == NULL ) { +#if 0 + printk(KERN_ERR + "%s: I/O ports for RT CMOS RAM not available -- aborting.\n", + _szMyName + ); + return -EBUSY; +#else + /* + * In some configs this region is already claimed by "rtc" + * Don't worry about it, since we take rtc_lock when we + * access the CMOS RAM + */ + printk(KERN_INFO + "%s: I/O ports for RT CMOS RAM not available, but ignoring this.\n", + _szMyName + ); +#endif + } + + if ( !thinkpad_ppde || !create_proc_read_entry( + _szProcfile, + S_IFREG | S_IRUGO, + NULL, + rtcmosram_read_proc, + NULL + ) ) { + printk(KERN_ERR + "%s: Could not create_proc_read_entry() /proc/%s\n", + _szMyName, _szProcfile + ); + } + /* proc entry created */ + +#ifdef CONFIG_DEVFS_FS + _devfs_handleRtcmosram = devfs_register( + NULL /* dir */, + "thinkpad/rtcmosram", + DEVFS_FL_DEFAULT | DEVFS_FL_AUTO_DEVNUM, + 0 /* major */, 0 /* minor */, + S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH, + &_fileopsRtcmosram, + NULL /* info */ + ); + if ( _devfs_handleRtcmosram == NULL ) { + printk(KERN_ERR "%s: Could not devfs_register(). Aborting.\n", _szMyName ); + return -EIO; + } + /* devfs entry created */ +#endif + + inter_module_register( _szImName, THIS_MODULE, &rtcmosram_do ); + + return 0; +} + + +static void __exit rtcmosram_exit( void ) +{ + + inter_module_unregister( _szImName ); + +#ifdef CONFIG_DEVFS_FS + devfs_unregister( _devfs_handleRtcmosram ); +#endif + + remove_proc_entry( _szProcfile, NULL ); + + if ( _presourceRtcmosram != NULL ) release_resource( _presourceRtcmosram ); + + return; +} + +module_init(rtcmosram_init); +module_exit(rtcmosram_exit); diff -urNp thinkpad/char/thinkpad/rtcmosram.h 2.4.20pre8aa2/char/thinkpad/rtcmosram.h --- thinkpad/char/thinkpad/rtcmosram.h Thu Jan 1 01:00:00 1970 +++ 2.4.20pre8aa2/char/thinkpad/rtcmosram.h Wed Oct 2 06:41:39 2002 @@ -0,0 +1,198 @@ + +/********************************************************************* + * + * Filename: rtcmosram.h + * Description: header file for the rtcmosram driver + * Author: Thomas Hood + * Created: 24 July 1999 + * + * Please report bugs to the author ASAP. + * + * Copyright (c) 1999 J.D. Thomas Hood, All rights reserved + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * To receive a copy of the GNU General Public License, please write + * to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA + * + ********************************************************************/ + +#ifndef __RTCMOSRAM_H__ +#define __RTCMOSRAM_H__ + +/****** defines ******/ + +#define RTCMOSRAM_FUNC_GETDATA (0) +#define RTCMOSRAM_FUNC_DAYLIGHTSAVINGTIME_ABLIFY (1) +#define RTCMOSRAM_FUNC_DAYLIGHTSAVINGTIME_GET (2) + +/****** typedefs ******/ + +typedef struct _rtcmosram_data_t { + byte bSeconds; /* 0x00 */ + byte bSecondAlarm; /* 0x01 */ + byte bMinutes; /* 0x02 */ + byte bMinuteAlarm; /* 0x03 */ + byte bHours; /* 0x04 */ + byte bHourAlarm; /* 0x05 */ + byte bDayOfWeek; /* 0x06 */ + byte bDateOfMonth; /* 0x07 */ + byte bMonth; /* 0x08 */ + byte bYear; /* 0x09 */ + byte bStatusA; /* 0x0A */ + byte bStatusB; /* 0x0B */ + byte bStatusC; /* 0x0C */ + byte bStatusD; /* 0x0D */ + byte bStatusDiag; /* 0x0E */ + byte bStatusShutdown; /* 0x0F */ + byte bDisketteDriveType; /* 0x10 */ + byte bHardDiskDrive23Type;/* 0x11 */ + byte bHardDiskDrive01Type;/* 0x12 */ + byte bReserved13; /* 0x13 */ + byte bEquipment; /* 0x14 */ + byte bSizeBaseMemLow; /* 0x15 */ /* Note that there is a word boundary */ + byte bSizeBaseMemHigh; /* 0x16 */ /* between the two halves of this ! */ + byte bSizeExpMemLow; /* 0x17 */ /* Note that there is a word boundary */ + byte bSizeExpMemHigh; /* 0x18 */ /* between the two halves of this ! */ + byte bReserved19; /* 0x19 */ + byte bReserved1A; /* 0x1A */ + byte bHardDiskDrive2Type;/* 0x1B */ + byte bHardDiskDrive3Type;/* 0x1C */ + byte bReserved1D; /* 0x1D */ + byte bReserved1E; /* 0x1E */ + byte bReserved1F; /* 0x1F */ + byte bReserved20; /* 0x20 */ + /* On the ThinkPad 600 21U, the low two bits of bReserved20 + * record the internal pointing device setup: + * 0:enable 1:disable 2:autodisable */ + byte bReserved21; /* 0x21 */ + byte bReserved22; /* 0x22 */ + byte bReserved23; /* 0x23 */ + byte bReserved24; /* 0x24 */ + byte bReserved25; /* 0x25 */ + byte bReserved26; /* 0x26 */ + byte bReserved27; /* 0x27 */ + byte bReserved28; /* 0x28 */ + byte bReserved29; /* 0x29 */ + byte bReserved2A; /* 0x2A */ + byte bReserved2B; /* 0x2B */ + byte bReserved2C; /* 0x2C */ + byte bReserved2D; /* 0x2D */ + byte bConfigChecksumHigh;/* 0x2E */ + byte bConfigChecksumLow; /* 0x2F */ + word wSizeUsableMem; /* 0x30,0x31 */ + bcd8_t bcd8DateCentury; /* 0x32 */ + byte bReserved33; /* 0x33 */ + byte bReserved34; /* 0x34 */ + byte bReserved35; /* 0x35 */ + byte bReserved36; /* 0x36 */ + byte bReserved37; /* 0x37 */ + byte bReserved38; /* 0x38 */ + byte bReserved39; /* 0x39 */ + byte bReserved3A; /* 0x3A */ + byte bReserved3B; /* 0x3B */ + byte bReserved3C; /* 0x3C */ + byte bReserved3D; /* 0x3D */ + byte bReserved3E; /* 0x3E */ + byte bReserved3F; /* 0x3F */ + byte bReserved40; /* 0x40 */ + byte bReserved41; /* 0x41 */ + byte bReserved42; /* 0x42 */ + byte bReserved43; /* 0x43 */ + byte bReserved44; /* 0x44 */ + byte bReserved45; /* 0x45 */ + byte bReserved46; /* 0x46 */ + byte bReserved47; /* 0x47 */ + byte bReserved48; /* 0x48 */ + byte bReserved49; /* 0x49 */ + byte bReserved4A; /* 0x4A */ + byte bReserved4B; /* 0x4B */ + byte bReserved4C; /* 0x4C */ + byte bReserved4D; /* 0x4D */ + byte bReserved4E; /* 0x4E */ + byte bReserved4F; /* 0x4F */ + byte bReserved50; /* 0x50 */ + byte bReserved51; /* 0x51 */ + byte bReserved52; /* 0x52 */ + byte bReserved53; /* 0x53 */ + byte bReserved54; /* 0x54 */ + byte bReserved55; /* 0x55 */ + byte bReserved56; /* 0x56 */ + byte bReserved57; /* 0x57 */ + byte bReserved58; /* 0x58 */ + byte bReserved59; /* 0x59 */ + byte bReserved5A; /* 0x5A */ + byte bReserved5B; /* 0x5B */ + byte bReserved5C; /* 0x5C */ + byte bReserved5D; /* 0x5D */ + byte bReserved5E; /* 0x5E */ + byte bReserved5F; /* 0x5F */ + byte bReserved60; /* 0x60 */ + byte bReserved61; /* 0x61 */ + byte bReserved62; /* 0x62 */ + byte bReserved63; /* 0x63 */ + byte bReserved64; /* 0x64 */ + byte bReserved65; /* 0x65 */ + byte bReserved66; /* 0x66 */ + byte bReserved67; /* 0x67 */ + byte bReserved68; /* 0x68 */ + byte bReserved69; /* 0x69 */ + byte bReserved6A; /* 0x6A */ + byte bReserved6B; /* 0x6B */ + byte bReserved6C; /* 0x6C */ + byte bReserved6D; /* 0x6D */ + byte bReserved6E; /* 0x6E */ + byte bReserved6F; /* 0x6F */ + byte bReserved70; /* 0x70 */ + byte bReserved71; /* 0x71 */ + byte bReserved72; /* 0x72 */ + byte bReserved73; /* 0x73 */ + byte bReserved74; /* 0x74 */ + byte bReserved75; /* 0x75 */ + byte bReserved76; /* 0x76 */ + byte bReserved77; /* 0x77 */ + byte bReserved78; /* 0x78 */ + byte bReserved79; /* 0x79 */ + byte bReserved7A; /* 0x7A */ + byte bReserved7B; /* 0x7B */ + byte bReserved7C; /* 0x7C */ + byte bReserved7D; /* 0x7D */ + byte bReserved7E; /* 0x7E */ + byte bReserved7F; /* 0x7F */ +} rtcmosram_data_t __attribute__ (( packed )); + +typedef struct _rtcmosram_inparm_t { + word wFunc; + word wParm0; + dword dwParm1; +} rtcmosram_inparm_t; + +typedef struct _rtcmosram_outparm_t { + word wRtn; + word wParm0; + dword dwParm1; +} rtcmosram_outparm_t; + +typedef union _rtcmosram_ioparm_t { + rtcmosram_inparm_t in; + rtcmosram_outparm_t out; + rtcmosram_data_t data; +} rtcmosram_ioparm_t; + +/****** declarations ******/ + +int rtcmosram_do( + unsigned long ulongIoctlArg, + flag_t fCallerHasWritePerm +); + +#endif diff -urNp thinkpad/char/thinkpad/smapi.h 2.4.20pre8aa2/char/thinkpad/smapi.h --- thinkpad/char/thinkpad/smapi.h Thu Jan 1 01:00:00 1970 +++ 2.4.20pre8aa2/char/thinkpad/smapi.h Wed Oct 2 06:41:39 2002 @@ -0,0 +1,54 @@ + +/********************************************************************* + * + * Filename: smapi.h + * Description: header file for the smapi driver + * Author: Thomas Hood + * Created: 19 July 1999 + * + * Please report bugs to the author ASAP. + * + * Copyright (c) 1999 J.D. Thomas Hood, All rights reserved + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * To receive a copy of the GNU General Public License, please write + * to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA + * + ********************************************************************/ + +#ifndef __SMAPI_H__ +#define __SMAPI_H__ + +#include "smapibios.h" + + +/****** typedefs ******/ + +typedef smb_inparm_t smapi_inparm_t; +typedef smb_outparm_t smapi_outparm_t; + +typedef union _smapi_ioparm_t { + smapi_inparm_t in; + smapi_outparm_t out; +} smapi_ioparm_t; + + +/****** declarations ******/ + +int smapi_do( + unsigned long ulongIoctlArg, + flag_t fCallerHasWritePerm +); + + +#endif diff -urNp thinkpad/char/thinkpad/smapi_call.S 2.4.20pre8aa2/char/thinkpad/smapi_call.S --- thinkpad/char/thinkpad/smapi_call.S Thu Jan 1 01:00:00 1970 +++ 2.4.20pre8aa2/char/thinkpad/smapi_call.S Wed Oct 2 06:41:39 2002 @@ -0,0 +1,55 @@ + +#********************************************************************* +#* +#* Filename: smapi_call.s +#* Version: 1.0 +#* Author: Thomas Hood +#* Created: 19 July 1999 +#* +#* Please report bugs to the author ASAP. +#* +#* Copyright (c) 1999 J.D. Thomas Hood, All rights reserved +#* +#* This program is free software; you can redistribute it and/or +#* modify it under the terms of the GNU General Public License as +#* published by the Free Software Foundation; either version 2 of +#* the License, or (at your option) any later version. +#* +#* This program is distributed in the hope that it will be useful, +#* but WITHOUT ANY WARRANTY; without even the implied warranty of +#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +#* GNU General Public License for more details. +#* +#* To receive a copy of the GNU General Public License, please write +#* to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, +#* Boston, MA 02111-1307 USA +#* +#********************************************************************/ + + .align +farpxSmapiBios: # far pointer to the SMAPI function + .globl _dwAddressSmapiBios +_dwAddressSmapiBios: .long 0xc00fe9c4 # offset; should be set up by caller +wSegSmapiBios: .word 0x18 # cs is stored here by us before call + + .globl SMAPI_BIOS_do + .align +SMAPI_BIOS_do: + pushl %ebp + movl %esp,%ebp + + movl 0xC(%ebp),%eax + pushl %ds + pushl %eax + movl 0x8(%ebp),%eax + pushl %ds + pushl %eax + + movl $0,%eax + movw %cs,(wSegSmapiBios) + lcall *(farpxSmapiBios) + + add $0x10,%esp + popl %ebp + ret + diff -urNp thinkpad/char/thinkpad/smapi_call.h 2.4.20pre8aa2/char/thinkpad/smapi_call.h --- thinkpad/char/thinkpad/smapi_call.h Thu Jan 1 01:00:00 1970 +++ 2.4.20pre8aa2/char/thinkpad/smapi_call.h Wed Oct 2 06:41:39 2002 @@ -0,0 +1,36 @@ + +/********************************************************************* + * + * Filename: smapi_call.h + * Description: header file for the smapi call code + * Author: Thomas Hood + * Created: 19 July 1999 + * + * Please report bugs to the author ASAP. + * + * Copyright (c) 1999 J.D. Thomas Hood, All rights reserved + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * To receive a copy of the GNU General Public License, please write + * to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA + * + ********************************************************************/ + +#ifndef __SMAPI_CALL_H__ +#define __SMAPI_CALL_H__ + +/****** declarations ******/ +int SMAPI_BIOS_do( smapi_inparm_t * , smapi_outparm_t * ); +extern dword _dwAddressSmapiBios; + +#endif diff -urNp thinkpad/char/thinkpad/smapi_core.c 2.4.20pre8aa2/char/thinkpad/smapi_core.c --- thinkpad/char/thinkpad/smapi_core.c Thu Jan 1 01:00:00 1970 +++ 2.4.20pre8aa2/char/thinkpad/smapi_core.c Wed Oct 2 06:41:39 2002 @@ -0,0 +1,421 @@ + +/********************************************************************* + * + * Filename: smapi_core.c + * Description: smapi is a kernel module that serves to interface + * with the SMAPI BIOS in IBM ThinkPads + * Author: Thomas Hood + * Created: 19 July 1999 + * + * Please report bugs to the author ASAP. + * + * Copyright (c) 1999 J.D. Thomas Hood, All rights reserved + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * To receive a copy of the GNU General Public License, please write + * to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA + * + ********************************************************************/ + +#include "thinkpad_driver.h" + +#include +#include +#include +#include +#include +#include +#include +#include "thinkpad_common.h" +#include "smapi.h" +#include "smapi_call.h" + + +/****** definitions ******/ + + +/****** declarations ******/ + +extern struct proc_dir_entry *thinkpad_ppde; + +#ifdef CONFIG_DEVFS_FS +static int smapi_open( + struct inode * pinodeThe, + struct file * pfileThe +); +static int smapi_release( + struct inode * pinodeThe, + struct file * pfileThe +); +static int smapi_ioctl( + struct inode * pinodeThe, + struct file * pfileThe, + unsigned int uintIoctlNum, + unsigned long ulongIoctlArg +); +#endif + +/****** variables ******/ + +static const char _szMyName[] = "smapi"; +static const char _szImName[] = "smapi_do"; +static const char _szMyVersion[] = "3.1"; +static const char _szProcfile[] = "driver/thinkpad/smapi"; + +MODULE_AUTHOR( "Thomas Hood" ); +MODULE_DESCRIPTION( "Driver for the SMAPI BIOS on IBM ThinkPads" ); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,10) +MODULE_LICENSE( "GPL" ); +#endif + +#ifdef CONFIG_DEVFS_FS +static struct file_operations _fileopsSmapi = { + ioctl: smapi_ioctl, + open: smapi_open, + release: smapi_release, + owner: THIS_MODULE +}; + +static devfs_handle_t _devfs_handleSmapi; +#endif + +/****** functions *******/ + + +static flag_t smapi_req_need_w( byte bFunc, byte bSubFunc ) +{ + + switch ( bFunc ) { + case 0x00: return 0; + case 0x10: if ( bSubFunc == 0x00 ) return 0; break; + case 0x11: if ( bSubFunc == 0x02 ) return 0; break; + case 0x13: if ( bSubFunc == 0x02 ) return 0; break; + case 0x22: + if ( bSubFunc == 0x00 ) return 0; + if ( bSubFunc == 0x02 ) return 0; + break; + case 0x30: if ( bSubFunc == 0x00 ) return 0; break; + case 0x31: if ( bSubFunc == 0x00 ) return 0; break; + case 0x32: + if ( bSubFunc == 0x00 ) return 0; + if ( bSubFunc == 0x02 ) return 0; + if ( bSubFunc == 0x06 ) return 0; + break; + case 0x33: if ( bSubFunc == 0x00 ) return 0; break; + case 0x34: + if ( bSubFunc == 0x00 ) return 0; + if ( bSubFunc == 0x02 ) return 0; + break; + default: + return 1; + } + + return 1; +} + + +static byte byte_of_bcd8( bcd8_t bcd8The ) +{ + byte bTens, bUnits; + + bUnits = (byte)bcd8The & 0xF; + bTens = (byte)(bcd8The & 0xF0) >> 4; + + if ( bUnits > 9 || bTens > 9 ) { + return 0xFF; + } + + return bUnits + (bTens * 10); +} + + +static int smapi_read_proc( + char *pchBuf, + char **ppchStart, + off_t off, + int intCount, + int *pintEof, + void *data +) { + int intRtn; + bcd8_t bcd8SysMgmtHigh, bcd8SysMgmtLow; + bcd8_t bcd8SMAPIIfaceHigh, bcd8SMAPIIfaceLow; + word wSysMgmtBiosRevMajor, wSysMgmtBiosRevMinor; + word wSmapiBiosIfaceRevMajor, wSmapiBiosIfaceRevMinor; + smb_inparm_t inparmMy; + smb_outparm_t outparmMy; + + inparmMy.bFunc = (byte) 0; + inparmMy.bSubFunc = (byte) 0; + + intRtn = SMAPI_BIOS_do( &inparmMy, &outparmMy ); + if ( intRtn ) { + return snprintf( + pchBuf, intCount, + "%s module ver. %s interfacing to 32-bit protected mode system management BIOS:\n" + " error getting BIOS information\n", + _szMyName, _szMyVersion + ); + } + + bcd8SysMgmtHigh = (bcd8_t)( (outparmMy.dwParm4 >> 8) & 0xFF ); + bcd8SysMgmtLow = (bcd8_t)( outparmMy.dwParm4 & 0xFF ); + wSysMgmtBiosRevMajor = (word) byte_of_bcd8( bcd8SysMgmtHigh ); + wSysMgmtBiosRevMinor = (word) byte_of_bcd8( bcd8SysMgmtLow ); + + bcd8SMAPIIfaceHigh = (bcd8_t)( (outparmMy.dwParm5 >> 8) & 0xFF ); + bcd8SMAPIIfaceLow = (bcd8_t)( outparmMy.dwParm5 & 0xFF ); + wSmapiBiosIfaceRevMajor = (word) byte_of_bcd8( bcd8SMAPIIfaceHigh ); + wSmapiBiosIfaceRevMinor = (word) byte_of_bcd8( bcd8SMAPIIfaceLow ); + + return snprintf( + pchBuf, intCount, + "%s module ver. %s interfacing to 32-bit protected mode System-Management-API BIOS ver. %d.%d at address 0x%lx through interface version %d.%d\n", + _szMyName, _szMyVersion, + wSysMgmtBiosRevMajor, wSysMgmtBiosRevMinor, + (unsigned long) _dwAddressSmapiBios, + wSmapiBiosIfaceRevMajor, wSmapiBiosIfaceRevMinor + ); +} + +int smapi_do( + unsigned long ulongIoctlArg, + flag_t fCallerHasWritePerm +) { + smb_inparm_t inparmMy; + smb_outparm_t outparmMy; + unsigned long ulRtnCopy; + int intRtnDo; + + ulRtnCopy = copy_from_user( + &inparmMy, + (byte *)ulongIoctlArg, + sizeof( inparmMy ) + ); + if ( ulRtnCopy ) return -EFAULT; + + if ( smapi_req_need_w( inparmMy.bFunc, inparmMy.bSubFunc ) && !fCallerHasWritePerm ) { + printk(KERN_ERR + "%s: Caller does not have permission to make this request of SMAPI\n", + _szMyName + ); + return -EACCES; + } + + intRtnDo = SMAPI_BIOS_do( &inparmMy , &outparmMy ); + + if ( intRtnDo != outparmMy.bRc ) { + static unsigned char count; /* = 0 */ + if ( !count++ ) + printk(KERN_INFO "%s: SMAPI BIOS return codes differ!\n", _szMyName ); + } + + ulRtnCopy = copy_to_user( + (byte *)ulongIoctlArg, + &outparmMy, + sizeof( inparmMy ) + ); + if ( ulRtnCopy ) return -EFAULT; + + return outparmMy.bRc ? -ETHINKPAD_SUBDRIVER : 0; +} + + +#ifdef CONFIG_DEVFS_FS +static int smapi_open( + struct inode * pinodeThe, + struct file * pfileThe +) { + + return 0; +} + + +static int smapi_release( + struct inode * pinodeThe, + struct file * pfileThe +) { + + return 0; +} + + +static flag_t caller_has_w( struct file * pfileThe ) +{ + return ((pfileThe->f_mode) & FMODE_WRITE) ? 1 : 0; +} + + +static int smapi_ioctl( + struct inode * pinodeThe, + struct file * pfileThe, + unsigned int uintIoctlNum, + unsigned long ulongIoctlArg +) { + +#ifdef DEBUG_VERBOSE + printk( "%s: Doing ioctl number 0x%x\n", _szMyName, uintIoctlNum ); +#endif + + switch ( uintIoctlNum ) { + /* should return at the end of each case block */ + + case IOCTL_SMAPI_REQUEST: + return smapi_do( + ulongIoctlArg, + caller_has_w( pfileThe ) + ); + + default: + /* ioctl number not recognized -- do nothing */ + return -ENOTTY; + + } /* switch */ + + return -ETHINKPAD_PROGRAMMING; /* We should never arrive here */ +} +#endif /* defined(CONFIG_DEVFS_FS) */ + + +/* + * Returns a pointer to the first SMAPI BIOS header found + * with correct checksum + * Returns NULL if no header found with correct checksum + */ +static smb_header_t * locate_smb_header( void ) +{ + smb_header_t *pheaderSearch, *pheaderLim; + + /*** Search for the sig ***/ + pheaderSearch = (smb_header_t *) phys_to_virt(0xF0000); + pheaderLim = (smb_header_t *) phys_to_virt(0xFFFF0); + + while ( 1 ) { + + if ( + ( pheaderSearch->bSig[0] == '$') && + ( pheaderSearch->bSig[1] == 'S') && + ( pheaderSearch->bSig[2] == 'M') && + ( pheaderSearch->bSig[3] == 'B') + ) { + /* We found a signature */ + /*** check the header checksum ***/ + byte chksum; + int cnt; + + chksum = 0; + for ( cnt=0; cnt < pheaderSearch->bLen; cnt++ ) { + chksum += (byte)(pheaderSearch->bSig[cnt]); + } + if ( chksum == 0 ) /* good checksum */ + return pheaderSearch; + + /* bad checksum */ + } + + /*** Keep searching ***/ + pheaderSearch++ ; + if ( pheaderSearch > pheaderLim ) { + /* search space exhausted */ + return (smb_header_t *) NULL; + } + + } /* while */ + +} + + +static int __init smapi_init( void ) +{ + smb_header_t * pheaderFound; + + /*** locate SMAPI BIOS header ***/ + pheaderFound = locate_smb_header(); + if ( pheaderFound == NULL ) { + printk(KERN_ERR + "%s: No SMAPI BIOS header was found. :-(\n", + _szMyName + ); + return -ETHINKPAD_HW_NOT_FOUND; + } + /* a header was located */ + + if ( ! (pheaderFound->wInfo & 4) ) { + printk(KERN_ERR + "%s: The SMAPI BIOS does not support 32-bit protected mode. :-(\n", + _szMyName + ); + return -ETHINKPAD_HW_NOT_FOUND; + } + /* a header was located and it supports 32-bit protected mode */ + + _dwAddressSmapiBios = (dword) phys_to_virt( + pheaderFound->dwP32_base + + pheaderFound->dwP32_offset + ); + + printk(KERN_INFO + "%s: 32-bit protected mode SMAPI BIOS found. :-)\n", + _szMyName + ); + + if ( !thinkpad_ppde || !create_proc_read_entry( + _szProcfile, + S_IFREG | S_IRUGO, + NULL, + smapi_read_proc, + NULL + ) ) { + printk(KERN_ERR "%s: Could not create_proc_read_entry() /proc/%s\n", _szMyName, _szProcfile ); + } + /* proc entry created */ + +#ifdef CONFIG_DEVFS_FS + _devfs_handleSmapi = devfs_register( + NULL /* dir */, + "thinkpad/smapi", + DEVFS_FL_DEFAULT | DEVFS_FL_AUTO_DEVNUM, + 0 /* major */, 0 /* minor */, + S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH, + &_fileopsSmapi, + NULL /* info */ + ); + if ( _devfs_handleSmapi == NULL ) { + printk(KERN_ERR "%s: Could not devfs_register(). Aborting.\n", _szMyName ); + return -EIO; + } + /* devfs entry created */ +#endif + + inter_module_register( _szImName, THIS_MODULE, &smapi_do ); + + return 0; +} + + +static void __exit smapi_exit( void ) +{ + + inter_module_unregister( _szImName ); + +#ifdef CONFIG_DEVFS_FS + devfs_unregister( _devfs_handleSmapi ); +#endif + + remove_proc_entry( _szProcfile, NULL ); + + return; +} + +module_init(smapi_init); +module_exit(smapi_exit); diff -urNp thinkpad/char/thinkpad/smapibios.h 2.4.20pre8aa2/char/thinkpad/smapibios.h --- thinkpad/char/thinkpad/smapibios.h Thu Jan 1 01:00:00 1970 +++ 2.4.20pre8aa2/char/thinkpad/smapibios.h Wed Oct 2 06:41:39 2002 @@ -0,0 +1,93 @@ + +/********************************************************************* + * + * Filename: smapibios.h + * Description: header file for the IBM SMAPI BIOS + * Author: Thomas Hood + * Created: 14 July 1999 + * + * Please report bugs to the author ASAP. + * + * Copyright (c) 1999 J.D. Thomas Hood, All rights reserved + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * To receive a copy of the GNU General Public License, please write + * to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA + * + ********************************************************************/ + +#ifndef __SMAPIBIOS_H__ +#define __SMAPIBIOS_H__ + +/* Is included by smapi.h */ + +/*** SMAPI BIOS error codes ***/ +#define ERR_SMB_MIN ((byte)0x01) +#define ERR_SMB_FUNC_NOT_AVAIL ((byte)0x53) +#define ERR_SMB_FUNC_NOT_SUPPORTED ((byte)0x86) +#define ERR_SMB_SYSTEM_ERROR ((byte)0x90) +#define ERR_SMB_SYSTEM_INVALID ((byte)0x91) +#define ERR_SMB_SYSTEM_BUSY ((byte)0x92) +#define ERR_SMB_DEVICE_ERROR ((byte)0xA0) +#define ERR_SMB_DEVICE_BUSY ((byte)0xA1) +#define ERR_SMB_DEVICE_NOT_ATTACHED ((byte)0xA2) +#define ERR_SMB_DEVICE_DISABLED ((byte)0xA3) +#define ERR_SMB_PARM_INVALID ((byte)0x81) +#define ERR_SMB_PARM_OUT_OF_RANGE ((byte)0xA4) +#define ERR_SMB_PARM_NOT_ACCEPTED ((byte)0xA5) +#define ERR_SMB_MAX ((byte)0xFF) + +/* The following structure definitions come from the ThinkPad 560Z Technical Reference */ + +/*** SMAPI BIOS header ***/ +typedef struct _smb_header { + byte bSig[4]; /* signature */ + byte bVerMajor; /* major version */ + byte bVerMinor; /* minor version */ + byte bLen; /* length */ + byte bChksum; /* checksum */ + word wInfo; /* information word */ + word wRsv1; /* reserve 1 */ + word wR_offset; /* real mode offset */ + word wR_segment; /* real mode segment */ + word wRsv2; /* reserve 2 */ + word wP16_offset; /* 16-bit protect mode offset */ + dword dwP16_base; /* 16-bit protect mode base address */ + dword dwP32_offset; /* 32-bit protect mode offset */ + dword dwP32_base; /* 32-bit protect mode base address */ +} smb_header_t; + +/*** SMAPI BIOS call input parameters ***/ +typedef struct _smb_inparm { + byte bFunc; + byte bSubFunc; + word wParm1; + word wParm2; + word wParm3; + dword dwParm4; + dword dwParm5; +} smb_inparm_t; + + +/*** SMAPI BIOS call output parameters ***/ +typedef struct _smb_outparm { + byte bRc; + byte bSubRc; + word wParm1; + word wParm2; + word wParm3; + dword dwParm4; + dword dwParm5; +} smb_outparm_t; + +#endif diff -urNp thinkpad/char/thinkpad/superio.c 2.4.20pre8aa2/char/thinkpad/superio.c --- thinkpad/char/thinkpad/superio.c Thu Jan 1 01:00:00 1970 +++ 2.4.20pre8aa2/char/thinkpad/superio.c Wed Oct 2 06:41:39 2002 @@ -0,0 +1,1011 @@ + +/********************************************************************* + * + * Filename: superio.c + * Description: kernel module that configures the PC97338 + * Super I/O chip present in some ThinkPads + * Author: Thomas Hood + * Reference: National Semiconductor PC87338/PC97338 data sheet. November, 1998. + * Created: 19 July 1999 + * + * Please report bugs to the author ASAP. + * + * Copyright (c) 1999 J.D. Thomas Hood, All rights reserved + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * To receive a copy of the GNU General Public License, please write + * to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA + * + ********************************************************************/ + +#include "thinkpad_driver.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include "thinkpad_common.h" +#include "superio.h" + + +/****** definitions ******/ + + +/****** declarations ******/ + +extern struct proc_dir_entry *thinkpad_ppde; + +#ifdef CONFIG_DEVFS_FS +static int superio_open( + struct inode * pinodeThe, + struct file * pfileThe +); +static int superio_release( + struct inode * pinodeThe, + struct file * pfileThe +); +static int superio_ioctl( + struct inode * pinodeThe, + struct file * pfileThe, + unsigned int uintIoctlNum, + unsigned long ulongIoctlArg +); +#endif + +/****** variables ******/ +static const char _szMyName[] = "superio"; +static const char _szImName[] = "superio_do"; +static const char _szMyVersion[] = "3.0"; +static const char _szProcfile[] = "driver/thinkpad/superio"; +static word _wPortIndex, _wPortData; +static struct resource *_presourceSuperio; + +MODULE_AUTHOR( "Thomas Hood" ); +MODULE_DESCRIPTION( "Driver for the Super I/O chip on IBM ThinkPads" ); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,10) +MODULE_LICENSE( "GPL" ); +#endif + +#ifdef CONFIG_DEVFS_FS +static struct file_operations _fileopsSuperio = { + ioctl: superio_ioctl, + open: superio_open, + release: superio_release, + owner: THIS_MODULE +}; + +static devfs_handle_t _devfs_handleSuperio; +#endif + +/****** functions ******/ + +/* + * We use _p variant of outb just for safety + * getregb and putregb use the global variables + * _wPortIndex and _wPortData + */ +static byte getregb( byte bWhere ) +{ + byte bGot; + unsigned long flags; + + save_flags( flags ); cli(); + outb_p( bWhere, _wPortIndex ); + bGot = inb( _wPortData ); + restore_flags( flags ); + + return bGot; +} + + +static void putregb( byte bWhat, byte bWhere ) +{ + unsigned long flags; + + save_flags( flags ); cli(); + outb_p( bWhere, _wPortIndex ); + outb( bWhat, _wPortData ); + restore_flags( flags ); + + return; +} + + +static int get_leg_regs( superio_outparm_t *poutparmThe ) +{ + byte bTmp, bID, bRev; + + poutparmThe->dwParm1 = 0; + poutparmThe->dwParm2 = 0; + + bTmp = getregb( 8 ); /* chip ID and rev */ + bID = bTmp & ~7; + bRev = bTmp & 7; + poutparmThe->wParm0 = (((word)bID)<<8) | bRev; + + bTmp = getregb( 0 ); /* enable */ + poutparmThe->dwParm1 |= (dword)bTmp; + + bTmp = getregb( 1 ); /* address */ + poutparmThe->dwParm1 |= ((dword)bTmp) << 8; + + bTmp = getregb( 2 ); /* power and test */ + poutparmThe->dwParm1 |= ((dword)bTmp) << 16; + + bTmp = getregb( 3 ); /* function control */ + poutparmThe->dwParm1 |= ((dword)bTmp) << 24; + + bTmp = getregb( 4 ); /* printer control */ + poutparmThe->dwParm2 |= (dword)bTmp; + +#if 0 + bTmp = getregb( 5 ); /* not used */ + poutparmThe->dwParm2 |= ((dword)bTmp) << 8; +#endif + + bTmp = getregb( 6 ); /* power management */ + poutparmThe->dwParm2 |= ((dword)bTmp) << 16; + + bTmp = getregb( 7 ); /* tape, ser, par config */ + poutparmThe->dwParm2 |= ((dword)bTmp) << 24; + + return 0; +} + + +/* + * This should always be done by read-modify-write. + */ +static int set_leg_regs( superio_inparm_t *pinparmThe ) +{ + byte bTmp; + + bTmp = pinparmThe->dwParm1 & 0xFF; + putregb( bTmp, 0 ); /* enable */ + + bTmp = (pinparmThe->dwParm1 >> 8) & 0xFF; + putregb( bTmp, 1 ); /* address */ + + bTmp = (pinparmThe->dwParm1 >> 16) & 0xFF; + putregb( bTmp, 2 ); /* power and test */ + + bTmp = (pinparmThe->dwParm1 >> 24) & 0xFF; + putregb( bTmp, 3 ); /* function control */ + + bTmp = pinparmThe->dwParm2 & 0xFF; + putregb( bTmp, 4 ); /* printer control */ + +#if 0 + bTmp = (pinparmThe->dwParm2 >> 8) & 0xFF; + putregb( bTmp, 5 ); /* not used */ +#endif + + bTmp = (pinparmThe->dwParm2 >> 16) & 0xFF; + putregb( bTmp, 6 ); /* power management */ + + bTmp = (pinparmThe->dwParm2 >> 24) & 0xFF; + putregb( bTmp, 7 ); /* tape, ser, par config */ + + return 0; +} + + +static int get_pnp_regs( dword *pdwRegs ) +{ + + *pdwRegs = (dword)getregb( 0x1b ) ; + *pdwRegs |= ((dword)getregb( 0x1c )) << 8 ; + *pdwRegs |= ((dword)getregb( 0x41 )) << 16; + *pdwRegs |= ((dword)getregb( 0x4F )) << 24; + + return 0; +} + + +static flag_t is_in_pnp_mode( word wPortIndex, word wPortData ) +{ + byte bGot; + unsigned long flags; + + save_flags( flags ); cli(); + outb_p( 0x1b, wPortIndex ); + bGot = inb( wPortData ); + restore_flags( flags ); + + return (flag_t)( (bGot >> 3) & 1 ); +} + + +static byte irq_whose_pnp_code_is( byte bCode ) +{ + + switch ( bCode ) { + case 0: return 0; /* "disable" */ + case 1: return 0xFF; + case 2: return 0xFF; + case 3: return 3; + case 4: return 4; + case 5: return 5; + case 6: return 6; + case 7: return 7; + case 8: return 0xFF; /* "invalid" */ + case 9: return 9; + case 10: return 10; + case 11: return 11; + case 12: return 12; + case 13: return 0xFF; /* "invalid" */ + case 14: return 0xFF; /* "invalid" */ + case 15: return 15; + } + + return 0xfe; /* we shouldn't reach here */ +} + + +/* + * returns -EINVAL if can't encode IRQ + */ +static int int_pnp_code_for_irq( byte bIRQ ) +{ + + switch ( bIRQ ) { + case 0: return 0; /* "disable" */ + case 3: return 3; + case 4: return 4; + case 5: return 5; + case 6: return 6; + case 7: return 7; + case 9: return 9; + case 10: return 10; + case 11: return 11; + case 12: return 12; + case 15: return 15; + default: return -EINVAL; + } + + return -EINVAL; +} + + +static flag_t disable_par_tmp( void ) +{ + byte bFER; + flag_t fWasEnabled; + + /*** disable ***/ + bFER = getregb( 0 ); /* FER */ + fWasEnabled = bFER & 1; + putregb( bFER & ~1, 0 ); + + return fWasEnabled; +} + + +static flag_t disable_ser_tmp( byte bWhich ) +{ + byte bFER, bMaskFER; + flag_t fWasEnabled; + + switch ( bWhich ) { + case 1: bMaskFER=2; break; + case 2: bMaskFER=4; break; + default: bMaskFER=0; break; + } + + /*** disable ***/ + bFER = getregb( 0 ); /* FER */ + fWasEnabled = (bFER & bMaskFER) ? 1 : 0; + putregb( bFER & ~bMaskFER, 0 ); + + return fWasEnabled; +} + + +static int get_fdd_irq( byte *pbIRQ ) +{ + byte bTmp; + + bTmp = getregb( 0x41 ) & 0x0F; + + *pbIRQ = irq_whose_pnp_code_is( bTmp ); + + return 0; +} + + +static int get_fdd_base_address( word *pwAdrs) +{ + + *pwAdrs = ((word)getregb( 0x48 ) & ~1) << 2; /* low */ + *pwAdrs |= (((word)getregb( 0x49 ) & ~3) << 8); /* high */ + + return 0; +} + + +static int ablify_par( flag_t fEnable ) +{ + byte bFER; + + bFER = getregb( 0 ); /* FER */ + if ( fEnable ) + putregb( bFER | 1, 0 ); + else + putregb( bFER & ~1, 0 ); + + return 0; +} + + + +static int get_par_irq_legacymode( byte *pbIRQ ) +{ + byte bTmp; + + bTmp = getregb( 0x1b ) & 7; + switch ( bTmp ) { + case 0: *pbIRQ = 0xFF; break; + case 1: *pbIRQ = 7; break; + case 2: *pbIRQ = 9; break; + case 3: *pbIRQ = 10; break; + case 4: *pbIRQ = 11; break; + case 5: *pbIRQ = 14; break; + case 6: *pbIRQ = 15; break; + case 7: *pbIRQ = 5; break; + } + + return 0; +} + + +static int set_par_irq_legacymode( byte bIRQ ) +{ + byte bCode, bPPCR0; + flag_t fWasEnabled; + + /*** compute code ***/ + switch ( bIRQ ) { + case 7: bCode = 1; break; + case 9: bCode = 2; break; + case 10: bCode = 3; break; + case 11: bCode = 4; break; + case 14: bCode = 5; break; + case 15: bCode = 6; break; + case 5: bCode = 7; break; + default: + return -EINVAL; + } + + fWasEnabled = disable_par_tmp(); + + /*** set ***/ + bPPCR0 = getregb( 0x1b ); + putregb( (bPPCR0 & ~7) | (bCode & 7), 0x1b ); + + ablify_par( fWasEnabled ); + + return 0; +} + + +static int get_par_irq_pnpmode( byte *pbIRQ ) +{ + byte bTmp; + + bTmp = getregb( 0x1b ) >> 4; + + *pbIRQ = irq_whose_pnp_code_is( bTmp ); + + return 0; +} + + +static int set_par_irq_pnpmode( byte bIRQ ) +{ + int intCode; + byte bPPCR0, bCode; + flag_t fWasEnabled; + + /*** compute code ***/ + intCode = int_pnp_code_for_irq( bIRQ ); + if ( intCode == -EINVAL ) return -EINVAL; + bCode = (byte)intCode; + + fWasEnabled = disable_par_tmp(); + + /*** set ***/ + bPPCR0 = getregb( 0x1b ); + putregb( (bPPCR0 & 0x0F) | (bCode << 4), 0x1b ); + + ablify_par( fWasEnabled ); + + return 0; +} + + +static int get_par_base_address( word *pwAdrs) +{ + + *pwAdrs = ((word)getregb( 0x42 )) << 2; + *pwAdrs |= (((word)getregb( 0x43 ) & ~3) << 8); + + return 0; +} + + +/* + * When we write we take care not to alter the "reserved" bits + */ +static int set_par_base_address( word wAdrs ) +{ + byte bTmp; + flag_t fWasEnabled; + + fWasEnabled = disable_par_tmp(); + + /*** set ***/ + putregb( (byte)(wAdrs>>2), 0x42 ); /* low */ + + bTmp = getregb( 0x43 ) & 3; + putregb( ((byte)(wAdrs>>8)&~3) | bTmp, 0x43 ); /* high */ + + ablify_par( fWasEnabled ); + + return 0; +} + + +static int get_par_mode( superio_par_mode_t *pmode ) +{ + byte bPCR, bPTR; + + bPCR = getregb( 4 ); + bPTR = getregb( 2 ); + + if ( (bPCR & 5) == 0 && (bPTR & 0x80) == 0 ) { + *pmode = SUPERIO_PAR_MODE_COMPATIBLE; + return 0; + } else if ( (bPCR & 5) == 0 && (bPTR & 0x80) ) { + *pmode = SUPERIO_PAR_MODE_EXTENDED; + return 0; + } else if ( (bPCR & 5) == 1 && (bPTR & 0x80) == 0 && (bPCR & 2) == 0 ) { + *pmode = SUPERIO_PAR_MODE_EPP_1_7; + return 0; + } else if ( (bPCR & 5) == 1 && (bPTR & 0x80) == 0 && (bPCR & 2) ) { + *pmode = SUPERIO_PAR_MODE_EPP_1_9; + return 0; + } else if ( (bPCR & 5) == 4 ) { + *pmode = SUPERIO_PAR_MODE_ECP; + return 0; + } + + printk(KERN_INFO + "%s: Parallel port mode not recognized: PCR = 0x%x PTR = 0x%x\n", + _szMyName, + bPCR, bPTR + ); + *pmode = SUPERIO_PAR_MODE_UNRECOGNIZED; + + return 0; +} + + +static int set_par_mode( superio_par_mode_t mode ) +{ + byte bPCR, bPTR; + + bPCR = getregb( 4 ); + bPTR = getregb( 2 ); + + switch( mode ) { + case SUPERIO_PAR_MODE_COMPATIBLE: + bPCR &= ~5; + bPTR &= ~0x80; + break; + case SUPERIO_PAR_MODE_EXTENDED: + bPCR &= ~5; + bPTR |= 0x80; + break; + case SUPERIO_PAR_MODE_EPP_1_7: + bPCR &= ~4; bPCR |= 1; + bPCR &= ~2; /* EPP version 1.7 */ + bPTR &= ~0x80; + break; + case SUPERIO_PAR_MODE_EPP_1_9: + bPCR &= ~4; bPCR |= 1; + bPCR |= 2; /* EPP version 1.9 */ + bPTR &= ~0x80; + break; + case SUPERIO_PAR_MODE_ECP: + bPCR &= ~1; bPCR |= 4; + break; + case SUPERIO_PAR_MODE_UNRECOGNIZED: + return -EINVAL; + } + + putregb( bPCR, 4 ); + putregb( bPTR, 2 ); + + return 0; +} + + +static int ablify_ser( byte bWhich, flag_t fEnable ) +{ + byte bFER, bMaskFER; + + switch ( bWhich ) { + case 1: bMaskFER=2; break; + case 2: bMaskFER=4; break; + default: + return -EINVAL; + } + + bFER = getregb( 0 ); /* FER */ + if ( fEnable ) + putregb( (bFER | bMaskFER), 0 ); + else + putregb( (bFER & ~bMaskFER), 0 ); + + return 0; +} + + +static int get_ser_irq( byte bWhich, byte *pbIRQ ) +{ + byte bTmp, bCode; + + bTmp = getregb( 0x1c ); + + switch ( bWhich ) { + case 1: bCode = bTmp & 0xF; break; + case 2: bCode = bTmp >> 4; break; + default: + return -EINVAL; + } + + *pbIRQ = irq_whose_pnp_code_is( bCode ); + + return 0; +} + + +static int set_ser_irq( byte bWhich, byte bIRQ ) +{ + int intCode; + byte bPPCR1, bCode; + flag_t fWasEnabled; + + intCode = int_pnp_code_for_irq( bIRQ ); + if ( intCode == -EINVAL ) return -EINVAL; + bCode = (byte)intCode; + + fWasEnabled = disable_ser_tmp( bWhich ); + + /*** set ***/ + bPPCR1 = getregb( 0x1c ); + switch( bWhich ) { + case 1: putregb( (bPPCR1 & 0xF0) | bCode, 0x1c ); break; + case 2: putregb( (bPPCR1 & 0x0F) | (bCode << 4), 0x1c ); break; + default: + return -EINVAL; + } + + ablify_ser( bWhich, fWasEnabled ); + + return 0; +} + + +static int get_ser_base_address( + byte bWhich, + word *pwAdrs +) { + byte bIndexL, bIndexH; + + switch ( bWhich ) { + case 1: bIndexL = 0x44; bIndexH = 0x45; break; + case 2: bIndexL = 0x46; bIndexH = 0x47; break; + default: + return -EINVAL; + } + + *pwAdrs = ((word)getregb( bIndexL ) & ~1) << 2; + *pwAdrs |= (((word)getregb( bIndexH ) & ~3) << 8); + + return 0; +} + + +/* + * When we write we take care not to alter the "reserved" bits + */ +static int set_ser_base_address( + byte bWhich, + word wAdrs +) { + byte bIndexL, bIndexH, bTmp; + flag_t fWasEnabled; + + switch ( bWhich ) { + case 1: bIndexL = 0x44; bIndexH = 0x45; break; + case 2: bIndexL = 0x46; bIndexH = 0x47; break; + default: + return -EINVAL; + } + + fWasEnabled = disable_ser_tmp( bWhich ); + + /*** set ***/ + bTmp = getregb( bIndexL ) & 1; + putregb( ((byte)(wAdrs>>2)&~1) | bTmp, bIndexL ); + + bTmp = getregb( bIndexH ) & 3; + putregb( ((byte)(wAdrs>>8)&~3) | bTmp, bIndexH ); + + ablify_ser( bWhich, fWasEnabled ); + + return 0; +} + + +static int superio_read_proc( + char *pchBuf, + char **ppchStart, + off_t off, + int intCount, + int *pintEof, + void *data +) { + return snprintf( + pchBuf, intCount, + "%s version %s controlling Super I/O chip at ioports 0x%x, 0x%x\n", + _szMyName, _szMyVersion, + _wPortIndex, _wPortData + ); +} + +static int superio_do_func( + superio_inparm_t *pinparmThe, + superio_outparm_t *poutparmThe, + flag_t fHasWritePerm +) { + + switch ( pinparmThe->wFunc ) { + case SUPERIO_FUNC_LEG_REGS_GET: + return get_leg_regs( poutparmThe ); + case SUPERIO_FUNC_LEG_REGS_SET: + if ( !fHasWritePerm ) return -EACCES; + return set_leg_regs( pinparmThe ); + case SUPERIO_FUNC_PNP_REGS_GET: + return get_pnp_regs( &(poutparmThe->dwParm1) ); + case SUPERIO_FUNC_FDD_IRQ_GET: + return get_fdd_irq( (byte *)&(poutparmThe->dwParm1) ); + case SUPERIO_FUNC_FDD_BASE_GET: + return get_fdd_base_address( (word *)&(poutparmThe->dwParm1) ); + case SUPERIO_FUNC_PAR_IRQ_GET: + if ( is_in_pnp_mode( _wPortIndex, _wPortData ) ) { + return get_par_irq_pnpmode( (byte *)&(poutparmThe->dwParm1) ); + } else { + printk(KERN_INFO + "%s: Super I/O chip is in legacy mode!\n", + _szMyName + ); + return get_par_irq_legacymode( (byte *)&(poutparmThe->dwParm1) ); + } + case SUPERIO_FUNC_PAR_IRQ_SET: + if ( !fHasWritePerm ) return -EACCES; + set_par_irq_legacymode( (byte)(pinparmThe->dwParm1) ); + return set_par_irq_pnpmode( (byte)(pinparmThe->dwParm1) ); + case SUPERIO_FUNC_PAR_BASE_GET: + return get_par_base_address( (word *)&(poutparmThe->dwParm1) ); + case SUPERIO_FUNC_PAR_BASE_SET: + if ( !fHasWritePerm ) return -EACCES; + return set_par_base_address( (word)(pinparmThe->dwParm1) ); + case SUPERIO_FUNC_PAR_MODE_GET: + return get_par_mode( (superio_par_mode_t *)&(poutparmThe->dwParm1) ); + case SUPERIO_FUNC_PAR_MODE_SET: + if ( !fHasWritePerm ) return -EACCES; + return set_par_mode( (superio_par_mode_t)(pinparmThe->dwParm1) ); + + case SUPERIO_FUNC_PAR_ABLIFY: + if ( !fHasWritePerm ) return -EACCES; + return ablify_par( (flag_t)(pinparmThe->dwParm1) ); + case SUPERIO_FUNC_SER_IRQ_GET: + return get_ser_irq( (byte)pinparmThe->wParm0, (byte *)&(poutparmThe->dwParm1) ); + case SUPERIO_FUNC_SER_IRQ_SET: + if ( !fHasWritePerm ) return -EACCES; + return set_ser_irq( (byte)pinparmThe->wParm0, (byte)(pinparmThe->dwParm1) ); + case SUPERIO_FUNC_SER_BASE_GET: + return get_ser_base_address( pinparmThe->wParm0, (word *)&(poutparmThe->dwParm1) ); + case SUPERIO_FUNC_SER_BASE_SET: + if ( !fHasWritePerm ) return -EACCES; + return set_ser_base_address( pinparmThe->wParm0, (word)(pinparmThe->dwParm1) ); + case SUPERIO_FUNC_SER_ABLIFY: + if ( !fHasWritePerm ) return -EACCES; + return ablify_ser( pinparmThe->wParm0, (flag_t)(pinparmThe->dwParm1) ); + default: + return -EINVAL; + } +} + + +int superio_do( + unsigned long ulongIoctlArg, + flag_t fCallerHasWritePerm +) { + superio_inparm_t inparmThe; + superio_outparm_t outparmThe; + unsigned long ulRtnCopy; + int intRtnDo; + + ulRtnCopy = copy_from_user( + &inparmThe, + (byte *)&(((superio_ioparm_t *)ulongIoctlArg)->in), + sizeof( inparmThe ) + ); + if ( ulRtnCopy ) return -EFAULT; + + intRtnDo = superio_do_func( &inparmThe, &outparmThe, fCallerHasWritePerm ); + + if ( intRtnDo == -EACCES ) { + printk(KERN_ERR + "%s: caller does not have permission to do this to the Super IO device\n", + _szMyName + ); + return intRtnDo; + } + + ulRtnCopy = copy_to_user( + (byte *)&(((superio_ioparm_t *)ulongIoctlArg)->out), + &outparmThe, + sizeof( outparmThe ) + ); + if ( ulRtnCopy ) return -EFAULT; + + return intRtnDo; /* Should be either 0 or -EACCES or -EINVAL */ +} + +#ifdef CONFIG_DEVFS_FS +static int superio_open( + struct inode * pinodeThe, + struct file * pfileThe +) { + + return 0; +} + + +static int superio_release( + struct inode * pinodeThe, + struct file * pfileThe +) { + + return 0; +} + + +static flag_t caller_has_w( struct file * pfileThe ) +{ + return ((pfileThe->f_mode) & FMODE_WRITE) ? 1 : 0; +} + + +static int superio_ioctl( + struct inode * pinodeThe, + struct file * pfileThe, + unsigned int uintIoctlNum, + unsigned long ulongIoctlArg +) { + +#ifdef DEBUG_VERBOSE + printk( "%s: Doing ioctl number 0x%x\n", _szMyName, uintIoctlNum ); +#endif + + switch ( uintIoctlNum ) { + /* should return at the end of each case block */ + + case IOCTL_SUPERIO_REQUEST: + return superio_do( + ulongIoctlArg, + caller_has_w( pfileThe ) + ); + + default: + /* ioctl number not recognized -- do nothing */ + return -ENOTTY; + + } /* switch */ + + return -ETHINKPAD_PROGRAMMING; /* We should never arrive here */ +} +#endif /* defined(CONFIG_DEVFS_FS) */ + + +/* + * We write to nonsense port 0x80 in order to + * protect against false positives due to + * ISA bus float + */ +static flag_t a_super_io_chip_appears_to_be_at( word wPort ) +{ + byte bSave, bID; + unsigned long flags; + + save_flags( flags ); cli(); + + bSave = inb( wPort ); + + /*** Check for a register ***/ + outb( 0x0a, wPort ); + outb( ~0x0a, 0x080 ); + if ( inb( wPort ) != 0x0a ) { goto No; } + outb( 0x11, wPort ); + outb( ~0x11, 0x080 ); + if ( inb( wPort ) != 0x11 ) { goto No; } + outb( 0x44, wPort ); + outb( ~0x44, 0x080 ); + if ( inb( wPort ) != 0x44 ) { goto No; } + + /* There's a register */ + + /*** Check for chip ID ***/ + outb( 0x08, wPort ); + bID = inb( wPort + 1 ); + if ( (bID & ~3) != 0xb0 ) { goto No; } + +/* Yes: */ + /* No need to restore index port's contents */ + restore_flags( flags ); + return 1; + +No: + outb( bSave, wPort ); /* restore the port's contents */ + restore_flags( flags ); + return 0; +} + + +static word locate_chip( void ) +{ + + if ( a_super_io_chip_appears_to_be_at( 0x26e ) ) return 0x26e; + if ( a_super_io_chip_appears_to_be_at( 0x2e ) ) return 0x2e; + return 0; +} + + +static flag_t see_index_ID( word wPort ) +{ + if ( inb( wPort ) == 0x88 ) if ( inb( wPort ) == 0 ) return 1; + return 0; +} + + +static int __init superio_init( void ) +{ + word wPortBase; + flag_t fVirgin; + + fVirgin = see_index_ID( 0x2e ); + + wPortBase = locate_chip(); + + if ( wPortBase == 0 ) { + printk(KERN_ERR + "%s: Super I/O chip not found. :-(\n", + _szMyName + ); + return -ETHINKPAD_HW_NOT_FOUND; + } + + /* chip found at wPortBase */ + + if ( !is_in_pnp_mode( wPortBase, wPortBase+1 ) ) { + printk(KERN_ERR + "%s: Super I/O chip found at port base 0x%x is not in plug-n-play mode. :-(\n", + _szMyName, wPortBase + ); + return -ETHINKPAD_HW_NOT_FOUND; + } + + printk(KERN_INFO + "%s: Super I/O chip (%svirgin) %sin plug-n-play mode found at port base 0x%x. :-)\n", + _szMyName, + fVirgin ? "" : "non-", + is_in_pnp_mode( wPortBase, wPortBase+1 ) ? "" : "not ", + wPortBase + ); + + /* At this point we assume we have found a working chip at wPortBase */ + + /*** request the io ports ***/ + _presourceSuperio = request_region( wPortBase, 2, "superio" ); + if ( _presourceSuperio == NULL ) { +/* + * The region is claimed by the programmable interrupt controller "pic1" + * as part of the range 0x20--0x3f. + */ +#if 0 + printk(KERN_ERR + "%s: I/O ports for Super I/O chip not available -- aborting.\n", + _szMyName + ); + return -ETHINKPAD_HW_NOT_FOUND; +#else + printk(KERN_INFO + "%s: I/O ports for Super I/O chip not available, but ignoring this.\n", + _szMyName + ); +#endif + } + + _wPortIndex = wPortBase; + _wPortData = wPortBase + 1; + + if ( !thinkpad_ppde || !create_proc_read_entry( + _szProcfile, + S_IFREG | S_IRUGO, + NULL, + superio_read_proc, + NULL + ) ) { + printk(KERN_ERR "%s: Could not create_proc_read_entry() /proc/%s\n", _szMyName, _szProcfile ); + } + /* proc entry created */ + +#ifdef CONFIG_DEVFS_FS + _devfs_handleSuperio = devfs_register( + NULL /* dir */, + "thinkpad/superio", + DEVFS_FL_DEFAULT | DEVFS_FL_AUTO_DEVNUM, + 0 /* major */, 0 /* minor */, + S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH, + &_fileopsSuperio, + NULL /* info */ + ); + if ( _devfs_handleSuperio == NULL ) { + printk(KERN_ERR "%s: Could not devfs_register(). Aborting.\n", _szMyName ); + return -EIO; + } + /* devfs entry created */ +#endif + + inter_module_register( _szImName, THIS_MODULE, &superio_do ); + + return 0; +} + + +static void __exit superio_exit( void ) +{ + + inter_module_unregister( _szImName ); + +#ifdef CONFIG_DEVFS_FS + devfs_unregister( _devfs_handleSuperio ); +#endif + + remove_proc_entry( _szProcfile, NULL ); + + if ( _presourceSuperio != NULL ) release_resource( _presourceSuperio ); + + return; +} + +module_init(superio_init); +module_exit(superio_exit); diff -urNp thinkpad/char/thinkpad/superio.h 2.4.20pre8aa2/char/thinkpad/superio.h --- thinkpad/char/thinkpad/superio.h Thu Jan 1 01:00:00 1970 +++ 2.4.20pre8aa2/char/thinkpad/superio.h Wed Oct 2 06:41:39 2002 @@ -0,0 +1,92 @@ + +/********************************************************************* + * + * Filename: superio.h + * Description: header file for the superio driver + * Author: Thomas Hood + * Created: 19 July 1999 + * + * Please report bugs to the author ASAP. + * + * Copyright (c) 1999 J.D. Thomas Hood, All rights reserved + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * To receive a copy of the GNU General Public License, please write + * to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA + * + ********************************************************************/ + +#ifndef __SUPERIO_H__ +#define __SUPERIO_H__ + +/****** defines ******/ + +#define SUPERIO_FUNC_LEG_REGS_GET ((word)0x100) +#define SUPERIO_FUNC_LEG_REGS_SET ((word)0x101) +#define SUPERIO_FUNC_PNP_REGS_GET ((word)0x200) +#define SUPERIO_FUNC_FDD_IRQ_GET ((word)0x310) +#define SUPERIO_FUNC_FDD_BASE_GET ((word)0x320) +#define SUPERIO_FUNC_PAR_ABLIFY ((word)0x400) +#define SUPERIO_FUNC_PAR_IRQ_GET ((word)0x413) +#define SUPERIO_FUNC_PAR_IRQ_SET ((word)0x411) +#define SUPERIO_FUNC_PAR_BASE_GET ((word)0x420) +#define SUPERIO_FUNC_PAR_BASE_SET ((word)0x421) +#define SUPERIO_FUNC_PAR_MODE_GET ((word)0x430) +#define SUPERIO_FUNC_PAR_MODE_SET ((word)0x431) +#define SUPERIO_FUNC_SER_ABLIFY ((word)0x500) +#define SUPERIO_FUNC_SER_IRQ_GET ((word)0x510) +#define SUPERIO_FUNC_SER_IRQ_SET ((word)0x511) +#define SUPERIO_FUNC_SER_BASE_GET ((word)0x520) +#define SUPERIO_FUNC_SER_BASE_SET ((word)0x521) + +/****** typedefs ******/ + +/*** superio module input parameters ***/ +typedef struct _superio_inparm { + word wFunc; + word wParm0; + dword dwParm1; + dword dwParm2; +} superio_inparm_t; + +/*** superio module output parameters ***/ +typedef struct _superio_outparm { + word wRc; + word wParm0; + dword dwParm1; + dword dwParm2; +} superio_outparm_t; + +typedef union _superio_ioparm_t { + superio_inparm_t in; + superio_inparm_t out; +} superio_ioparm_t; + +typedef enum _superio_par_mode { + SUPERIO_PAR_MODE_COMPATIBLE=0, + SUPERIO_PAR_MODE_EXTENDED, + SUPERIO_PAR_MODE_EPP_1_7, + SUPERIO_PAR_MODE_EPP_1_9, + SUPERIO_PAR_MODE_ECP, + SUPERIO_PAR_MODE_UNRECOGNIZED +} superio_par_mode_t; + +/****** declarations ******/ + +int superio_do( + unsigned long ulongIoctlArg, + flag_t fCallerHasWritePerm +); + + +#endif diff -urNp thinkpad/char/thinkpad/thinkpad.c 2.4.20pre8aa2/char/thinkpad/thinkpad.c --- thinkpad/char/thinkpad/thinkpad.c Thu Jan 1 01:00:00 1970 +++ 2.4.20pre8aa2/char/thinkpad/thinkpad.c Wed Oct 2 06:41:39 2002 @@ -0,0 +1,420 @@ + +/********************************************************************* + * + * Filename: thinkpad.c + * Description: loadable kernel module that serves as a router of ioctl + * requests to other modules that control various hardware + * features of IBM ThinkPads + * Author: Thomas Hood + * Created: 19 July 1999 + * + * Notes: This driver exists so that several thinkpad devices can be + * driven with only a single permanent misc device minor number + * allocated. With the advent of devfs, such tricks are no longer + * necessary. The elegant thing to do, under devfs, would be + * for each driver to have its own device file under /dev/thinkpad. + * However, the present scheme continues to work under devfs and + * will not be changed unless there is a pressing need, since it + * would involve substantial changes both to the drivers and to + * the tpctl program that uses them. + * + * Please report bugs to the author ASAP. + * + * Copyright (c) 1999 J.D. Thomas Hood, All rights reserved + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * To receive a copy of the GNU General Public License, please write + * to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA + * + ********************************************************************/ + +#include "thinkpad_driver.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "thinkpad_common.h" +#include "thinkpad.h" +#include "smapi.h" +#include "superio.h" +#include "rtcmosram.h" +#include "thinkpadpm.h" + +/****** definitions ******/ + +#define MINOR_THINKPAD 170 + +/****** forward declarations ******/ +static int thinkpad_open( + struct inode * pinodeThe, + struct file * pfileThe +); +static int thinkpad_release( + struct inode * pinodeThe, + struct file * pfileThe +); +static int thinkpad_ioctl( + struct inode * pinodeThe, + struct file * pfileThe, + unsigned int uintIoctlNum, + unsigned long ulongIoctlArg +); + +typedef enum _mod_t { + MOD_SMAPI, + MOD_SUPERIO, + MOD_RTCMOSRAM, + MOD_THINKPADPM +} mod_t; + +/* pointer to an executable "do" function returning an integer */ +typedef int (* pxint_do_t)( unsigned long, flag_t ); + +/****** variables ******/ + +/*** global ***/ +struct proc_dir_entry *thinkpad_ppde; + +/*** module parameters ***/ +static int enable_smapi = 1; +static int enable_superio = 1; +static int enable_rtcmosram = 1; +static int enable_thinkpadpm = 1; +MODULE_PARM( enable_smapi, "i" ); +MODULE_PARM( enable_superio, "i" ); +MODULE_PARM( enable_rtcmosram, "i" ); +MODULE_PARM( enable_thinkpadpm, "i" ); +MODULE_AUTHOR( "Thomas Hood" ); +MODULE_DESCRIPTION( "Metadriver for IBM ThinkPad hardware drivers" ); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,10) +MODULE_LICENSE( "GPL" ); +#endif + +/*** local ***/ +static const char _szMyName[] = "thinkpad"; +static const char _szMyVersion[] = "3.0"; +static const char _szSmapiName[] = "smapi"; +static const char _szSuperioName[] = "superio"; +static const char _szRtcmosramName[] = "rtcmosram"; +static const char _szThinkpadpmName[] = "thinkpadpm"; +static flag_t _fInUse = 1; + +static struct file_operations _fileopsThinkpad = { + ioctl: thinkpad_ioctl, + open: thinkpad_open, + release: thinkpad_release, + owner: THIS_MODULE +}; + +#ifdef CONFIG_DEVFS_FS +static devfs_handle_t _devfs_handleThinkpadDir; +static devfs_handle_t _devfs_handleThinkpadDev; +#endif + + +/****** functions ******/ + +static int thinkpad_read_proc( + char *pchBuf, + char **ppchStart, + off_t off, + int intCount, + int *pintEof, + void *pdata +) { + return snprintf( + pchBuf, intCount, + "%s version %s enabled to access modules: %s %s %s %s.\n", + _szMyName, _szMyVersion, + enable_smapi ? _szSmapiName : "", + enable_superio ? _szSuperioName : "", + enable_rtcmosram ? _szRtcmosramName : "", + enable_thinkpadpm ? _szThinkpadpmName : "" + ); +} + +static int thinkpad_open( + struct inode * pinodeThe, + struct file * pfileThe +) { + + if ( _fInUse ) return -EBUSY; + + _fInUse = 1; + + return 0; +} + + +static int thinkpad_release( + struct inode * pinodeThe, + struct file * pfileThe +) { + + _fInUse = 0; + + return 0; +} + + +static flag_t caller_has_w( struct file * pfileThe ) +{ + return ((pfileThe->f_mode) & FMODE_WRITE) ? 1 : 0; +} + + +static int thinkpad_ioctl( + struct inode * pinodeThe, + struct file * pfileThe, + unsigned int uintIoctlNum, + unsigned long ulongIoctlArg +) { + unsigned long ulRtnCopy; + +#ifdef DEBUG_VERBOSE + printk( "%s: Doing ioctl number 0x%x\n", _szMyName, uintIoctlNum ); +#endif + + switch ( uintIoctlNum ) { + /* should return at the end of each case block */ + + case IOCTL_THINKPAD_GETVER: + ulRtnCopy = copy_to_user( + (byte *)ulongIoctlArg, + _szMyVersion, + strlen( _szMyVersion ) + 1 + ); + if ( ulRtnCopy ) return -EFAULT; + return 0; + + case IOCTL_THINKPAD_ENABLE: + case IOCTL_THINKPAD_DISABLE: { + long lRes; + char szBuf[LEN_NAME_MAX+1]; + flag_t fEnable; + + fEnable = ( uintIoctlNum == IOCTL_THINKPAD_ENABLE ) ? 1 : 0; + + if ( !caller_has_w( pfileThe ) ) return -EACCES; + + lRes = strncpy_from_user( + szBuf, + (char *)ulongIoctlArg, + LEN_NAME_MAX + ); + szBuf[LEN_NAME_MAX] = '\0'; /* ensure termination */ + + printk(KERN_INFO + "%s: %sabling %s\n", _szMyName, fEnable?"En":"Dis", szBuf + ); + + if ( strnicmp( szBuf, _szSmapiName, LEN_NAME_MAX ) == 0 ) { + enable_smapi = fEnable; return 0; + } else if ( strnicmp( szBuf, _szSuperioName, LEN_NAME_MAX ) == 0 ) { + enable_superio = fEnable; return 0; + } else if ( strnicmp( szBuf, _szRtcmosramName, LEN_NAME_MAX ) == 0 ) { + enable_rtcmosram = fEnable; return 0; + } else if ( strnicmp( szBuf, _szThinkpadpmName, LEN_NAME_MAX ) == 0 ) { + enable_thinkpadpm = fEnable; return 0; + } + return -EINVAL; + } + + case IOCTL_SMAPI_REQUEST: { + pxint_do_t pxint_doSmapi; + int intRet; + if ( ! enable_smapi ) return -ETHINKPAD_MODULE_DISABLED; + pxint_doSmapi = (pxint_do_t)inter_module_get_request( "smapi_do" , _szSmapiName ); + if ( pxint_doSmapi == NULL ) return -ETHINKPAD_MODULE_NOT_FOUND; + intRet = (*pxint_doSmapi)( + ulongIoctlArg, + caller_has_w( pfileThe ) + ); + inter_module_put("smapi_do"); + if ( intRet > 0 ) intRet = -ETHINKPAD_PROGRAMMING; + return intRet; + } + + case IOCTL_SUPERIO_REQUEST: { + pxint_do_t pxint_doSuperio; + int intRet; + if ( ! enable_superio ) return -ETHINKPAD_MODULE_DISABLED; + pxint_doSuperio = (pxint_do_t)inter_module_get_request( "superio_do" , _szSuperioName ); + if ( pxint_doSuperio == NULL ) return -ETHINKPAD_MODULE_NOT_FOUND; + intRet = (*pxint_doSuperio)( + ulongIoctlArg, + caller_has_w( pfileThe ) + ); + inter_module_put("superio_do"); + if ( intRet > 0 ) intRet = -ETHINKPAD_PROGRAMMING; + return intRet; + } + + case IOCTL_RTCMOSRAM_REQUEST: { + pxint_do_t pxint_doRtcmosram; + int intRet; + if ( ! enable_rtcmosram ) return -ETHINKPAD_MODULE_DISABLED; + pxint_doRtcmosram = (pxint_do_t)inter_module_get_request( "rtcmosram_do" , _szRtcmosramName ); + if ( pxint_doRtcmosram == NULL ) return -ETHINKPAD_MODULE_NOT_FOUND; + intRet = (*pxint_doRtcmosram)( + ulongIoctlArg, + caller_has_w( pfileThe ) + ); + inter_module_put("rtcmosram_do"); + if ( intRet > 0 ) intRet = -ETHINKPAD_PROGRAMMING; + return intRet; + } + + case IOCTL_THINKPADPM_REQUEST: { + pxint_do_t pxint_doThinkpadpm; + int intRet; + if ( ! enable_thinkpadpm ) return -ETHINKPAD_MODULE_DISABLED; + pxint_doThinkpadpm = (pxint_do_t)inter_module_get_request( "thinkpadpm_do" , _szThinkpadpmName ); + if ( pxint_doThinkpadpm == NULL ) return -ETHINKPAD_MODULE_NOT_FOUND; + intRet = (*pxint_doThinkpadpm)( + ulongIoctlArg, + caller_has_w( pfileThe ) + ); + inter_module_put("thinkpadpm_do"); + if ( intRet > 0 ) intRet = -ETHINKPAD_PROGRAMMING; + return intRet; + } + + default: + /* ioctl number not recognized -- do nothing */ + return -ENOTTY; + + } /* switch */ + + return -ETHINKPAD_PROGRAMMING; /* We should never arrive here */ +} + + +#ifndef CONFIG_DEVFS_FS +static struct miscdevice _structmiscdeviceThinkpad = { + MINOR_THINKPAD, + "thinkpad", + &_fileopsThinkpad +}; +#endif + +static int __init thinkpad_init( void ) +{ +#ifdef CONFIG_DEVFS_FS + _devfs_handleThinkpadDir = devfs_mk_dir( + NULL, /* dir */ + "thinkpad", + NULL /* info */ + ); + if ( _devfs_handleThinkpadDir == NULL ) { + printk(KERN_ERR + "%s: Could not devfs_mkdir(). Aborting.\n", + _szMyName + ); + return -EIO; + } + + _devfs_handleThinkpadDev = devfs_register( + _devfs_handleThinkpadDir, + "thinkpad", + DEVFS_FL_DEFAULT, + 10 /* major */, 170 /* minor */, + S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH, + &_fileopsThinkpad, + NULL /* info */ + ); + if ( _devfs_handleThinkpadDev == NULL ) { + printk(KERN_ERR + "%s: Could not devfs_register(). Aborting.\n", + _szMyName + ); + devfs_unregister( _devfs_handleThinkpadDir ); + return -EIO; + } + /* dev entry created */ +#else + int intRtnMiscRegister; + + intRtnMiscRegister = misc_register( &_structmiscdeviceThinkpad ); + if ( intRtnMiscRegister ) { + if ( intRtnMiscRegister == -EBUSY ) { + printk(KERN_ERR + "%s: Error %d was returned by misc_register(): device is busy\n", + _szMyName, intRtnMiscRegister + ); + } else { + printk(KERN_ERR + "%s: Error %d was returned by misc_register()\n", + _szMyName, intRtnMiscRegister + ); + } + return intRtnMiscRegister; + } +#endif /* ifdef CONFIG_DEVFS_FS */ + + /* this module has been registered successfully */ + + printk(KERN_INFO + "%s: I have registered to handle major: %d minor: %d.\n", + _szMyName, 10, MINOR_THINKPAD + ); + + if ( (thinkpad_ppde = proc_mkdir( "driver/thinkpad", NULL )) == NULL ) { + printk(KERN_ERR "%s: Could not proc_mkdir() /proc/driver/thinkpad/\n", _szMyName ); + } else { /* /proc/thinkpad was created. */ + if ( !create_proc_read_entry( "driver/thinkpad/thinkpad", S_IFREG | S_IRUGO, NULL, thinkpad_read_proc, NULL )) { + printk(KERN_ERR "%s: Could not create_proc_read_entry() /proc/driver/thinkpad/thinkpad\n", _szMyName ); + } + } + /* proc entries created */ + + _fInUse = 0; + + return 0; +} + + +static void __exit thinkpad_exit( void ) +{ + + remove_proc_entry( "driver/thinkpad/thinkpad", NULL ); + remove_proc_entry( "driver/thinkpad", NULL ); + +#ifndef CONFIG_DEVFS_FS + { + int intRtn; + + intRtn = misc_deregister( &_structmiscdeviceThinkpad ); + if ( intRtn != 0 ) printk(KERN_ERR "%s: Error reported by misc_deregister: %d\n", _szMyName, intRtn ); + } +#else + devfs_unregister( _devfs_handleThinkpadDev ); + devfs_unregister( _devfs_handleThinkpadDir ); +#endif + + printk(KERN_INFO + "%s: I have cleaned up.\n", + _szMyName + ); + + return; +} + +module_init(thinkpad_init); +module_exit(thinkpad_exit); diff -urNp thinkpad/char/thinkpad/thinkpad.h 2.4.20pre8aa2/char/thinkpad/thinkpad.h --- thinkpad/char/thinkpad/thinkpad.h Thu Jan 1 01:00:00 1970 +++ 2.4.20pre8aa2/char/thinkpad/thinkpad.h Wed Oct 2 06:41:39 2002 @@ -0,0 +1,39 @@ + +/********************************************************************* + * + * Filename: thinkpad.h + * Description: header file for the thinkpad driver + * Author: Thomas Hood + * Created: 19 July 1999 + * + * Please report bugs to the author ASAP. + * + * Copyright (c) 1999 J.D. Thomas Hood, All rights reserved + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * To receive a copy of the GNU General Public License, please write + * to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA + * + ********************************************************************/ + +#ifndef __THINKPAD_H__ +#define __THINKPAD_H__ + +/*** thinkpad module input/output parameters ***/ +typedef union _thinkpad_ioparm { + char szVersion[ LEN_VERSION_MAX+1 ]; + char szName[ LEN_NAME_MAX+1 ]; +} thinkpad_ioparm_t; + +#endif /* THINKPAD_H */ + diff -urNp thinkpad/char/thinkpad/thinkpad_common.h 2.4.20pre8aa2/char/thinkpad/thinkpad_common.h --- thinkpad/char/thinkpad/thinkpad_common.h Thu Jan 1 01:00:00 1970 +++ 2.4.20pre8aa2/char/thinkpad/thinkpad_common.h Wed Oct 2 06:41:39 2002 @@ -0,0 +1,124 @@ + +/********************************************************************* + * + * Filename: thinkpad_common.h + * Description: stuff required by the "thinkpad" drivers and + * by programs accessing them + * Author: Thomas Hood + * Created: 19 July 1999 + * + * Please report bugs to the author ASAP. + * + * Copyright (c) 1999 J.D. Thomas Hood, All rights reserved + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * To receive a copy of the GNU General Public License, please write + * to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA + * + ********************************************************************/ + +#ifndef __THINKPAD_COMMON_H__ +#define __THINKPAD_COMMON_H__ + +/* All module (etc.) names should be no longer than this: */ +#define LEN_NAME_MAX 80 + +/* All version strings should be no longer than this: */ +#define LEN_VERSION_MAX 30 + +/****** macros ******/ + +#ifdef DEBUG_IOPARM +#define DEBUG_PRINT_OUTPARMS( ioparmThe ) { \ + printf( "bRc: 0x%x\n", ioparmThe.out.bRc ); \ + printf( "bSubRc: 0x%x\n", ioparmThe.out.bSubRc ); \ + printf( "wParm1: 0x%x\n", ioparmThe.out.wParm1 ); \ + printf( "wParm2: 0x%x\n", ioparmThe.out.wParm2 ); \ + printf( "wParm3: 0x%x\n", ioparmThe.out.wParm3 ); \ + printf( "dwParm4: 0x%lx\n", (unsigned long) ioparmThe.out.dwParm4 ); \ + printf( "dwParm5: 0x%lx\n", (unsigned long) ioparmThe.out.dwParm5 ); \ +} +#define DEBUG_PRINT_INPARMS( ioparmThe ) { \ + printf( "bFunc: 0x%x\n", ioparmThe.in.bFunc ); \ + printf( "bSubFunc: 0x%x\n", ioparmThe.in.bSubFunc ); \ + printf( "wParm1: 0x%x\n", ioparmThe.in.wParm1 ); \ + printf( "wParm2: 0x%x\n", ioparmThe.in.wParm2 ); \ + printf( "wParm3: 0x%x\n", ioparmThe.in.wParm3 ); \ + printf( "dwParm4: 0x%lx\n", (unsigned long) ioparmThe.in.dwParm4 ); \ + printf( "dwParm5: 0x%lx\n", (unsigned long) ioparmThe.in.dwParm5 ); \ +} +#else +#define DEBUG_PRINT_OUTPARMS( ioparmThe ) +#define DEBUG_PRINT_INPARMS( ioparmThe ) +#endif + + +/****** types ******/ + +typedef __u8 byte; +typedef __u16 word; +typedef __u32 dword; +typedef char flag_t; +typedef byte bcd8_t; + + +/*** ioctl commands ***/ + +#include "thinkpad.h" +#include "smapi.h" +#include "superio.h" +#include "rtcmosram.h" +#include "thinkpadpm.h" + +#define MAGIC_THINKPAD_IOCTL ('(') +#define IOCTL_THINKPAD_GETVER _IOR (MAGIC_THINKPAD_IOCTL,0x1,thinkpad_ioparm_t) +#define IOCTL_THINKPAD_ENABLE _IOWR(MAGIC_THINKPAD_IOCTL,0x2,thinkpad_ioparm_t) +#define IOCTL_THINKPAD_DISABLE _IOWR(MAGIC_THINKPAD_IOCTL,0x3,thinkpad_ioparm_t) +#define IOCTL_SMAPI_REQUEST _IOWR(MAGIC_THINKPAD_IOCTL,0x10,smapi_ioparm_t) +#define IOCTL_SUPERIO_REQUEST _IOWR(MAGIC_THINKPAD_IOCTL,0x11,superio_ioparm_t) +#define IOCTL_RTCMOSRAM_REQUEST _IOWR(MAGIC_THINKPAD_IOCTL,0x12,rtcmosram_ioparm_t) +#define IOCTL_THINKPADPM_REQUEST _IOWR(MAGIC_THINKPAD_IOCTL,0x20,thinkpadpm_ioparm_t) + +/****** return values ******/ + +/* 0 as a return value always means OK */ + +/* + * We use the following standard UNIX errno's, defined in + * EFAULT memory error + * EBUSY device is already open + * EINVAL function code not recognized + * ENOTTY ioctl code not recognized + * EACCESS inadequate permission to perform action + * + * We use the following standard errnos under names more descriptive + * of our circumstances. Remember that the ioctl handler in the + * driver returns the negatives of these, but they turn up positive + * in user space in errno after an ioctl() call. Our convention + * for ioctl_blah() wrapper functions is to return the errno as a + * negative number. + */ +#define ETHINKPAD_EXECUTION (EILSEQ) +#define ETHINKPAD_PROGRAMMING (ENOSYS) +#define ETHINKPAD_HW_NOT_FOUND (ENXIO) +#define ETHINKPAD_MODULE_DISABLED (ESPIPE) +#define ETHINKPAD_MODULE_NOT_FOUND (ENODEV) +#define ETHINKPAD_SUBDRIVER (EPIPE) + +/* + * Subdriver error codes are returned in the parameter block + * and errno is set to THINKPAD_SUBDRIVER + * + */ + +#endif /* __THINKPAD_COMMON_H__ */ diff -urNp thinkpad/char/thinkpad/thinkpad_driver.h 2.4.20pre8aa2/char/thinkpad/thinkpad_driver.h --- thinkpad/char/thinkpad/thinkpad_driver.h Thu Jan 1 01:00:00 1970 +++ 2.4.20pre8aa2/char/thinkpad/thinkpad_driver.h Wed Oct 2 06:41:39 2002 @@ -0,0 +1,44 @@ + +/********************************************************************* + * + * Filename: thinkpad_driver.h + * Description: common header for all "thinkpad" drivers + * Author: Thomas Hood + * Created: 28 July 1999 + * + * Please report bugs to the author ASAP. + * + * Copyright (c) 1999 J.D. Thomas Hood, All rights reserved + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * To receive a copy of the GNU General Public License, please write + * to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA + * + ********************************************************************/ + +#ifndef __THINKPAD_DRIVER_H__ +#define __THINKPAD_DRIVER_H__ + +#include + +#if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS) +# define MODVERSIONS +#endif + +#ifdef MODVERSIONS + /* This has to follow something that includes config.h and precede + * headers that declare kernel functions that we use */ +#include +#endif + +#endif /* THINKPAD_DRIVER_H */ diff -urNp thinkpad/char/thinkpad/thinkpadpm.c 2.4.20pre8aa2/char/thinkpad/thinkpadpm.c --- thinkpad/char/thinkpad/thinkpadpm.c Thu Jan 1 01:00:00 1970 +++ 2.4.20pre8aa2/char/thinkpad/thinkpadpm.c Wed Oct 2 06:41:39 2002 @@ -0,0 +1,569 @@ + +/********************************************************************* + * + * Filename: thinkpadpm.c + * Description: thinkpadpm.o is a kernel module that serves as + * an interface between the thinkpad module and the + * kernel power management drivers + * Author: Thomas Hood + * Created: 27 January 2001 + * + * Please report bugs to the author ASAP. + * + * Copyright (c) 1999 J.D. Thomas Hood, All rights reserved + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * To receive a copy of the GNU General Public License, please write + * to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA + * + ********************************************************************/ + +#include "thinkpad_driver.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "thinkpad_common.h" +#include "thinkpadpm.h" + + +/****** definitions ******/ + + +/****** declarations ******/ + +extern struct proc_dir_entry *thinkpad_ppde; + +#ifdef CONFIG_DEVFS_FS +static int thinkpadpm_open( + struct inode * pinodeThe, + struct file * pfileThe +); +static int thinkpadpm_release( + struct inode * pinodeThe, + struct file * pfileThe +); +static int thinkpadpm_ioctl( + struct inode * pinodeThe, + struct file * pfileThe, + unsigned int uintIoctlNum, + unsigned long ulongIoctlArg +); +#endif + +/****** variables ******/ + +static const char _szMyName[] = "thinkpadpm"; +static const char _szImName[] = "thinkpadpm_do"; +static const char _szMyVersion[] = "3.0"; +static const char _szProcfile[] = "driver/thinkpad/thinkpadpm"; + +MODULE_AUTHOR( "Thomas Hood" ); +MODULE_DESCRIPTION( "Driver for managing power on IBM ThinkPads" ); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,10) +MODULE_LICENSE( "GPL" ); +#endif + +#ifdef CONFIG_DEVFS_FS +static struct file_operations _fileopsThinkpadpm = { + ioctl: thinkpadpm_ioctl, + open: thinkpadpm_open, + release: thinkpadpm_release, + owner: THIS_MODULE +}; + +static devfs_handle_t _devfs_handleThinkpadpm; +#endif + +/* + * ----------------------------------------------------------------------- + * THE FOLLOWING SECTION WAS COPIED VERBATIM OUT OF THE APM DRIVER v. 1.15 + * ... because the apm driver doesn't export these functions + * ----------------------------------------------------------------------- + */ +#include +#include + +/* + * Define to make the APM BIOS calls zero all data segment registers (so + * that an incorrect BIOS implementation will cause a kernel panic if it + * tries to write to arbitrary memory). + */ +#define APM_ZERO_SEGS + +/* + * Save a segment register away + */ +#define savesegment(seg, where) \ + __asm__ __volatile__("movl %%" #seg ",%0" : "=m" (where)) + +static struct { + unsigned long offset; + unsigned short segment; +} apm_bios_entry; + +/* + * These are the actual BIOS calls. Depending on APM_ZERO_SEGS and + * CONFIG_APM_ALLOW_INTS, we are being really paranoid here! Not only + * are interrupts disabled, but all the segment registers (except SS) + * are saved and zeroed this means that if the BIOS tries to reference + * any data without explicitly loading the segment registers, the kernel + * will fault immediately rather than have some unforeseen circumstances + * for the rest of the kernel. And it will be very obvious! :-) Doing + * this depends on CS referring to the same physical memory as DS so that + * DS can be zeroed before the call. Unfortunately, we can't do anything + * about the stack segment/pointer. Also, we tell the compiler that + * everything could change. + * + * Also, we KNOW that for the non error case of apm_bios_call, there + * is no useful data returned in the low order 8 bits of eax. + */ +#define APM_DO_CLI \ + if (apm_info.allow_ints) \ + __sti(); \ + else \ + __cli(); + +#ifdef APM_ZERO_SEGS +# define APM_DECL_SEGS \ + unsigned int saved_fs; unsigned int saved_gs; +# define APM_DO_SAVE_SEGS \ + savesegment(fs, saved_fs); savesegment(gs, saved_gs) +# define APM_DO_ZERO_SEGS \ + "pushl %%ds\n\t" \ + "pushl %%es\n\t" \ + "xorl %%edx, %%edx\n\t" \ + "mov %%dx, %%ds\n\t" \ + "mov %%dx, %%es\n\t" \ + "mov %%dx, %%fs\n\t" \ + "mov %%dx, %%gs\n\t" +# define APM_DO_POP_SEGS \ + "popl %%es\n\t" \ + "popl %%ds\n\t" +# define APM_DO_RESTORE_SEGS \ + loadsegment(fs, saved_fs); loadsegment(gs, saved_gs) +#else +# define APM_DECL_SEGS +# define APM_DO_SAVE_SEGS +# define APM_DO_ZERO_SEGS +# define APM_DO_POP_SEGS +# define APM_DO_RESTORE_SEGS +#endif + +/** + * apm_bios_call - Make an APM BIOS 32bit call + * @func: APM function to execute + * @ebx_in: EBX register for call entry + * @ecx_in: ECX register for call entry + * @eax: EAX register return + * @ebx: EBX register return + * @ecx: ECX register return + * @edx: EDX register return + * @esi: ESI register return + * + * Make an APM call using the 32bit protected mode interface. The + * caller is responsible for knowing if APM BIOS is configured and + * enabled. This call can disable interrupts for a long period of + * time on some laptops. The return value is in AH and the carry + * flag is loaded into AL. If there is an error, then the error + * code is returned in AH (bits 8-15 of eax) and this function + * returns non-zero. + */ + +static u8 apm_bios_call(u32 func, u32 ebx_in, u32 ecx_in, + u32 *eax, u32 *ebx, u32 *ecx, u32 *edx, u32 *esi) +{ + APM_DECL_SEGS + unsigned long flags; + + __save_flags(flags); + APM_DO_CLI; + APM_DO_SAVE_SEGS; + /* + * N.B. We do NOT need a cld after the BIOS call + * because we always save and restore the flags. + */ + __asm__ __volatile__(APM_DO_ZERO_SEGS + "pushl %%edi\n\t" + "pushl %%ebp\n\t" + "lcall %%cs:" SYMBOL_NAME_STR(apm_bios_entry) "\n\t" + "setc %%al\n\t" + "popl %%ebp\n\t" + "popl %%edi\n\t" + APM_DO_POP_SEGS + : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx), + "=S" (*esi) + : "a" (func), "b" (ebx_in), "c" (ecx_in) + : "memory", "cc"); + APM_DO_RESTORE_SEGS; + __restore_flags(flags); + return *eax & 0xff; +} + +/** + * apm_bios_call_simple - make a simple APM BIOS 32bit call + * @func: APM function to invoke + * @ebx_in: EBX register value for BIOS call + * @ecx_in: ECX register value for BIOS call + * @eax: EAX register on return from the BIOS call + * + * Make a BIOS call that does only returns one value, or just status. + * If there is an error, then the error code is returned in AH + * (bits 8-15 of eax) and this function returns non-zero. This is + * used for simpler BIOS operations. This call may hold interrupts + * off for a long time on some laptops. + */ + +static u8 apm_bios_call_simple(u32 func, u32 ebx_in, u32 ecx_in, u32 *eax) +{ + u8 error; + APM_DECL_SEGS + unsigned long flags; + + __save_flags(flags); + APM_DO_CLI; + APM_DO_SAVE_SEGS; + { + int cx, dx, si; + + /* + * N.B. We do NOT need a cld after the BIOS call + * because we always save and restore the flags. + */ + __asm__ __volatile__(APM_DO_ZERO_SEGS + "pushl %%edi\n\t" + "pushl %%ebp\n\t" + "lcall %%cs:" SYMBOL_NAME_STR(apm_bios_entry) "\n\t" + "setc %%bl\n\t" + "popl %%ebp\n\t" + "popl %%edi\n\t" + APM_DO_POP_SEGS + : "=a" (*eax), "=b" (error), "=c" (cx), "=d" (dx), + "=S" (si) + : "a" (func), "b" (ebx_in), "c" (ecx_in) + : "memory", "cc"); + } + APM_DO_RESTORE_SEGS; + __restore_flags(flags); + return error; +} + +/** + * set_power_state - set the power management state + * @what: which items to transition + * @state: state to transition to + * + * Request an APM change of state for one or more system devices. The + * processor state must be transitioned last of all. what holds the + * class of device in the upper byte and the device number (0xFF for + * all) for the object to be transitioned. + * + * The state holds the state to transition to, which may in fact + * be an acceptance of a BIOS requested state change. + */ + +static int set_power_state(u_short what, u_short state) +{ + u32 eax; + + if (apm_bios_call_simple(APM_FUNC_SET_STATE, what, state, &eax)) + return (eax >> 8) & 0xff; + return APM_SUCCESS; +} + +/* ----------------------------------------------------------------------- */ +/* END OF SECTION COPIED VERBATIM OUT OF THE APM DRIVER */ +/* ----------------------------------------------------------------------- */ + +static int get_power_state(u_short what, u_short *state) +{ + u32 eax; + u32 ecx; + u32 dummy; + + if (apm_bios_call(APM_FUNC_GET_STATE, what, 0, &eax, &dummy, &ecx, + &dummy, &dummy)) + return (eax >> 8) & 0xff; + *state = ecx; + + return APM_SUCCESS; +} + +/* ----------------------------------------------------------------------- */ + + +/****** functions *******/ + +static int thinkpadpm_read_proc( + char *pchBuf, + char **ppchStart, + off_t off, + int intCount, + int *pintEof, + void *data +) { + return snprintf( + pchBuf, intCount, + "%s version %s accessing APM BIOS at 0x%x:0x%lx\n", + _szMyName, _szMyVersion, + apm_bios_entry.segment, + apm_bios_entry.offset + ); +} + +static int get_state( word wWhat, word *pwState ) +{ + int intRtn; + +#ifdef DEBUG + printk(KERN_INFO + "%s: Getting power state for device 0x%x\n", + _szMyName, wWhat + ); +#endif + *pwState = 0x9999; /* ... so we can tell when *pwState wasn't changed */ + intRtn = get_power_state( wWhat, pwState ); + if ( intRtn ) { + printk(KERN_INFO + "%s: Power state of device 0x%x could not be got; 0x%x was returned as the state -- APM error 0x%x\n", + _szMyName, wWhat, *pwState, intRtn + ); + } else { +#ifdef DEBUG + printk(KERN_INFO + "%s: Power state of device 0x%x is 0x%x\n", + _szMyName, wWhat, *pwState + ); +#endif + } + + return intRtn; +} + +static int set_state( word wWhat, word wState ) +{ + int intRtn; + +#ifdef DEBUG + printk(KERN_INFO + "%s: Setting power state for device 0x%x to 0x%x\n", + _szMyName, wWhat, wState + ); +#endif + intRtn = set_power_state( wWhat, wState ); +#ifdef DEBUG + if ( intRtn ) { + printk(KERN_INFO + "%s: Power state of device 0x%x could not be set -- APM error 0x%x\n", + _szMyName, wWhat, intRtn + ); + } +#endif + + return intRtn; +} + +static int thinkpadpm_do_func( + thinkpadpm_inparm_t *pinparmThe, + thinkpadpm_outparm_t *poutparmThe, + flag_t fHasWritePerm +) { + + switch ( pinparmThe->wFunc ) { + case THINKPADPM_FUNC_STATE_GET: + return get_state( pinparmThe->wParm0, (word *)&(poutparmThe->dwParm1) ); + case THINKPADPM_FUNC_STATE_SET: + if ( !fHasWritePerm ) return -EACCES; + return set_state( pinparmThe->wParm0, (word)pinparmThe->dwParm1 ); + default: + return -EINVAL; + } +} + + +int thinkpadpm_do( + unsigned long ulongIoctlArg, + flag_t fCallerHasWritePerm +) { + thinkpadpm_inparm_t inparmThe; + thinkpadpm_outparm_t outparmThe; + unsigned long ulRtnCopy; + int intRtnDo; + + ulRtnCopy = copy_from_user( + &inparmThe, + (byte *)&(((thinkpadpm_ioparm_t *)ulongIoctlArg)->in), + sizeof( inparmThe ) + ); + if ( ulRtnCopy ) return -EFAULT; + + intRtnDo = thinkpadpm_do_func( &inparmThe, &outparmThe, fCallerHasWritePerm ); + + if ( intRtnDo == -EACCES ) { + printk(KERN_ERR + "%s: Caller does not have permission to do this power management act\n", + _szMyName + ); + return -EACCES; + } + + outparmThe.wRc = intRtnDo; + + ulRtnCopy = copy_to_user( + (byte *)&(((thinkpadpm_ioparm_t *)ulongIoctlArg)->out), + &outparmThe, + sizeof( outparmThe ) + ); + if ( ulRtnCopy ) return -EFAULT; + + return outparmThe.wRc ? -ETHINKPAD_SUBDRIVER : 0; +} + +#ifdef CONFIG_DEVFS_FS +static int thinkpadpm_open( + struct inode * pinodeThe, + struct file * pfileThe +) { + + return 0; +} + + +static int thinkpadpm_release( + struct inode * pinodeThe, + struct file * pfileThe +) { + + return 0; +} + + +static flag_t caller_has_w( struct file * pfileThe ) +{ + return ((pfileThe->f_mode) & FMODE_WRITE) ? 1 : 0; +} + + +static int thinkpadpm_ioctl( + struct inode * pinodeThe, + struct file * pfileThe, + unsigned int uintIoctlNum, + unsigned long ulongIoctlArg +) { + +#ifdef DEBUG_VERBOSE + printk( "%s: Doing ioctl number 0x%x\n", _szMyName, uintIoctlNum ); +#endif + + switch ( uintIoctlNum ) { + /* should return at the end of each case block */ + + case IOCTL_THINKPADPM_REQUEST: + return thinkpadpm_do( + ulongIoctlArg, + caller_has_w( pfileThe ) + ); + + default: + /* ioctl number not recognized -- do nothing */ + return -ENOTTY; + + } /* switch */ + + return -ETHINKPAD_PROGRAMMING; /* We should never arrive here */ +} +#endif /* defined(CONFIG_DEVFS_FS) */ + +static int __init thinkpadpm_init( void ) +{ + + /*** Set up APM BIOS interface ***/ + if ( !pm_active ) { + printk(KERN_INFO "thinkpadpm: Power management not active. :-(\n"); + return -ENODEV; + } + if (apm_info.bios.version == 0) { + printk(KERN_INFO "thinkpadpm: No APM BIOS. :-(\n"); + return -ENODEV; + } + if ((apm_info.bios.flags & APM_32_BIT_SUPPORT) == 0) { + printk(KERN_INFO "thinkpadpm: No 32 bit APM BIOS support. :-(\n"); + return -ENODEV; + } + apm_bios_entry.segment = APM_CS; + apm_bios_entry.offset = apm_info.bios.offset; + printk(KERN_INFO + "thinkpadpm: Found APM BIOS version %d.%d flags 0x%02x entry 0x%x:0x%lx. :-)\n", + ((apm_info.bios.version >> 8) & 0xff), + (apm_info.bios.version & 0xff), + apm_info.bios.flags, + apm_bios_entry.segment, + apm_bios_entry.offset + ); + + if ( !thinkpad_ppde || !create_proc_read_entry( + _szProcfile, + S_IFREG | S_IRUGO, + NULL, + thinkpadpm_read_proc, + NULL + ) ) { + printk(KERN_ERR "%s: Could not create_proc_read_entry() /proc/%s\n", _szMyName, _szProcfile ); + } + /* proc entry created */ + +#ifdef CONFIG_DEVFS_FS + _devfs_handleThinkpadpm = devfs_register( + NULL /* dir */, + "thinkpad/thinkpadpm", + DEVFS_FL_DEFAULT | DEVFS_FL_AUTO_DEVNUM, + 0 /* major */, 0 /* minor */, + S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH, + &_fileopsThinkpadpm, + NULL /* info */ + ); + if ( _devfs_handleThinkpadpm == NULL ) { + printk(KERN_ERR "%s: Could not devfs_register(). Aborting.\n", _szMyName ); + return -EIO; + } + /* dev entry created */ +#endif + + inter_module_register( _szImName, THIS_MODULE, &thinkpadpm_do ); + + return 0; +} + + +static void __exit thinkpadpm_exit( void ) +{ + + inter_module_unregister( _szImName ); + +#ifdef CONFIG_DEVFS_FS + devfs_unregister( _devfs_handleThinkpadpm ); +#endif + + remove_proc_entry( _szProcfile, NULL ); + + return; +} + +module_init(thinkpadpm_init); +module_exit(thinkpadpm_exit); diff -urNp thinkpad/char/thinkpad/thinkpadpm.h 2.4.20pre8aa2/char/thinkpad/thinkpadpm.h --- thinkpad/char/thinkpad/thinkpadpm.h Thu Jan 1 01:00:00 1970 +++ 2.4.20pre8aa2/char/thinkpad/thinkpadpm.h Wed Oct 2 06:41:39 2002 @@ -0,0 +1,73 @@ + +/********************************************************************* + * + * Filename: thinkpadpm.h + * Description: header file for the thinkpadpm driver + * Author: Thomas Hood + * Created: 27 January 2001 + * + * Please report bugs to the author ASAP. + * + * Copyright (c) 2001 J.D. Thomas Hood, All rights reserved + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * To receive a copy of the GNU General Public License, please write + * to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA + * + ********************************************************************/ + +#ifndef __THINKPADPM_H__ +#define __THINKPADPM_H__ + +#include + +/****** defines ******/ + +#define THINKPADPM_FUNC_STATE_GET ((word)0x100) +#define THINKPADPM_FUNC_STATE_SET ((word)0x101) + +#define THINKPADPM_DEVICE_SERIAL_1 (APM_DEVICE_SERIAL) +#define THINKPADPM_DEVICE_SERIAL_2 (APM_DEVICE_SERIAL | 0x0001) +#define THINKPADPM_DEVICE_PARALLEL (APM_DEVICE_PARALLEL) + +#define THINKPADPM_STATE_READY (APM_STATE_READY) +#define THINKPADPM_STATE_OFF (APM_STATE_OFF) + + +/*** thinpadpm module input parameters ***/ +typedef struct _thinkpadpm_inparm { + word wFunc; + word wParm0; + dword dwParm1; +} thinkpadpm_inparm_t; + +/*** thinkpadpm module output parameters ***/ +typedef struct _thinkpadpm_outparm { + word wRc; + word wParm0; + dword dwParm1; +} thinkpadpm_outparm_t; + +typedef union _thinkpadpm_ioparm_t { + thinkpadpm_inparm_t in; + thinkpadpm_outparm_t out; +} thinkpadpm_ioparm_t; + +/****** declarations ******/ + +int thinkpadpm_do( + unsigned long ulongIoctlArg, + flag_t fCallerHasWritePerm +); + +#endif /* __THINKPADPM_H__ */ diff -urNp thinkpad/drivers/char/Makefile 2.4.20pre8aa2/drivers/char/Makefile --- thinkpad/drivers/char/Makefile Wed Oct 2 06:40:50 2002 +++ 2.4.20pre8aa2/drivers/char/Makefile Wed Oct 2 06:42:00 2002 @@ -289,6 +289,11 @@ obj-$(CONFIG_WAFER_WDT) += wafer5823wdt. obj-$(CONFIG_SOFT_WATCHDOG) += softdog.o obj-$(CONFIG_AMD7XX_TCO) += amd7xx_tco.o +subdir-$(CONFIG_THINKPAD) += thinkpad +ifeq ($(CONFIG_THINKPAD),y) + obj-y += thinkpad/thinkpad_all.o +endif + subdir-$(CONFIG_MWAVE) += mwave ifeq ($(CONFIG_MWAVE),y) obj-y += mwave/mwave.o diff -urNp thinkpad/drivers/char/thinkpad/ChangeLog 2.4.20pre8aa2/drivers/char/thinkpad/ChangeLog --- thinkpad/drivers/char/thinkpad/ChangeLog Thu Jan 1 01:00:00 1970 +++ 2.4.20pre8aa2/drivers/char/thinkpad/ChangeLog Wed Oct 2 06:42:00 2002 @@ -0,0 +1,419 @@ +ChangeLog file for thinkpad device drivers +========================================== + +TODO +---- +- Add /proc interface for some commonly used functions? +- Merge smapi functionality with that in mwave driver +- Submit drivers for inclusion into kernel tree +HELP IS WELCOME + +3.5 changes from 3.3 +-------------------- +13Apr2002 JDTH : Update README + Bump smapi driver version (should have been done in 3.1) + +3.3 changes from 3.2 +-------------------- +27Mar2002 JDTH : Update thinkpad.4 man page + +3.2 changes from 3.1 +-------------------- + 9Mar2002 JDTH : Add thinkpad.4 man page + Update docs + +3.1 changes from 3.0 +-------------------- +28Feb2002 JDTH : Add debian directory + Reduce frequency of reports of differing SMAPI return codes + Include 2.2 directory containing drivers from 1.0 which + work with Linux 2.2 +18Feb2002 JDTH : Add A30 to SUPPORTED-MODELS + +------------------------------------------------------------- +Note that post 3.0 this is the ChangeLog for thinkpad only. +In 3.0 and earlier, tpctl and thinkpad had a common ChangeLog +------------------------------------------------------------- + +3.0 changes from 2.5 +-------------------- +10Feb2002 JDTH : Releases renamed '3.0' + 3Feb2002 JDTH : Release thinkpad 3.0pre7 + 3Feb2002 JDTH : Simplified proc read functions +23Dec2001 JDTH : Release thinkpad 3.0pre6 +23Dec2001 JDTH : Put #ifdefs around MODULE_LICENSE so that the + modules can be used with kernels < 2.4.10 + 7Dec2001 JDTH : Release thinkpad 3.0pre5 + 7Dec2001 JDTH : Change instructions on configuring devfsd in the + README file, to reflect recent changes in devfs +14Nov2001 JDTH : Release tpctl 3.0pre4 +14Nov2001 JDTH : Janitorial work: + Make type of all flags in tpctl flag_t + I hope the janitor didn't break anything + Tweak --pra handling to reflect the fact that + appointments are made either for every day or for + every century. Tweak printf and scanf formats +26Oct2001 JDTH : Release 3.0pre3 +24Oct2001 JDTH : Update thinkpad README file +24Oct2001 JDTH : Change module parameter names to omit "thinkpad" + prefix which isn't necessary if we simply make + the parameter variables static. This reverts a + change made for 2.5. Sorry!! +24Oct2001 JDTH : Sync thinkpadpm code with the apm driver code from + which it was copied +22Oct2001 JDTH : Update TROUBLESHOOTING file again +18Oct2001 JDTH : Release 3.0pre2 +18Oct2001 JDTH : Improve device file handling code; provide more + useful error messages when file not found, etc. +17Oct2001 JDTH : Append TODO to README + 6Oct2001 JDTH : Note in thinkpad README that drivers are compatible + with certain Linux kernels + 5Oct2001 JDTH : Revise TROUBLESHOOTING file + 4Oct2001 JDTH : Release 3.0pre1 +18Sep2001 JDTH : Move proc files under /proc/driver subdirectory + : Add devfs support to superio, thinkpadpm, rtcmosram +28Aug2001 JDTH : Add devfs support to ntpctl as I did to tpctl + : Update TODO +27Jul2001 JDTH : Added devfs support to thinkpad and smapi modules + : Cleaned up driver init and exit functions + : Modified tpctl so it looks for /dev/thinkpad/thinkpad + : Split into two packages: + thinkpad -- device drivers + tpctl -- tpctl and its kindred binaries and lib + : Eliminate Makefile-common + +2.5 changes from 2.4 +-------------------- +25Jul2001 JDTH : Added reference to new ed. of _Linux device drivers_ + : Change module options enable_* -> thinkpad_enable_* + : Introduce a global variable "thinkpad_ppde" so that + other modules will require thinkpad module in order + to load, thus preventing corruption of /proc fs. + This eliminates the needs for "below" statements in + /etc/modules.conf. Updated README accordingly. + : Eliminate *_MOD_USE_COUNT etc. in favour of kernel's + automatic use counting +17Jul2001 JDTH : Change rtcmosram to use rtc_lock spinlock + instead of disabling interrupts. + : Eliminate proc fs optionalness + : Update README for devfs users +27Apr2001 JDTH : Fixed comments in several header files +16Apr2001 JDTH : Add INFO-BIOS file to tarball + +2.4 changes from 2.3 +-------------------- +27Feb2001 JDTH : No changes, except version increased to deal with + FUBAR upload of 2.3 to SourceForge + +2.3 changes from 2.2 +-------------------- +23Feb2001 JDTH : Update TODO, README +23Feb2001 JDTH : Fixed bug in superio PnP mode detection fn +18Feb2001 JDTH : Make tpctl 2.x work nicely with 1.0 modules. +11Feb2001 JDTH : tpctl now does a sync() before sedating +10Feb2001 JDTH : Update man pages for tpctl and ntpctl + +2.2 changes from 2.1 +-------------------- +6Feb2001 JDTH : Make names and version strings "const" variables. +6Feb2001 JDTH : Clean up printouts at init time and in /proc/thinkpad +6Feb2001 JDTH : Copy APM BIOS interface from APM driver to thinkpadpm.c so + that no kernel patch is required. +5Feb2001 JDTH : Correct README, TODO, ChangeLog files. +4Feb2001 JDTH : Remove SUPPORTED-MODELS file. INFO-BIOS does the same job. + +2.1 changes from 2.0 +-------------------- +4Feb2001 JDTH : Eliminate unnecessary explicit dereference of function + variable names in thinkpad.c +2Feb2001 JDTH : Update TECHNOTES, TODO, README, ChangeLog, etc. +31Jan2001 JDTH : Change tpctl --rx print outs, including order of items ... + I hope this doesn't annoy anyone. +27Jan2001 JDTH : Clean up --- use recommended Linux 2.4.x API +27Jan2001 JDTH : Add thinkpadpm module to control subsystem power. +27Jan2001 JDTH : Remove use of global fReady flags -- not needed +23Jan2001 JDTH : Install man in /usr/share/man not /usr/man +23Jan2001 JDTH : Remove cOpen variable from thinkpad.c; use MOD_IN_USE +22Jan2001 JDTH : Change all versions to 2.1 +22Jan2001 JDTH : Rename thinkpad_mod_defines.h to terser "thinkpad_module.h" +22Jan2001 JDTH : Remove VIAGRA #ifdef ... #endif since hw acces seems safe +22Jan2001 JDTH : Remove old proc filesystem code: NEW_PROC is king +22Jan2001 JDTH : Remove POWER_SERIAL code: module will do the work + +2.0 changes from 1.0 +-------------------- +20Jan2001 JDTH : Move tpctlir up out of contrib/ directory +20Jan2001 DS/JDTH : Added apmiser to the package +22Dec2000 JDTH : Use /lib/modules/xyz/build as path to kernel sources +22Dec2000 JDTH : Clean up Makefiles +12Dec2000 JDTH : Install under /usr, not under /usr/local +12Dec2000 JDTH : Port drivers to Linux 2.4 API + +1.0 changes from 0.8.9 +---------------------- +26Oct2000 JDTH : Remove '*' from lcall in smapi_call.s +16Oct2000 JDTH : Create BUGS file +14Oct2000 JDTH : Change --pra code so that selecting a daily app't + does not overwrite the date of the non-daily app't +14Oct2000 JDTH : Standardize date and time display and input formats + (thanks to Marc Joosen for the suggestion) +14Oct2000 JDTH : Add "-Wno-uninitialized" to CFLAGS for compiling tpctl +11Oct2000 JDTH : Update docs +7Oct2000 JDTH : Change tpctl and ntpctl Makefiles to link to smapidev + in the same way +7Oct2000 JDTH : Add SUPPORTED-MODELS file +7Oct2000 JDTH : Update README +7Oct2000 JDTH : Remove tpctlify; config now to be done by hand + because there were too many problems with + automated installation. +7Oct2000 JDTH : Rename VGA_MODES file to "VGA-MODES" +7Oct2000 JDTH : Remove plug-n-play check from superio init + +0.8.9 changes from 0.8.8 +------------------------ +1July2000 JDTH : Add kdist_clean target to Makefile to make make-kpkg happy +6July2000 AB/JDTH : Rename libsmapidev.so to libsmapidev.so.1 and add symlinks +6July2000 JDTH : Update AUTHORS file +17July2000 JDTH : Remove ioctl_thinkpad(), ioctl_superio() and + ioctl_rtcmosram() from smapidev since these have nothing + to do with SMAPI; move them into tpctl.c . +17July2000 JDTH : Change display of parallel port mode so that it is the + same as what you have to input to change the mode. +17July2000 JDTH : Remove some sound-related cruft from the thinkpad driver. +17July2000 JDTH : Add support for switching serial port on and off at the + same time as the port is enabled or disabled. At present + this requires a patch to the kernel: see tpctl/README. +18July2000 JDTH : Display interpretative strings for numerical values + consistently. +18July2000 JDTH : Update TROUBLESHOOTING, README and TODO files + +0.8.8 changes from 0.8.7 +------------------------ +25May2000 JDTH : Add COPYING file +25May2000 JDTH : Streamline some of the tpctl code + +0.8.7 changes from 0.8.6 +------------------------ +28Apr2000 JDTH : Remove other_tools/ubswap + +0.8.6 changes from 0.8.5 +------------------------ +26Apr2000 JDTH : Remove hdparm patch from other_tools/ubswap + since the patch has been incorporated into + the standard hdparm source +13Mar2000 JDTH : Update TODO file + +0.8.5 changes from 0.8.4 +------------------------ +3Mar2000 JDTH : Removed superfluous legacy-mode (i.e., superio + non-pnp mode) config information from tpctl -rx + outputs +17Feb2000 FB/JDTH : create_proc_read_entry() appeared in the + linux-2.3.25 kernel and not in 2.3.0; + changed #if in thinkpad_mod_defines.h +19Jan2000 MF : ntpctl -- open device RDONLY if can't open RDWR +15Jan2000 JDR/JDTH : Call depmod and modprobe by full path name + +0.8.4 changes from 0.8.3 +------------------------ +11Jan2000 AB : Added man pages for ntpctl, ubswap, tpctlir + Thanks to Adrian Bridgett! + +0.8.3 changes from 0.8.2 +------------------------ +9Jan2000 JDTH : (Experimental) Added ability to select SPP/EPP/ECP + +0.8.2 changes from 0.8.1 +------------------------ +6Jan2000 JDTH : Send '/lib/modules/`uname -r`' to tpctlify as module + path argument instead of /lib/modules/`uname -r` + +0.8.1 changes from 0.8.0 +------------------------ +5Jan2000 JDTH : Tested with 2.2.14 kernel. A-OK. +5Jan2000 RB/JDTH : Implemented TP570_KLUDGE +5Jan2000 MS/JDTH : Send path arguments to tpctlify +4Jan2000 HV/JDTH : Kernel path now selectable via a Makefile variable +3Jan2000 JDTH : Improved byte_of_bcd8() error message +3Jan2000 MS/JDTH : Added "install_modules" target to Makefile so that + modules can be installed separately from the + other stuff +3Jan2000 AB/JDTH : tpctlir now fails gracefully if not run by root +3Jan2000 JDTH : Fixed typo in heading for 'tpctl --pdZ' output +3Jan2000 AB/JDTH : Fixed typo in heading for 'tpctl --ip' output + +0.8.0 changes from 0.7.6 +------------------------ +31Dec99 JDTH : Man path now selectable via a Makefile variable +29Dec99 JDTH : Documentation corrections + +0.7.6 changes from 0.7.5 +------------------------ +27Dec99 DD/JDTH : Added tpctl man page. Thanks to Dave Davey! +25Dec99 AG/JDTH : Modified drivers to work with 2.3.x kernels' /proc + filesystem interface. Thanks to Anders Gustafsson! + +0.7.5 changes from 0.7.4 +------------------------ +13Dec99 JDTH : No longer install tpctlify + +0.7.4 changes from 0.7.3 +------------------------ +11Dec99 JDTH : Fixed nasty bug in Makefile that caused /lib/modules + to be wiped out on install. DO NOT INSTALL 0.7.3 ! +11Dec99 JDTH : Eliminated RPM-related stuff. Will release only + tarballs from now on. +11Dec99 JDTH : Changed modules installation directory to: + /lib/modules//thinkpad + +0.7.3 changes from 0.7.2 +------------------------ +8Dec99 JDTH : Added "other_tools" directory with two nifty tools: + tpctlir -- enables/disables infrared subsystem on + ThinkPads with Programmable Option Select + ubswap -- allows hot swapping of UltraBay devices +7Dec99 JDTH : Added IOCTL_SND_REINIT to the thinkpad module + Created the tpreinitsnd program to call the new ioctl +1Dec99 JDTH : Tweaked ntpctl menus for greater consistency with tpctl + +0.7.2 changes from 0.7.1 +------------------------ +30Nov99 JDTH : Integrated ntpctl into the package + Moved files into subdirectories + +0.7.1 changes from 0.7.0 +------------------------ +13Nov99 JDTH : Added GetPowerExpenditureMode and SetPowerExpenditureMode + to libsmapidev +17Oct99 JDTH : Updated my email address + +0.7.0 changes from 0.6.1 +------------------------ +31Jul99 JDTH : Update TROUBLESHOOTING especially re: kernel compatibility +31Jul99 JDTH : Move /proc entries under /proc/thinkpad +31Jul99 JDTH : Fiddled with tpctlify + +0.6.1 changes from 0.6.0 +------------------------ +30Jul99 JDTH : (Build 3) Eliminate some warning messages from byte_of_bcd8() +29Jul99 JDTH : Change handling of error codes so that it does not + rely upon ioctl() returning positive error codes + to the user. Such reliance is not portable. + +0.6.0 changes from 0.5.10 +------------------------- +29Jul99 JDTH : Change highlighting to "bold" and use the curses library + to get the appropriate terminal control strings. + +0.5.10 changes from 0.5.9 +------------------------- +28Jul99 JDTH : (Build 2+) Allow rtcmosram module to load even if ioports are + occupied. +28Jul99 JDTH : Complete modularization: modules are now automatically and + independently loadable and unloadable. When tpctl is run, + thinkpad.o is loaded by the module loader as per instructions + in /etc/modules.conf. The thinkpad module, in turn, requests + the loading of the other modules as they are needed to perform + ioctl requests. Loading of a module is inhibited by setting + "enable_" to zero, which can be done at load time or + via ioctl(). See README. +27Jul99 JDTH : Simplify "SIZE_..._MAX" macros +28Jul99 JDTH : Change '--silent' to '--quiet' since the switch doesn't + make tpctl completely silent. + +0.5.9 changes from 0.5.8 +------------------------ +27Jul99 JDTH : Use more standard error messaging +27Jul99 JDTH : Hive off smapi, superio and rtcmosram as distinctly + loadable modules. +27Jul99 JDTH : Fix bug in smapi:locate_smb_header() +27Jul99 JDTH : Fix bug in --pra output +27Jul99 JDTH : Abandon "variants" idea of 0.5.8 since it doesn't solve + the problem that it was meant to solve +27Jul99 JDTH : Add /proc/* entries for each enabled submodule +27Jul99 JDTH : Add module parameters to thinkpad.o to govern enabling of + the subordinate modules +27Jul99 JDTH : Make superio mod more careful about interrupt cli/restore +27Jul99 JDTH : Clean up module code a lot: make it much more kernelifically + correct and fault tolerant + +0.5.8 changes from 0.5.7 +------------------------- +25Jul99 JDTH : Package rpm with both modversions and non-modversions variants +25Jul99 JDTH : (release 5:) and install these in /lib/modules/thinkpad/thinkpad + and symlink /lib/modules/thinkpad/thinkpad.o to the right one +25Jul99 JDTH : Fix bug in Usage output +25Jul99 JDTH : Require write access for writing to CMOS RAM + +0.5.7 changes from 0.5.6 +------------------------- +24Jul99 JDTH : Added rtcmosram module +24Jul99 JDTH : Added --sst option +24Jul99 JDTH : Added --ic option +24Jul99 JDTH : Renamed --ic option as '--ip' + +0.5.6 changes from 0.5.5 +------------------------- +22Jul99 JDTH : Added "--silent" option +22Jul99 JDTH : Changed highlighting code to make it disablable using + the "--dull" option + +0.5.5 changes from 0.5.4 +------------------------- +22Jul99 JDTH : Added info about confuring serial ports to README +22Jul99 JDTH : Tried to make superio more kosher with its ioport usage +22Jul99 JDTH : Made checking for Super I/O chip a little more careful. + +0.5.4 changes from 0.5.3 +------------------------- +22Jul99 JDTH : Display appointment info all on one line +22Jul99 JDTH : Changed tpctlify to check for perl before invoking it + Also, make it more verbose +22Jul99 JDTH : Changed so that print formatting is nicer when many arguments + are given. Highlighting option improved and enabled for + binary distribution. + Options added: + --pdZh --pdZu + --x --sx --px etc. + Option names changed: + --iu --> --iU + --state-* --> --setup-* + I hope this didn't break anything. +22Jul99 JDTH : Allow thinkpad to initialize even if superio doesn't +22Jul99 JDTH : Update TROUBLESHOOTING file (outdate ref to 10:168 <- wrong) +21Jul99 JDTH : Add PS2.EXE/tpctl comparison to TODO + + +0.5.3 changes from 0.5.2 +------------------------- +21Jul99 JDTH : (build 2) Change Makefile: remove -D switch which + is new to version 4.0 of install and do mkdirs instead +21Jul99 JDTH : (build 2) Change tpctlify to add /usr/local/lib + to the ld path if it's not already there +21Jul99 JDTH : Cleaned up superio.c code +21Jul99 JDTH : Fixed bug in tpctlify script -- didn't abort +21Jul99 JDTH : Removed '--verbose' options from Makefile commands + +0.5.2 changes from 0.5.1 +------------------------- +21Jul99 JDTH : Added 'rpm' target +21Jul99 JDTH : Compiler warning messages ("implicit declaration") eliminated + *This should solve some kernel compatibility problems!* +21Jul99 JDTH : Rest of par and ser configuration options implemented +21Jul99 JDTH : Make module init function a bit safer +20Jul99 JDTH : Changed device number to 10:170 by order of the + device number czar + +0.5.1 changes from 0.5.0 +------------------------- +20Jul99 JDTH : Fixed version printout formatting +20Jul99 JDTH : Print actual IRQs used + +0.5.0 changes from 0.3.7 +------------------------- +20Jul99 JDTH : --rs* functionality augmented +19Jul99 JDTH : --im folded into --ib +19Jul99 JDTH : Install script is now '/usr/local/sbin/tpctlify' +19Jul99 JDTH : Kernel module is now called 'thinkpad' +19Jul99 JDTH : Device file is now called /dev/thinkpad (dev. number 10:168) +19Jul99 JDTH : Widespread changes in the code structure diff -urNp thinkpad/drivers/char/thinkpad/Makefile 2.4.20pre8aa2/drivers/char/thinkpad/Makefile --- thinkpad/drivers/char/thinkpad/Makefile Thu Jan 1 01:00:00 1970 +++ 2.4.20pre8aa2/drivers/char/thinkpad/Makefile Wed Oct 2 06:42:00 2002 @@ -0,0 +1,30 @@ +# +# Makefile for IBM ThinkPad control support (tpctl). +# +# See the README file in this directory for more info. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definitions are now inherited from the +# parent makes.. +# + +TPMODS = thinkpad.o smapi.o superio.o rtcmosram.o thinkpadpm.o + +obj-$(CONFIG_THINKPAD) := $(TPMODS) + +ifeq ($(CONFIG_THINKPAD),y) + O_TARGET = thinkpad_all.o +endif + +include $(TOPDIR)/Rules.make + +thinkpad_all.o: $(TPMODS) + rm -f $@ + $(LD) $(EXTRA_LDFLAGS) -r -o $@ $(TPMODS) + +smapi.o: smapi_core.o smapi_call.o + rm -f $@ + $(LD) $(EXTRA_LDFLAGS) -r -o $@ smapi_core.o smapi_call.o diff -urNp thinkpad/drivers/char/thinkpad/README 2.4.20pre8aa2/drivers/char/thinkpad/README --- thinkpad/drivers/char/thinkpad/README Thu Jan 1 01:00:00 1970 +++ 2.4.20pre8aa2/drivers/char/thinkpad/README Wed Oct 2 06:42:00 2002 @@ -0,0 +1,162 @@ + README file for + thinkpad device drivers + +Last updated: 13 April 2002 + +Introduction +============ + +thinkpad.o, smapi.o, superio.o, rtcmosram.o and thinkpadpm.o are loadable +kernel modules that serve as interfaces to the IBM System Management +Application Program Interface (SMAPI) BIOS found in some IBM ThinkPad laptop +computers, and as drivers of certain ThinkPad hardware components. Access +to the modules is via the ioctl() system call. Each module adds an entry +under /proc/driver/thinkpad named like itself which contains some information +about the module. + +These drivers were written to be used with the tpctl program. +Please see the README file for that program for more information. + +Requirements +============ + +Hardware +-------- + +IBM ThinkPad laptop computer. See the SUPPORTED-MODELS file for more +information. If this file wasn't included in the thinkpad package, look +for it in the tpctl package. + +Kernel +------ + +The 3.x releases of the drivers support Linux 2.4.0 or later. + + +Installation +============ + +If you are using Debian, install the thinkpad-base package, then +install the thinkpad-source package and use make-kpkg to make a +thinkpad-modules- package for your kernel and install +that. You are finished. + +On distributions that don't set things up for you automatically, +you can install from the source tarball. First make sure that your +kernel source tree is at /lib/modules/`uname -r`/build . Do: + tar zxvf thinkpad-.src.tar.gz + cd thinkpad- + make all + +Once compilation has finished, to install the files do the following +(as root): + make install +This installs the loadable kernel modules under the directory +/lib/modules//thinkpad . + +You may want to follow this with: + make clean +which deletes all compiled binaries from your source directory. + +If you do _not_ use devfs then you must create a device node for the +thinkpad device driver. As root do: + mknod --mode=664 /dev/thinkpad c 10 170 + +If you _do_ use devfs you don't need to make a node; the driver +modules will create nodes under /dev/thinkpad when they are loaded. + +It might be useful to create a "thinkpad" group and add to it users +whom you want to allow to adjust settings. Then the device node's +group should be changed to "thinkpad". Without devfs do this as +root: + chown root.thinkpad /dev/thinkpad +With devfs, to make this change permanent, add the following line to +/etc/devfsd.conf and restart devfsd: + REGISTER ^thinkpad/.*$ PERMISSIONS root.thinkpad 0664 + +The package is now installed. + + +Uninstallation +============== + +To remove all installed thinkpad device driver files: + make uninstall + +Note that this removes /lib/modules//thinkpad +and all its contents and subdirectories! + + +Usage -- modules +================ + +The modules are loaded automatically when they are needed. + +thinkpad.o dispatches requests to the other modules. It can be loaded with +the following parameters: + enable_smapi=(0|1) disable|enable use of smapi module + enable_superio=(0|1) disable|enable use of superio module + enable_rtcmosram=(0|1) disable|enable use of rtcmosram module + enable_thinkpadpm=(0|1) disable|enable use of thinkpadpm module +E.g., + insmod thinkpad enable_superio=0 +loads the thinkpad module while preventing it from using the superio module. +tpctl commands that employ the superio module will then return an error +message. The default value of each parameter is 1. These parameters can be +added to the /etc/modules.conf or /etc/conf.modules file as follows so that +they are in effect whenever thinkpad.o loaded by modprobe. E.g., + options thinkpad enable_smapi=0 enable_superio=0 +These parameters were added so that thinkpad.o can be used "safely" on +ThinkPads which lack some of the supported hardware. + +The file /proc/thinkpad/ contains information about each of +the drivers. + + +Security +======== + +The user requires write permission on the thinkpad device file (normally +/dev/thinkpad or /dev/thinkpad/thinkpad) in order to change settings or +to "sedate" the machine. This means that it is safe to allow an untrusted +user to execute tpctl or ntpctl, so long as he or she doesn't have write +permission on the device file. + + +References +========== + +In writing the code I found the following documentation helpful. +With the advent of kernel 2.4.0 much of their content is out of date. + +------------------------------------------------------------------------ + +IBM. _IBM ThinkPad 560Z Technical Reference_. First ed (October 1998). + _IBM ThinkPad 560 Technical Reference_. + _IBM ThinkPad 600 Technical Reference_. + _IBM ThinkPad 765 Technical Reference_. + _IBM ThinkPad 770 Technical Reference_. + +National Semiconductor. _PC87338/PC97338 data sheet_. November, 1998. + +Pomerantz, Ori. _Linux kernel module programming guide_. Version 1.1.0 + 26 April 1999. + +Rubini, Alessandro. _Linux device drivers_. Cambridge: O'Reilly, 1998. + +Rubini, Alessandro and Jonathan Corbet. _Linux device drivers_. 2nd ed. + Cambridge, O'Reilly, 2001. + http://www.oreilly.com/catalog/linuxdrive2/chapter/book/index.html + +------------------------------------------------------------------------ + +The first of the IBM Technical Reference manuals listed is the most +current and correct that I have found. All are available in the +"support" section of IBM's website www.ibm.com. + +I thank Ori Pomerantz for his contribution. + +The O'Reilly book, now in its second edition, is superb. + +-- +Thomas Hood diff -urNp thinkpad/drivers/char/thinkpad/SUPPORTED-MODELS 2.4.20pre8aa2/drivers/char/thinkpad/SUPPORTED-MODELS --- thinkpad/drivers/char/thinkpad/SUPPORTED-MODELS Thu Jan 1 01:00:00 1970 +++ 2.4.20pre8aa2/drivers/char/thinkpad/SUPPORTED-MODELS Wed Oct 2 06:42:00 2002 @@ -0,0 +1,854 @@ +The following is a list of outputs from the "tpctl --info-bios" +command that have been helpfully submitted by tpctl users. + +Because this information is obtained via a SMAPI function, each +of the machines listed below is proved to have some sort of +SMAPI BIOS, and so probably supports most of the functions of +tpctl. The machine may or may not support the "--r*" functions, +which do not use SMAPI. + +I give several outputs on the same line whenever several +users have submitted outputs that differ. The differences +reflect the fact that some people have newer machines than +others and/or have upgraded their BIOS. + +365X (2625-2E9) + system ID: 28 + country code: 1 + system BIOS revision: 0.28 + system management BIOS revision: 1.20 + SMAPI BIOS interface revision: 0.86 + video BIOS revision: 1.00 + slave controller revision: 1.10 + +(--r* options don't work) + +365XD + system ID: 28 + country code: 1 + system BIOS revision: 0.24 + system management BIOS revision: 1.18 + SMAPI BIOS interface revision: 0.86 + video BIOS revision: 1.00 + slave controller revision: 1.10 + +380D + system ID: 37 37 + country code: 1 1 + system BIOS revision: 0.17 0.33 + sys management BIOS revision: 1.10 1.16 + SMAPI BIOS interface revision: 0.88 0.88 + video BIOS revision: 1.22 1.32 + slave controller revision: 1.11 1.11 + +380ED + system ID: 37 + country code: 1 + system BIOS revision: 0.33 + system management BIOS revision: 1.16 + video BIOS revision: 1.32 + slave controller revision: 1.11 + +380XD (Australian model) + system ID: 44 + country code: 1 + system BIOS revision: 1.02 + system management BIOS revision: 1.01 + SMAPI BIOS interface revision: 0.90 + video BIOS revision: 1.12 + slave controller revision: 1.5 + +380Z (2635-HGO) + system ID: 54 + country code: 1 + system BIOS revision: 1.04 + system management BIOS revision: 1.08 + SMAPI BIOS interface revision: 0.90 + video BIOS revision: 1.15 + slave controller revision: 1.5 + +385CD (2635-2EU) + system ID: 37 + country code: 1 + system BIOS revision: 0.35 + system management BIOS revision: 1.18 + SMAPI BIOS interface revision: 0.88 + video BIOS revision: 1.32 + slave controller revision: 1.11 + +385XD (2635-DEU) + system ID: 53 + country code: 1 + system BIOS revision: 1.06 + system management BIOS revision: 1.10 + SMAPI BIOS interface revision: 0.90 + video BIOS revision: 1.16 + slave controller revision: 1.8 + +560 + system ID: 26 + country code: 1 + system BIOS revision: 0.27 + system management BIOS revision: 1.35 + SMAPI BIOS interface revision: 0.86 + video BIOS revision: 1.00 + slave controller revision: 1.2 + +560E + system ID: 38 + country code: 1 + system BIOS revision: 0.09 0.12 + system management BIOS revision: 1.37 1.40 + SMAPI BIOS interface revision: 0.86 + video BIOS revision: 1.00 + slave controller revision: 1.2 + +560X (233MHz MMX) + system ID: 43 + country code: 1 + system BIOS revision: 0.01 + system management BIOS revision: 1.04 + SMAPI BIOS interface revision: 0.90 + video BIOS revision: 1.11 + slave controller revision: 1.10 + +560Z + system ID: 55 + country code: 1 + system BIOS revision: 1.06 + system management BIOS revision: 1.09 + SMAPI BIOS interface revision: 0.90 + video BIOS revision: 1.16 + slave controller revision: 1.6 + +570 + system ID: 60 60 + country code: 1 1 + system BIOS revision: 0.31 0.34 + system management BIOS revision: 255.255 255.255 + SMAPI BIOS interface revision: 2.00 2.00 + video BIOS revision: 1.15 1.15 + slave controller revision: 0.9 1.0 + +570 (2644-3AU) + system ID: 60 + country code: 1 + system BIOS revision: 0.36 + system management BIOS revision: 255.255 + SMAPI BIOS interface revision: 2.00 + video BIOS revision: 1.15 + slave controller revision: 1.0 + +570E + system ID: 88 88 + country code: 1 1 + system BIOS revision: 0.11 0.14 + system management BIOS revision: 255.255 255.255 + SMAPI BIOS interface revision: 2.00 2.00 + video BIOS revision: 1.15 1.15 + slave controller revision: 1.1 1.2 + +600 (21U) + system ID: 45 45 45 + country code: 1 1 1 + system BIOS revision: 1.33 1.36 1.39 + sys management BIOS revision: 2.13 2.15 2.18 + SMAPI BIOS interface revision: 0.90 0.90 0.90 + video BIOS revision: 1.16 1.16 1.28 + slave controller revision: 1.14 1.14 1.15 + +600 (21O) + system ID: 45 + country code: 1 + system BIOS revision: 1.37 + sys management BIOS revision: 2.16 + SMAPI BIOS interface revision: 0.90 + video BIOS revision: 1.16 + slave controller revision: 1.14 + +600 (35U) + system ID: 45 + country code: 1 + system BIOS revision: 1.03 + system management BIOS revision: 1.03 + SMAPI BIOS interface revision: 0.90 + video BIOS revision: 1.14 + slave controller revision: 1.14 + +600 (41A) + system ID: 45 + country code: 1 + system BIOS revision: 1.39 + system management BIOS revision: 2.18 + SMAPI BIOS interface revision: 0.90 + video BIOS revision: 1.28 + slave controller revision: 1.15 + +600 (45O) + system ID: 45 + country code: 1 + system BIOS revision: 1.36 + system management BIOS revision: 2.15 + SMAPI BIOS interface revision: 0.90 + video BIOS revision: 1.16 + slave controller revision: 1.14 + +600 (51U) + system ID: 45 45 45 45 45 + country code: 1 1 1 1 1 + system BIOS revision: 1.38 1.39 1.47 1.48 1.49 + system management BIOS revision: 2.17 2.18 2.24 2.24 2.24 + SMAPI BIOS interface revision: 0.90 0.90 0.90 0.90 0.90 + video BIOS revision: 1.16 1.28 1.28 1.28 1.28 + slave controller revision: 1.14 1.15 1.15 1.15 1.15 + +600 (85U) + system ID: 45 + country code: 1 + system BIOS revision: 1.39 + system management BIOS revision: 2.18 + SMAPI BIOS interface revision: 0.90 + video BIOS revision: 1.28 + slave controller revision: 1.15 + +600E (2645-4AA) + system ID: 68 + country code: 1 + system BIOS revision: 1.03 + system management BIOS revision: 1.00 + SMAPI BIOS interface revision: 0.92 + video BIOS revision: 1.15 + slave controller revision: 1.5 + +600E (2645-4AU) + system ID: 68 + country code: 1 + system BIOS revision: 1.14 + system management BIOS revision: 1.07 + SMAPI BIOS interface revision: 0.92 + video BIOS revision: 1.15 + slave controller revision: 1.8 + +600E (2645-550) + system ID: 57 + country code: 1 + system BIOS revision: 1.04 + system management BIOS revision: 1.04 + SMAPI BIOS interface revision: 0.92 + video BIOS revision: 1.15 + slave controller revision: 1.4 + +600E (2645-5AA) + system ID: 68 + country code: 1 + system BIOS revision: 1.09 + system management BIOS revision: 1.05 + SMAPI BIOS interface revision: 0.92 + video BIOS revision: 1.15 + slave controller revision: 1.5 + +600E (2645-5AO) + system ID: 68 + country code: 1 + system BIOS revision: 1.10 + system management BIOS revision: 1.06 + SMAPI BIOS interface revision: 0.92 + video BIOS revision: 1.15 + slave controller revision: 1.8 + +600E (2645-5BU) + system ID: 68 + country code: 1 + system BIOS revision: 1.21 + system management BIOS revision: 1.11 + SMAPI BIOS interface revision: 0.92 + video BIOS revision: 1.15 + slave controller revision: 1.8 + +600E (2645-5JU) + system ID: 68 + country code: 1 + system BIOS revision: 1.15 + system management BIOS revision: 1.08 + SMAPI BIOS interface revision: 0.92 + video BIOS revision: 1.15 + slave controller revision: 1.8 + +600E (2645-8A0) + system ID: 68 + country code: 1 + system BIOS revision: 1.03 + system management BIOS revision: 1.00 + SMAPI BIOS interface revision: 0.92 + video BIOS revision: 1.15 + slave controller revision: 1.5 + +600E (2645-A5U) + system ID: 57 + country code: 1 + system BIOS revision: 1.06 + system management BIOS revision: 1.05 + SMAPI BIOS interface revision: 0.92 + video BIOS revision: 1.15 + slave controller revision: 1.4 + +600E (2645-UN1) + system ID: 68 + country code: 1 + system BIOS revision: 1.09 + system management BIOS revision: 1.05 + SMAPI BIOS interface revision: 0.92 + video BIOS revision: 1.15 + slave controller revision: 1.5 + +600X (2645-3EU) + system ID: 74 74 + country code: 1 1 + system BIOS revision: 1.10 1.13 + system management BIOS revision: 1.06 1.07 + SMAPI BIOS interface revision: 0.93 0.93 + video BIOS revision: 2.00 2.00 + slave controller revision: 1.10 1.10 + +600X (2645-4EU) + system ID: 74 74 74 + country code: 1 1 1 + system BIOS revision: 1.04 1.10 1.13 + system management BIOS revision: 1.01 1.06 1.07 + SMAPI BIOS interface revision: 0.93 0.93 0.93 + video BIOS revision: 2.00 2.00 2.00 + slave controller revision: 1.10 1.10 1.10 + +600X (2645-5EU) + system ID: 74 + country code: 1 + system BIOS revision: 1.04 + system management BIOS revision: 1.01 + SMAPI BIOS interface revision: 0.93 + video BIOS revision: 2.00 + slave controller revision: 1.10 + +600X (2645-5FU) + + system ID: 74 + country code: 1 + system BIOS revision: 1.18 + system management BIOS revision: 1.11 + SMAPI BIOS interface revision: 0.93 + video BIOS revision: 2.00 + slave controller revision: 1.10 + +600X (2645-7EG) + system ID: 74 + country code: 1 + system BIOS revision: 1.12 + system management BIOS revision: 1.07 + SMAPI BIOS interface revision: 0.93 + video BIOS revision: 2.00 + slave controller revision: 1.10 + +600X (2646-8EU) + system ID: 74 74 + country code: 1 1 + system BIOS revision: 1.13 1.20 + system management BIOS revision: 1.07 1.11 + SMAPI BIOS interface revision: 0.93 0.93 + video BIOS revision: 2.00 2.00 + slave controller revision: 1.10 1.10 + +760C + system ID: 14 + country code: 1 + system BIOS revision: 0.14 0.30 + system management BIOS revision: 1.15 1.22 + SMAPI BIOS interface revision: 0.78 + video BIOS revision: 1.00 + slave controller revision: 2.2 + +760E + system ID: 17 + country code: 1 + system BIOS revision: 0.47 + system management BIOS revision: 1.36 + SMAPI BIOS interface revision: 0.86 + video BIOS revision: 1.00 + slave controller revision: 1.8 + +760ED (9546-U3A) + system ID: 24 + country code: 1 + system BIOS revision: 0.56 0.57 + system management BIOS revision: 1.43 1.44 + SMAPI BIOS interface revision: 0.86 + video BIOS revision: 1.00 + slave controller revision: 1.8 + +"760EL" + system ID: 24 + country code: 1 + system BIOS revision: 0.59 + system management BIOS revision: 1.45 + SMAPI BIOS interface revision: 0.86 + video BIOS revision: 1.00 + slave controller revision: 1.12 + +760EL (9547) + system ID: 17 + country code: 1 + system BIOS revision: 0.45 + system management BIOS revision: 1.35 + SMAPI BIOS interface revision: 0.86 + video BIOS revision: 1.00 + slave controller revision: 1.12 + +760XD (9546) + system ID: 33 + country code: 1 + system BIOS revision: 0.50 + system management BIOS revision: 1.34 + SMAPI BIOS interface revision: 0.86 + video BIOS revision: 1.00 + slave controller revision: 1.12 + +760XL (9547-U9C) + system ID: 24 + country code: 1 + system BIOS revision: 0.57 + system management BIOS revision: 1.44 + SMAPI BIOS interface revision: 0.86 + video BIOS revision: 1.00 + slave controller revision: 1.12 + +765D (9546-U9H) + system ID: 33 + country code: 1 + system BIOS revision: 0.49 + system management BIOS revision: 1.33 + SMAPI BIOS interface revision: 0.86 + video BIOS revision: 1.00 + slave controller revision: 1.12 + +770 (9548) + system ID: 39 + country code: 1 + system BIOS revision: 1.26 + sys management BIOS revision: 2.06 + SMAPI BIOS interface revision: 0.90 + video BIOS revision: 1.21 + slave controller revision: 1.17 + +770 (9549-1A) + system ID: 39 + country code: 1 + system BIOS revision: 1.31 + system management BIOS revision: 2.12 + SMAPI BIOS interface revision: 0.90 + video BIOS revision: 1.22 + slave controller revision: 1.17 + +770 (9549-1AU) + system ID: 39 + country code: 1 + system BIOS revision: 1.32 + system management BIOS revision: 2.13 + SMAPI BIOS interface revision: 0.90 + video BIOS revision: 1.22 + slave controller revision: 1.17 + +770ED + system ID: 46 + country code: 1 + system BIOS revision: 1.31 + sys management BIOS revision: 2.12 + SMAPI BIOS interface revision: 0.90 + video BIOS revision: 1.22 + slave controller revision: 1.8 + +"770E/ED" (9549-5AU) + system ID: 46 + country code: 1 + system BIOS revision: 1.28 + system management BIOS revision: 2.10 + SMAPI BIOS interface revision: 0.90 + video BIOS revision: 1.22 + slave controller revision: 1.8 + +770X (9549-7B0) + system ID: 56 56 + country code: 1 1 + system BIOS revision: 1.01 1.09 + sys management BIOS revision: 1.01 1.07 + SMAPI BIOS interface revision: 0.92 0.92 + video BIOS revision: 1.24 1.27 + slave controller revision: (?) 1.7 + +770X (9549-7BU) + system ID: 56 + country code: 1 + system BIOS revision: 1.10 + sys management BIOS revision: 1.08 + SMAPI BIOS interface revision: 0.92 + video BIOS revision: 1.27 + slave controller revision: 1.7 + +770Z (9549-8AU) + system ID: 67 + country code: 1 + system BIOS revision: 1.01 + system management BIOS revision: 0.13 + SMAPI BIOS interface revision: 0.92 + video BIOS revision: 1.27 + slave controller revision: 1.6 + +770Z (9549-820) + system ID: 67 + country code: 1 + system BIOS revision: 1.03 + system management BIOS revision: 1.01 + SMAPI BIOS interface revision: 0.92 + video BIOS revision: 1.27 + slave controller revision: 1.6 + +A20, A30, T20 (2647-44U), T21, X20 (26621BK) + Many tpctl functions work on these new ThinkPad models, + but "--ib" isn't one of them. :( + +R30 + No SMAPI BIOS or Super I/O chip, so only tpctl -ic works. + + +------------------------------------------------------------------------- +Here is a thorough test of tpctl on an A30. + +(The following work as expected.) +tpctl --hibernate +tpctl --suspend +tpctl --standby +tpctl --pmb=high +tpctl --pmb=auto +tpctl --help + +tpctl --all + tpctl: SMAPI BIOS error 0x86 ("function is not supported") -- exiting. + +tpctl --info-all + tpctl: SMAPI BIOS error 0x86 ("function is not supported") -- exiting. + +tpctl --info-bios + tpctl: SMAPI BIOS error 0x86 ("function is not supported") -- exiting. + +tpctl --info-docking + information about docking station: + docking station ID: (not docked) + security key unlocked?: - + bus connected?: - + +tpctl --info-sensor + is: + the lid closed?: N + the keyboard open?: N + the AC adapter attached?: N + +tpctl --setup-all + setup of display: CMOS current + internal display enabled?: disable enable + crt display: enable disable + tv display: disable disable + 2ual display: enable enable + TV display selected?: N N + monitor detection ignored?: N N + setup of fn hotkey: + sticky Fn key supported?: N + sticky & locked Fn key supported?: Y + fn hotkey state: nonsticky + setup of pointing device: CMOS current + internal pointing device + controllable state?: Y Y + auto control supported?: Y Y + activation mode: auto-disable auto-disable + external pointing device + controllable state?: N N + activation mode: disable disable + setup of: CMOS + daylight saving time: disable + +tpctl --setup-display-all + setup of display: CMOS current + internal display enabled?: disable enable + crt display: enable disable + tv display: disable disable + 2ual display: enable enable + TV display selected?: N N + monitor detection ignored?: N N + +tpctl --setup-display-internal + setup of display: CMOS current + internal display enabled?: disable enable + +tpctl --setup-display-CRT + setup of display: CMOS current + crt display: enable disable + +tpctl --setup-display-TV + setup of display: CMOS current + tv display: disable disable + +tpctl --setup-display-TV-select + setup of display: CMOS current + TV display selected?: N N + +tpctl --setup-display-monitor-detection-ignore + setup of display: CMOS current + monitor detection ignored?: N N + +tpctl --setup-display-dual + setup of display: CMOS current + 2ual display: enable enable + +tpctl --setup-Fn-hotkey + setup of fn hotkey: + sticky Fn key supported?: N + sticky & locked Fn key supported?: Y + fn hotkey state: nonsticky + +tpctl --setup-pointing-device-all + setup of pointing device: CMOS current + internal pointing device + controllable state?: Y Y + auto control supported?: Y Y + activation mode: auto-disable auto-disable + external pointing device + controllable state?: N N + activation mode: disable disable + +tpctl --setup-pointing-device-internal + setup of pointing device: CMOS current + internal pointing device + controllable state?: Y Y + auto control supported?: Y Y + activation mode: auto-disable auto-disable + +tpctl --setup-pointing-device-external + setup of pointing device: CMOS current + external pointing device + controllable state?: N N + activation mode: disable disable + +tpctl --setup-daylight-saving-time + setup of: CMOS + daylight saving time: disable + +tpctl --pm-all + power management modes: + ac power expenditure: high + battery power expenditure: auto + RediSafe global mode overrides non-global mode?: Y + RediSafe globally enabled?: N + power management resume events: capability current + appointment-r.t.clock-initiated?: Y N (daily 00:00:00) + hardware-initiated?: Y Y + lid-opening-initiated?: Y Y + serial-RI-initiated?: Y N + power management sedative events: capability current + (SZRHO) (SZRHO) + hardware-or-software-initiated: SZ-HO SZ-HO + power-switch-initiated: ---HO ----O + lid-closure-initiated: -Z--- -Z--- + Standby-timer-initiated: ----- ----- + Zuspend-or-hibern.-timer-initiated: -Z-H- -Z--- + Hibernate-from-susp.-timer-init'd: ----- ----- + battery-low-initiated: -Z-H- -Z-H- + env'mt-exhausted-initiated: -Z--- -Z--- + power management timer modes: capability current + Standby timer: N N + Zuspend-or-hibernation timer: Y Y + Blank-internal-display timer: Y Y + drive power-down timer: Y Y + power management delay of Hibernate-from-suspend: 30 minutes + power management delays of Zuspend or hibernate: current + (specifiable in each power mode)? + ac power "manual" expenditure mode: Y 5 minutes + tpctl: SMAPI BIOS error 0x81 ("invalid parameter") -- exiting. + +tpctl --pm-mode-all + power management modes: + ac power expenditure: high + battery power expenditure: auto + RediSafe global mode overrides non-global mode?: Y + RediSafe globally enabled?: N + +tpctl --pm-mode-AC + power management modes: + ac power expenditure: high + +tpctl --pm-mode-battery + power management modes: + battery power expenditure: auto + +tpctl --pm-mode-RediSafe + power management modes: + RediSafe global mode overrides non-global mode?: Y + RediSafe globally enabled?: N + +tpctl --pm-mode-safe-suspend + power management modes: + RediSafe global mode overrides non-global mode?: Y + RediSafe globally enabled?: N + +tpctl --pm-resume-all + power management resume events: capability current + appointment-r.t.clock-initiated?: Y N (daily 00:00:00) + hardware-initiated?: Y Y + lid-opening-initiated?: Y Y + serial-RI-initiated?: Y N + +tpctl --pm-resume-appointment + power management resume events: capability current + appointment-r.t.clock-initiated?: Y N (daily 00:00:00) + +tpctl --pm-resume-hardware + power management resume events: capability current + h ardware-initiated?: Y Y + +tpctl --pm-resume-lid + power management resume events: capability current + lid-opening-initiated?: Y Y + +tpctl --pm-resume-serial-RI + power management resume events: capability current + serial-RI-initiated?: Y N + +tpctl --pm-sedation-all + power management sedative events: capability current + (SZRHO) (SZRHO) + hardware-or-software-initiated: SZ-HO SZ-HO + power-switch-initiated: ---HO ----O + lid-closure-initiated: -Z--- -Z--- + Standby-timer-initiated: ----- ----- + Zuspend-or-hibern.-timer-initiated: -Z-H- -Z--- + Hibernate-from-susp.-timer-init'd: ----- ----- + battery-low-initiated: -Z-H- -Z-H- + env'mt-exhausted-initiated: -Z--- -Z--- + +tpctl --pm-sedation-standby-timer + power management sedative events: capability current + (SZRHO) (SZRHO) + S tandby-timer-initiated: ----- ----- + +tpctl --pm-sedation-suspend-or-hibernate-timer + power management sedative events: capability current + (SZRHO) (SZRHO) + Z uspend-or-hibern.-timer-initiated: -Z-H- -Z--- + +tpctl --pm-sedation-hibernate-from-suspend-timer + power management sedative events: capability current + (SZRHO) (SZRHO) + Hibernate-from-susp.-timer-init'd: ----- ----- + +tpctl --pm-sedation-battery-low + power management sedative events: capability current + (SZRHO) (SZRHO) + battery-low-initiated: -Z-H- -Z-H- + +tpctl --pm-sedation-environment-exhausted + power management sedative events: capability current + (SZRHO) (SZRHO) + env'mt-exhausted-initiated: -Z--- -Z--- + +tpctl --pm-sedation-hardware-or-software + power management sedative events: capability current + (SZRHO) (SZRHO) + hardware-or-software-initiated: SZ-HO SZ-HO + +tpctl --pm-sedation-lid-closure + power management sedative events: capability current + (SZRHO) (SZRHO) + lid-closure-initiated: -Z--- -Z--- + +tpctl --pm-sedation-power-switch + power management sedative events: capability current + (SZRHO) (SZRHO) + power-switch-initiated: ---HO ----O + +tpctl --pm-timer-mode-all + power management timer modes: capability current + Standby timer: N N + Zuspend-or-hibernation timer: Y Y + Blank-internal-display timer: Y Y + drive power-down timer: Y Y + +tpctl --pm-timer-mode-blank-display + power management timer modes: capability current + Blank-internal-display timer: Y Y + +tpctl --pm-timer-mode-standby + power management timer modes: capability current + Standby timer: N N + +tpctl --pm-timer-mode-suspend-or-hibernate + power management timer modes: capability current + Zuspend-or-hibernation timer: Y Y + +tpctl --pm-timer-mode-drive-powerdown + power management timer modes: capability current + drive power-down timer: Y Y + +tpctl --pm-delay-all + power management delay of Hibernate-from-suspend: 30 minutes + power management delays of Zuspend or hibernate: current + (specifiable in each power mode)? + ac power "manual" expenditure mode: Y 5 minutes + tpctl: SMAPI BIOS error 0x81 ("invalid parameter") -- exiting. + +tpctl --pm-delay-hibernate-from-suspend + power management delay of Hibernate-from-suspend: 30 minutes + +tpctl --pm-delay-suspend-or-hibernate-all + power management delays of Zuspend or hibernate: current + (specifiable in each power mode)? + ac power "manual" expenditure mode: Y 5 minutes + tpctl: SMAPI BIOS error 0x81 ("invalid parameter") -- exiting. + +tpctl --pm-delay-suspend-or-hibernate-AC-manual + tpctl: unrecognized option `--pm-delay-suspend-or-hibernate-AC-manual' + tpctl: Error scanning options. Try 'tpctl --help'. + +tpctl --pm-delay-suspend-or-hibernate-battery-manual + tpctl: unrecognized option `--pm-delay-suspend-or-hibernate-battery-manual' + tpctl: Error scanning options. Try 'tpctl --help'. + +tpctl --pm-delay-suspend-or-hibernate-high + power management delays of Zuspend or hibernate: current + (specifiable in each power mode)? + "h igh" power expenditure mode: Y 60 minutes + +tpctl --pm-delay-suspend-or-hibernate-auto + power management delays of Zuspend or hibernate: current + (specifiable in each power mode)? + tpctl: SMAPI BIOS error 0x81 ("invalid parameter") -- exiting. + +tpctl --resource-all + resource state: ioaddr irq# able? mode/power + tpctl: module required for request is not loaded. + +tpctl --resource-floppy + resource state: ioaddr irq# able? mode/power + tpctl: module required for request is not loaded. + +tpctl --resource-parallel + resource state: ioaddr irq# able? mode/power + tpctl: module required for request is not loaded. + +tpctl --resource-serial-all + resource state: ioaddr irq# able? mode/power + tpctl: module required for request is not loaded. + +tpctl --resource-serial-1 + resource state: ioaddr irq# able? mode/power + tpctl: module required for request is not loaded. + +tpctl --resource-serial-2 + resource state: ioaddr irq# able? mode/power + tpctl: module required for request is not loaded. + +------------------------------------------------------------------------- diff -urNp thinkpad/drivers/char/thinkpad/rtcmosram.c 2.4.20pre8aa2/drivers/char/thinkpad/rtcmosram.c --- thinkpad/drivers/char/thinkpad/rtcmosram.c Thu Jan 1 01:00:00 1970 +++ 2.4.20pre8aa2/drivers/char/thinkpad/rtcmosram.c Wed Oct 2 06:42:00 2002 @@ -0,0 +1,351 @@ + +/********************************************************************* + * + * Filename: rtcmosram.c + * Description: rtcmosram is a kernel module that serves to interface + * with the RT/CMOS RAM in IBM ThinkPads + * Author: Thomas Hood + * Created: 24 July 1999 + * + * Please report bugs to the author ASAP. + * + * Copyright (c) 1999 J.D. Thomas Hood, All rights reserved + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * To receive a copy of the GNU General Public License, please write + * to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA + * + ********************************************************************/ + +#include "thinkpad_driver.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "thinkpad_common.h" +#include "rtcmosram.h" + + +/****** definitions ******/ + + +/****** declarations ******/ + +extern struct proc_dir_entry *thinkpad_ppde; + +#ifdef CONFIG_DEVFS_FS +static int rtcmosram_open( + struct inode * pinodeThe, + struct file * pfileThe +); +static int rtcmosram_release( + struct inode * pinodeThe, + struct file * pfileThe +); +static int rtcmosram_ioctl( + struct inode * pinodeThe, + struct file * pfileThe, + unsigned int uintIoctlNum, + unsigned long ulongIoctlArg +); +#endif + +/****** variables ******/ + +static const char _szMyName[] = "rtcmosram"; +static const char _szImName[] = "rtcmosram_do"; +static const char _szMyVersion[] = "3.0"; +static const char _szProcfile[] = "driver/thinkpad/rtcmosram"; +static struct resource *_presourceRtcmosram; + +MODULE_AUTHOR( "Thomas Hood" ); +MODULE_DESCRIPTION( "Driver for the RT CMOS RAM device on IBM ThinkPads" ); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,10) +MODULE_LICENSE( "GPL" ); +#endif + +#ifdef CONFIG_DEVFS_FS +static struct file_operations _fileopsRtcmosram = { + ioctl: rtcmosram_ioctl, + open: rtcmosram_open, + release: rtcmosram_release, + owner: THIS_MODULE +}; + +static devfs_handle_t _devfs_handleRtcmosram; +#endif + +/****** functions *******/ + +/* + * We use _p variants just for safety. The rtc_lock spinlock keeps us + * from fighting with the rtc driver. + */ +static byte cmos_getb( byte bWhere ) +{ + byte bGot; + unsigned long flags; + + spin_lock_irqsave(&rtc_lock,flags); + outb_p( bWhere, 0x70 ); + bGot = inb_p( 0x71 ); + outb_p( 0x0f, 0x70 ); /* required, according to Tech Ref */ + inb( 0x71 ); + spin_unlock_irqrestore(&rtc_lock,flags); + + return bGot; +} + + +static void cmos_putb( byte bWhat, byte bWhere ) +{ + unsigned long flags; + + spin_lock_irqsave(&rtc_lock,flags); + outb_p( bWhere, 0x70 ); + outb_p( bWhat, 0x71 ); + outb_p( 0x0F, 0x70 ); /* required, according to Tech Ref */ + inb( 0x71 ); + spin_unlock_irqrestore(&rtc_lock,flags); + + return; +} + + +static int rtcmosram_read_proc( + char *pchBuf, + char **ppchStart, + off_t off, + int intCount, + int *pintEof, + void *data +) { + return snprintf( + pchBuf, intCount, + "%s version %s accessing RT CMOS RAM at ioports 0x%x, 0x%x\n", + _szMyName, _szMyVersion, + 0x70, 0x71 + ); +} + + +int rtcmosram_do( + unsigned long ulongIoctlArg, + flag_t fCallerHasWritePerm +) { + rtcmosram_ioparm_t ioparmMy; + unsigned long ulRtnCopy; + + ulRtnCopy = copy_from_user( + (byte *)&ioparmMy, + (byte *)(rtcmosram_ioparm_t *)ulongIoctlArg, + sizeof( ioparmMy ) + ); + if ( ulRtnCopy ) return -EFAULT; + + switch ( ioparmMy.in.wFunc ) { + + case RTCMOSRAM_FUNC_GETDATA: { + rtcmosram_data_t dataThe; + int i; + + for ( i=0; idata), + (byte *)&dataThe, + sizeof(dataThe) + ); + if ( ulRtnCopy ) return -EFAULT; + + return 0; + } + + case RTCMOSRAM_FUNC_DAYLIGHTSAVINGTIME_ABLIFY: + if ( ! fCallerHasWritePerm ) + return -EACCES; + + if ( (flag_t)ioparmMy.in.dwParm1 ) { + cmos_putb( cmos_getb(0xB) | 1, 0xB ); + } else { + cmos_putb( cmos_getb(0xB) & ~1, 0xB ); + } + return 0; + + case RTCMOSRAM_FUNC_DAYLIGHTSAVINGTIME_GET: { + byte bGot; + bGot = cmos_getb( 0xB ); + ioparmMy.out.wRtn = 0; + ioparmMy.out.dwParm1 = (bGot & 1) ? (dword)1 : (dword)0; + ulRtnCopy = copy_to_user( + (byte *)(rtcmosram_ioparm_t *)ulongIoctlArg, + (byte *)&ioparmMy, + sizeof(ioparmMy) + ); + if ( ulRtnCopy ) return -EFAULT; + return 0; + } + + default: + printk(KERN_ERR + "%s: Function %d not recognized\n", + _szMyName, ioparmMy.in.wFunc + ); + return -EINVAL; + } /* switch */ + + return -ETHINKPAD_PROGRAMMING; /* we should not reach here */ +} + + +#ifdef CONFIG_DEVFS_FS +static int rtcmosram_open( + struct inode * pinodeThe, + struct file * pfileThe +) { + + return 0; +} + + +static int rtcmosram_release( + struct inode * pinodeThe, + struct file * pfileThe +) { + + return 0; +} + + +static flag_t caller_has_w( struct file * pfileThe ) +{ + return ((pfileThe->f_mode) & FMODE_WRITE) ? 1 : 0; +} + + +static int rtcmosram_ioctl( + struct inode * pinodeThe, + struct file * pfileThe, + unsigned int uintIoctlNum, + unsigned long ulongIoctlArg +) { + +#ifdef DEBUG_VERBOSE + printk( "%s: Doing ioctl number 0x%x\n", _szMyName, uintIoctlNum ); +#endif + + switch ( uintIoctlNum ) { + /* should return at the end of each case block */ + + case IOCTL_RTCMOSRAM_REQUEST: + return rtcmosram_do( + ulongIoctlArg, + caller_has_w( pfileThe ) + ); + + default: + /* ioctl number not recognized -- do nothing */ + return -ENOTTY; + + } /* switch */ + + return -ETHINKPAD_PROGRAMMING; /* We should never arrive here */ +} +#endif /* defined(CONFIG_DEVFS_FS) */ + +static int __init rtcmosram_init( void ) +{ + + _presourceRtcmosram = request_region( 0x70, 2, _szMyName ); + if ( _presourceRtcmosram == NULL ) { +#if 0 + printk(KERN_ERR + "%s: I/O ports for RT CMOS RAM not available -- aborting.\n", + _szMyName + ); + return -EBUSY; +#else + /* + * In some configs this region is already claimed by "rtc" + * Don't worry about it, since we take rtc_lock when we + * access the CMOS RAM + */ + printk(KERN_INFO + "%s: I/O ports for RT CMOS RAM not available, but ignoring this.\n", + _szMyName + ); +#endif + } + + if ( !thinkpad_ppde || !create_proc_read_entry( + _szProcfile, + S_IFREG | S_IRUGO, + NULL, + rtcmosram_read_proc, + NULL + ) ) { + printk(KERN_ERR + "%s: Could not create_proc_read_entry() /proc/%s\n", + _szMyName, _szProcfile + ); + } + /* proc entry created */ + +#ifdef CONFIG_DEVFS_FS + _devfs_handleRtcmosram = devfs_register( + NULL /* dir */, + "thinkpad/rtcmosram", + DEVFS_FL_DEFAULT | DEVFS_FL_AUTO_DEVNUM, + 0 /* major */, 0 /* minor */, + S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH, + &_fileopsRtcmosram, + NULL /* info */ + ); + if ( _devfs_handleRtcmosram == NULL ) { + printk(KERN_ERR "%s: Could not devfs_register(). Aborting.\n", _szMyName ); + return -EIO; + } + /* devfs entry created */ +#endif + + inter_module_register( _szImName, THIS_MODULE, &rtcmosram_do ); + + return 0; +} + + +static void __exit rtcmosram_exit( void ) +{ + + inter_module_unregister( _szImName ); + +#ifdef CONFIG_DEVFS_FS + devfs_unregister( _devfs_handleRtcmosram ); +#endif + + remove_proc_entry( _szProcfile, NULL ); + + if ( _presourceRtcmosram != NULL ) release_resource( _presourceRtcmosram ); + + return; +} + +module_init(rtcmosram_init); +module_exit(rtcmosram_exit); diff -urNp thinkpad/drivers/char/thinkpad/rtcmosram.h 2.4.20pre8aa2/drivers/char/thinkpad/rtcmosram.h --- thinkpad/drivers/char/thinkpad/rtcmosram.h Thu Jan 1 01:00:00 1970 +++ 2.4.20pre8aa2/drivers/char/thinkpad/rtcmosram.h Wed Oct 2 06:42:00 2002 @@ -0,0 +1,198 @@ + +/********************************************************************* + * + * Filename: rtcmosram.h + * Description: header file for the rtcmosram driver + * Author: Thomas Hood + * Created: 24 July 1999 + * + * Please report bugs to the author ASAP. + * + * Copyright (c) 1999 J.D. Thomas Hood, All rights reserved + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * To receive a copy of the GNU General Public License, please write + * to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA + * + ********************************************************************/ + +#ifndef __RTCMOSRAM_H__ +#define __RTCMOSRAM_H__ + +/****** defines ******/ + +#define RTCMOSRAM_FUNC_GETDATA (0) +#define RTCMOSRAM_FUNC_DAYLIGHTSAVINGTIME_ABLIFY (1) +#define RTCMOSRAM_FUNC_DAYLIGHTSAVINGTIME_GET (2) + +/****** typedefs ******/ + +typedef struct _rtcmosram_data_t { + byte bSeconds; /* 0x00 */ + byte bSecondAlarm; /* 0x01 */ + byte bMinutes; /* 0x02 */ + byte bMinuteAlarm; /* 0x03 */ + byte bHours; /* 0x04 */ + byte bHourAlarm; /* 0x05 */ + byte bDayOfWeek; /* 0x06 */ + byte bDateOfMonth; /* 0x07 */ + byte bMonth; /* 0x08 */ + byte bYear; /* 0x09 */ + byte bStatusA; /* 0x0A */ + byte bStatusB; /* 0x0B */ + byte bStatusC; /* 0x0C */ + byte bStatusD; /* 0x0D */ + byte bStatusDiag; /* 0x0E */ + byte bStatusShutdown; /* 0x0F */ + byte bDisketteDriveType; /* 0x10 */ + byte bHardDiskDrive23Type;/* 0x11 */ + byte bHardDiskDrive01Type;/* 0x12 */ + byte bReserved13; /* 0x13 */ + byte bEquipment; /* 0x14 */ + byte bSizeBaseMemLow; /* 0x15 */ /* Note that there is a word boundary */ + byte bSizeBaseMemHigh; /* 0x16 */ /* between the two halves of this ! */ + byte bSizeExpMemLow; /* 0x17 */ /* Note that there is a word boundary */ + byte bSizeExpMemHigh; /* 0x18 */ /* between the two halves of this ! */ + byte bReserved19; /* 0x19 */ + byte bReserved1A; /* 0x1A */ + byte bHardDiskDrive2Type;/* 0x1B */ + byte bHardDiskDrive3Type;/* 0x1C */ + byte bReserved1D; /* 0x1D */ + byte bReserved1E; /* 0x1E */ + byte bReserved1F; /* 0x1F */ + byte bReserved20; /* 0x20 */ + /* On the ThinkPad 600 21U, the low two bits of bReserved20 + * record the internal pointing device setup: + * 0:enable 1:disable 2:autodisable */ + byte bReserved21; /* 0x21 */ + byte bReserved22; /* 0x22 */ + byte bReserved23; /* 0x23 */ + byte bReserved24; /* 0x24 */ + byte bReserved25; /* 0x25 */ + byte bReserved26; /* 0x26 */ + byte bReserved27; /* 0x27 */ + byte bReserved28; /* 0x28 */ + byte bReserved29; /* 0x29 */ + byte bReserved2A; /* 0x2A */ + byte bReserved2B; /* 0x2B */ + byte bReserved2C; /* 0x2C */ + byte bReserved2D; /* 0x2D */ + byte bConfigChecksumHigh;/* 0x2E */ + byte bConfigChecksumLow; /* 0x2F */ + word wSizeUsableMem; /* 0x30,0x31 */ + bcd8_t bcd8DateCentury; /* 0x32 */ + byte bReserved33; /* 0x33 */ + byte bReserved34; /* 0x34 */ + byte bReserved35; /* 0x35 */ + byte bReserved36; /* 0x36 */ + byte bReserved37; /* 0x37 */ + byte bReserved38; /* 0x38 */ + byte bReserved39; /* 0x39 */ + byte bReserved3A; /* 0x3A */ + byte bReserved3B; /* 0x3B */ + byte bReserved3C; /* 0x3C */ + byte bReserved3D; /* 0x3D */ + byte bReserved3E; /* 0x3E */ + byte bReserved3F; /* 0x3F */ + byte bReserved40; /* 0x40 */ + byte bReserved41; /* 0x41 */ + byte bReserved42; /* 0x42 */ + byte bReserved43; /* 0x43 */ + byte bReserved44; /* 0x44 */ + byte bReserved45; /* 0x45 */ + byte bReserved46; /* 0x46 */ + byte bReserved47; /* 0x47 */ + byte bReserved48; /* 0x48 */ + byte bReserved49; /* 0x49 */ + byte bReserved4A; /* 0x4A */ + byte bReserved4B; /* 0x4B */ + byte bReserved4C; /* 0x4C */ + byte bReserved4D; /* 0x4D */ + byte bReserved4E; /* 0x4E */ + byte bReserved4F; /* 0x4F */ + byte bReserved50; /* 0x50 */ + byte bReserved51; /* 0x51 */ + byte bReserved52; /* 0x52 */ + byte bReserved53; /* 0x53 */ + byte bReserved54; /* 0x54 */ + byte bReserved55; /* 0x55 */ + byte bReserved56; /* 0x56 */ + byte bReserved57; /* 0x57 */ + byte bReserved58; /* 0x58 */ + byte bReserved59; /* 0x59 */ + byte bReserved5A; /* 0x5A */ + byte bReserved5B; /* 0x5B */ + byte bReserved5C; /* 0x5C */ + byte bReserved5D; /* 0x5D */ + byte bReserved5E; /* 0x5E */ + byte bReserved5F; /* 0x5F */ + byte bReserved60; /* 0x60 */ + byte bReserved61; /* 0x61 */ + byte bReserved62; /* 0x62 */ + byte bReserved63; /* 0x63 */ + byte bReserved64; /* 0x64 */ + byte bReserved65; /* 0x65 */ + byte bReserved66; /* 0x66 */ + byte bReserved67; /* 0x67 */ + byte bReserved68; /* 0x68 */ + byte bReserved69; /* 0x69 */ + byte bReserved6A; /* 0x6A */ + byte bReserved6B; /* 0x6B */ + byte bReserved6C; /* 0x6C */ + byte bReserved6D; /* 0x6D */ + byte bReserved6E; /* 0x6E */ + byte bReserved6F; /* 0x6F */ + byte bReserved70; /* 0x70 */ + byte bReserved71; /* 0x71 */ + byte bReserved72; /* 0x72 */ + byte bReserved73; /* 0x73 */ + byte bReserved74; /* 0x74 */ + byte bReserved75; /* 0x75 */ + byte bReserved76; /* 0x76 */ + byte bReserved77; /* 0x77 */ + byte bReserved78; /* 0x78 */ + byte bReserved79; /* 0x79 */ + byte bReserved7A; /* 0x7A */ + byte bReserved7B; /* 0x7B */ + byte bReserved7C; /* 0x7C */ + byte bReserved7D; /* 0x7D */ + byte bReserved7E; /* 0x7E */ + byte bReserved7F; /* 0x7F */ +} rtcmosram_data_t __attribute__ (( packed )); + +typedef struct _rtcmosram_inparm_t { + word wFunc; + word wParm0; + dword dwParm1; +} rtcmosram_inparm_t; + +typedef struct _rtcmosram_outparm_t { + word wRtn; + word wParm0; + dword dwParm1; +} rtcmosram_outparm_t; + +typedef union _rtcmosram_ioparm_t { + rtcmosram_inparm_t in; + rtcmosram_outparm_t out; + rtcmosram_data_t data; +} rtcmosram_ioparm_t; + +/****** declarations ******/ + +int rtcmosram_do( + unsigned long ulongIoctlArg, + flag_t fCallerHasWritePerm +); + +#endif diff -urNp thinkpad/drivers/char/thinkpad/smapi.h 2.4.20pre8aa2/drivers/char/thinkpad/smapi.h --- thinkpad/drivers/char/thinkpad/smapi.h Thu Jan 1 01:00:00 1970 +++ 2.4.20pre8aa2/drivers/char/thinkpad/smapi.h Wed Oct 2 06:42:00 2002 @@ -0,0 +1,54 @@ + +/********************************************************************* + * + * Filename: smapi.h + * Description: header file for the smapi driver + * Author: Thomas Hood + * Created: 19 July 1999 + * + * Please report bugs to the author ASAP. + * + * Copyright (c) 1999 J.D. Thomas Hood, All rights reserved + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * To receive a copy of the GNU General Public License, please write + * to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA + * + ********************************************************************/ + +#ifndef __SMAPI_H__ +#define __SMAPI_H__ + +#include "smapibios.h" + + +/****** typedefs ******/ + +typedef smb_inparm_t smapi_inparm_t; +typedef smb_outparm_t smapi_outparm_t; + +typedef union _smapi_ioparm_t { + smapi_inparm_t in; + smapi_outparm_t out; +} smapi_ioparm_t; + + +/****** declarations ******/ + +int smapi_do( + unsigned long ulongIoctlArg, + flag_t fCallerHasWritePerm +); + + +#endif diff -urNp thinkpad/drivers/char/thinkpad/smapi_call.S 2.4.20pre8aa2/drivers/char/thinkpad/smapi_call.S --- thinkpad/drivers/char/thinkpad/smapi_call.S Thu Jan 1 01:00:00 1970 +++ 2.4.20pre8aa2/drivers/char/thinkpad/smapi_call.S Wed Oct 2 06:42:00 2002 @@ -0,0 +1,55 @@ + +#********************************************************************* +#* +#* Filename: smapi_call.s +#* Version: 1.0 +#* Author: Thomas Hood +#* Created: 19 July 1999 +#* +#* Please report bugs to the author ASAP. +#* +#* Copyright (c) 1999 J.D. Thomas Hood, All rights reserved +#* +#* This program is free software; you can redistribute it and/or +#* modify it under the terms of the GNU General Public License as +#* published by the Free Software Foundation; either version 2 of +#* the License, or (at your option) any later version. +#* +#* This program is distributed in the hope that it will be useful, +#* but WITHOUT ANY WARRANTY; without even the implied warranty of +#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +#* GNU General Public License for more details. +#* +#* To receive a copy of the GNU General Public License, please write +#* to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, +#* Boston, MA 02111-1307 USA +#* +#********************************************************************/ + + .align +farpxSmapiBios: # far pointer to the SMAPI function + .globl _dwAddressSmapiBios +_dwAddressSmapiBios: .long 0xc00fe9c4 # offset; should be set up by caller +wSegSmapiBios: .word 0x18 # cs is stored here by us before call + + .globl SMAPI_BIOS_do + .align +SMAPI_BIOS_do: + pushl %ebp + movl %esp,%ebp + + movl 0xC(%ebp),%eax + pushl %ds + pushl %eax + movl 0x8(%ebp),%eax + pushl %ds + pushl %eax + + movl $0,%eax + movw %cs,(wSegSmapiBios) + lcall *(farpxSmapiBios) + + add $0x10,%esp + popl %ebp + ret + diff -urNp thinkpad/drivers/char/thinkpad/smapi_call.h 2.4.20pre8aa2/drivers/char/thinkpad/smapi_call.h --- thinkpad/drivers/char/thinkpad/smapi_call.h Thu Jan 1 01:00:00 1970 +++ 2.4.20pre8aa2/drivers/char/thinkpad/smapi_call.h Wed Oct 2 06:42:00 2002 @@ -0,0 +1,36 @@ + +/********************************************************************* + * + * Filename: smapi_call.h + * Description: header file for the smapi call code + * Author: Thomas Hood + * Created: 19 July 1999 + * + * Please report bugs to the author ASAP. + * + * Copyright (c) 1999 J.D. Thomas Hood, All rights reserved + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * To receive a copy of the GNU General Public License, please write + * to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA + * + ********************************************************************/ + +#ifndef __SMAPI_CALL_H__ +#define __SMAPI_CALL_H__ + +/****** declarations ******/ +int SMAPI_BIOS_do( smapi_inparm_t * , smapi_outparm_t * ); +extern dword _dwAddressSmapiBios; + +#endif diff -urNp thinkpad/drivers/char/thinkpad/smapi_core.c 2.4.20pre8aa2/drivers/char/thinkpad/smapi_core.c --- thinkpad/drivers/char/thinkpad/smapi_core.c Thu Jan 1 01:00:00 1970 +++ 2.4.20pre8aa2/drivers/char/thinkpad/smapi_core.c Wed Oct 2 06:42:00 2002 @@ -0,0 +1,421 @@ + +/********************************************************************* + * + * Filename: smapi_core.c + * Description: smapi is a kernel module that serves to interface + * with the SMAPI BIOS in IBM ThinkPads + * Author: Thomas Hood + * Created: 19 July 1999 + * + * Please report bugs to the author ASAP. + * + * Copyright (c) 1999 J.D. Thomas Hood, All rights reserved + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * To receive a copy of the GNU General Public License, please write + * to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA + * + ********************************************************************/ + +#include "thinkpad_driver.h" + +#include +#include +#include +#include +#include +#include +#include +#include "thinkpad_common.h" +#include "smapi.h" +#include "smapi_call.h" + + +/****** definitions ******/ + + +/****** declarations ******/ + +extern struct proc_dir_entry *thinkpad_ppde; + +#ifdef CONFIG_DEVFS_FS +static int smapi_open( + struct inode * pinodeThe, + struct file * pfileThe +); +static int smapi_release( + struct inode * pinodeThe, + struct file * pfileThe +); +static int smapi_ioctl( + struct inode * pinodeThe, + struct file * pfileThe, + unsigned int uintIoctlNum, + unsigned long ulongIoctlArg +); +#endif + +/****** variables ******/ + +static const char _szMyName[] = "smapi"; +static const char _szImName[] = "smapi_do"; +static const char _szMyVersion[] = "3.1"; +static const char _szProcfile[] = "driver/thinkpad/smapi"; + +MODULE_AUTHOR( "Thomas Hood" ); +MODULE_DESCRIPTION( "Driver for the SMAPI BIOS on IBM ThinkPads" ); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,10) +MODULE_LICENSE( "GPL" ); +#endif + +#ifdef CONFIG_DEVFS_FS +static struct file_operations _fileopsSmapi = { + ioctl: smapi_ioctl, + open: smapi_open, + release: smapi_release, + owner: THIS_MODULE +}; + +static devfs_handle_t _devfs_handleSmapi; +#endif + +/****** functions *******/ + + +static flag_t smapi_req_need_w( byte bFunc, byte bSubFunc ) +{ + + switch ( bFunc ) { + case 0x00: return 0; + case 0x10: if ( bSubFunc == 0x00 ) return 0; break; + case 0x11: if ( bSubFunc == 0x02 ) return 0; break; + case 0x13: if ( bSubFunc == 0x02 ) return 0; break; + case 0x22: + if ( bSubFunc == 0x00 ) return 0; + if ( bSubFunc == 0x02 ) return 0; + break; + case 0x30: if ( bSubFunc == 0x00 ) return 0; break; + case 0x31: if ( bSubFunc == 0x00 ) return 0; break; + case 0x32: + if ( bSubFunc == 0x00 ) return 0; + if ( bSubFunc == 0x02 ) return 0; + if ( bSubFunc == 0x06 ) return 0; + break; + case 0x33: if ( bSubFunc == 0x00 ) return 0; break; + case 0x34: + if ( bSubFunc == 0x00 ) return 0; + if ( bSubFunc == 0x02 ) return 0; + break; + default: + return 1; + } + + return 1; +} + + +static byte byte_of_bcd8( bcd8_t bcd8The ) +{ + byte bTens, bUnits; + + bUnits = (byte)bcd8The & 0xF; + bTens = (byte)(bcd8The & 0xF0) >> 4; + + if ( bUnits > 9 || bTens > 9 ) { + return 0xFF; + } + + return bUnits + (bTens * 10); +} + + +static int smapi_read_proc( + char *pchBuf, + char **ppchStart, + off_t off, + int intCount, + int *pintEof, + void *data +) { + int intRtn; + bcd8_t bcd8SysMgmtHigh, bcd8SysMgmtLow; + bcd8_t bcd8SMAPIIfaceHigh, bcd8SMAPIIfaceLow; + word wSysMgmtBiosRevMajor, wSysMgmtBiosRevMinor; + word wSmapiBiosIfaceRevMajor, wSmapiBiosIfaceRevMinor; + smb_inparm_t inparmMy; + smb_outparm_t outparmMy; + + inparmMy.bFunc = (byte) 0; + inparmMy.bSubFunc = (byte) 0; + + intRtn = SMAPI_BIOS_do( &inparmMy, &outparmMy ); + if ( intRtn ) { + return snprintf( + pchBuf, intCount, + "%s module ver. %s interfacing to 32-bit protected mode system management BIOS:\n" + " error getting BIOS information\n", + _szMyName, _szMyVersion + ); + } + + bcd8SysMgmtHigh = (bcd8_t)( (outparmMy.dwParm4 >> 8) & 0xFF ); + bcd8SysMgmtLow = (bcd8_t)( outparmMy.dwParm4 & 0xFF ); + wSysMgmtBiosRevMajor = (word) byte_of_bcd8( bcd8SysMgmtHigh ); + wSysMgmtBiosRevMinor = (word) byte_of_bcd8( bcd8SysMgmtLow ); + + bcd8SMAPIIfaceHigh = (bcd8_t)( (outparmMy.dwParm5 >> 8) & 0xFF ); + bcd8SMAPIIfaceLow = (bcd8_t)( outparmMy.dwParm5 & 0xFF ); + wSmapiBiosIfaceRevMajor = (word) byte_of_bcd8( bcd8SMAPIIfaceHigh ); + wSmapiBiosIfaceRevMinor = (word) byte_of_bcd8( bcd8SMAPIIfaceLow ); + + return snprintf( + pchBuf, intCount, + "%s module ver. %s interfacing to 32-bit protected mode System-Management-API BIOS ver. %d.%d at address 0x%lx through interface version %d.%d\n", + _szMyName, _szMyVersion, + wSysMgmtBiosRevMajor, wSysMgmtBiosRevMinor, + (unsigned long) _dwAddressSmapiBios, + wSmapiBiosIfaceRevMajor, wSmapiBiosIfaceRevMinor + ); +} + +int smapi_do( + unsigned long ulongIoctlArg, + flag_t fCallerHasWritePerm +) { + smb_inparm_t inparmMy; + smb_outparm_t outparmMy; + unsigned long ulRtnCopy; + int intRtnDo; + + ulRtnCopy = copy_from_user( + &inparmMy, + (byte *)ulongIoctlArg, + sizeof( inparmMy ) + ); + if ( ulRtnCopy ) return -EFAULT; + + if ( smapi_req_need_w( inparmMy.bFunc, inparmMy.bSubFunc ) && !fCallerHasWritePerm ) { + printk(KERN_ERR + "%s: Caller does not have permission to make this request of SMAPI\n", + _szMyName + ); + return -EACCES; + } + + intRtnDo = SMAPI_BIOS_do( &inparmMy , &outparmMy ); + + if ( intRtnDo != outparmMy.bRc ) { + static unsigned char count; /* = 0 */ + if ( !count++ ) + printk(KERN_INFO "%s: SMAPI BIOS return codes differ!\n", _szMyName ); + } + + ulRtnCopy = copy_to_user( + (byte *)ulongIoctlArg, + &outparmMy, + sizeof( inparmMy ) + ); + if ( ulRtnCopy ) return -EFAULT; + + return outparmMy.bRc ? -ETHINKPAD_SUBDRIVER : 0; +} + + +#ifdef CONFIG_DEVFS_FS +static int smapi_open( + struct inode * pinodeThe, + struct file * pfileThe +) { + + return 0; +} + + +static int smapi_release( + struct inode * pinodeThe, + struct file * pfileThe +) { + + return 0; +} + + +static flag_t caller_has_w( struct file * pfileThe ) +{ + return ((pfileThe->f_mode) & FMODE_WRITE) ? 1 : 0; +} + + +static int smapi_ioctl( + struct inode * pinodeThe, + struct file * pfileThe, + unsigned int uintIoctlNum, + unsigned long ulongIoctlArg +) { + +#ifdef DEBUG_VERBOSE + printk( "%s: Doing ioctl number 0x%x\n", _szMyName, uintIoctlNum ); +#endif + + switch ( uintIoctlNum ) { + /* should return at the end of each case block */ + + case IOCTL_SMAPI_REQUEST: + return smapi_do( + ulongIoctlArg, + caller_has_w( pfileThe ) + ); + + default: + /* ioctl number not recognized -- do nothing */ + return -ENOTTY; + + } /* switch */ + + return -ETHINKPAD_PROGRAMMING; /* We should never arrive here */ +} +#endif /* defined(CONFIG_DEVFS_FS) */ + + +/* + * Returns a pointer to the first SMAPI BIOS header found + * with correct checksum + * Returns NULL if no header found with correct checksum + */ +static smb_header_t * locate_smb_header( void ) +{ + smb_header_t *pheaderSearch, *pheaderLim; + + /*** Search for the sig ***/ + pheaderSearch = (smb_header_t *) phys_to_virt(0xF0000); + pheaderLim = (smb_header_t *) phys_to_virt(0xFFFF0); + + while ( 1 ) { + + if ( + ( pheaderSearch->bSig[0] == '$') && + ( pheaderSearch->bSig[1] == 'S') && + ( pheaderSearch->bSig[2] == 'M') && + ( pheaderSearch->bSig[3] == 'B') + ) { + /* We found a signature */ + /*** check the header checksum ***/ + byte chksum; + int cnt; + + chksum = 0; + for ( cnt=0; cnt < pheaderSearch->bLen; cnt++ ) { + chksum += (byte)(pheaderSearch->bSig[cnt]); + } + if ( chksum == 0 ) /* good checksum */ + return pheaderSearch; + + /* bad checksum */ + } + + /*** Keep searching ***/ + pheaderSearch++ ; + if ( pheaderSearch > pheaderLim ) { + /* search space exhausted */ + return (smb_header_t *) NULL; + } + + } /* while */ + +} + + +static int __init smapi_init( void ) +{ + smb_header_t * pheaderFound; + + /*** locate SMAPI BIOS header ***/ + pheaderFound = locate_smb_header(); + if ( pheaderFound == NULL ) { + printk(KERN_ERR + "%s: No SMAPI BIOS header was found. :-(\n", + _szMyName + ); + return -ETHINKPAD_HW_NOT_FOUND; + } + /* a header was located */ + + if ( ! (pheaderFound->wInfo & 4) ) { + printk(KERN_ERR + "%s: The SMAPI BIOS does not support 32-bit protected mode. :-(\n", + _szMyName + ); + return -ETHINKPAD_HW_NOT_FOUND; + } + /* a header was located and it supports 32-bit protected mode */ + + _dwAddressSmapiBios = (dword) phys_to_virt( + pheaderFound->dwP32_base + + pheaderFound->dwP32_offset + ); + + printk(KERN_INFO + "%s: 32-bit protected mode SMAPI BIOS found. :-)\n", + _szMyName + ); + + if ( !thinkpad_ppde || !create_proc_read_entry( + _szProcfile, + S_IFREG | S_IRUGO, + NULL, + smapi_read_proc, + NULL + ) ) { + printk(KERN_ERR "%s: Could not create_proc_read_entry() /proc/%s\n", _szMyName, _szProcfile ); + } + /* proc entry created */ + +#ifdef CONFIG_DEVFS_FS + _devfs_handleSmapi = devfs_register( + NULL /* dir */, + "thinkpad/smapi", + DEVFS_FL_DEFAULT | DEVFS_FL_AUTO_DEVNUM, + 0 /* major */, 0 /* minor */, + S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH, + &_fileopsSmapi, + NULL /* info */ + ); + if ( _devfs_handleSmapi == NULL ) { + printk(KERN_ERR "%s: Could not devfs_register(). Aborting.\n", _szMyName ); + return -EIO; + } + /* devfs entry created */ +#endif + + inter_module_register( _szImName, THIS_MODULE, &smapi_do ); + + return 0; +} + + +static void __exit smapi_exit( void ) +{ + + inter_module_unregister( _szImName ); + +#ifdef CONFIG_DEVFS_FS + devfs_unregister( _devfs_handleSmapi ); +#endif + + remove_proc_entry( _szProcfile, NULL ); + + return; +} + +module_init(smapi_init); +module_exit(smapi_exit); diff -urNp thinkpad/drivers/char/thinkpad/smapibios.h 2.4.20pre8aa2/drivers/char/thinkpad/smapibios.h --- thinkpad/drivers/char/thinkpad/smapibios.h Thu Jan 1 01:00:00 1970 +++ 2.4.20pre8aa2/drivers/char/thinkpad/smapibios.h Wed Oct 2 06:42:00 2002 @@ -0,0 +1,93 @@ + +/********************************************************************* + * + * Filename: smapibios.h + * Description: header file for the IBM SMAPI BIOS + * Author: Thomas Hood + * Created: 14 July 1999 + * + * Please report bugs to the author ASAP. + * + * Copyright (c) 1999 J.D. Thomas Hood, All rights reserved + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * To receive a copy of the GNU General Public License, please write + * to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA + * + ********************************************************************/ + +#ifndef __SMAPIBIOS_H__ +#define __SMAPIBIOS_H__ + +/* Is included by smapi.h */ + +/*** SMAPI BIOS error codes ***/ +#define ERR_SMB_MIN ((byte)0x01) +#define ERR_SMB_FUNC_NOT_AVAIL ((byte)0x53) +#define ERR_SMB_FUNC_NOT_SUPPORTED ((byte)0x86) +#define ERR_SMB_SYSTEM_ERROR ((byte)0x90) +#define ERR_SMB_SYSTEM_INVALID ((byte)0x91) +#define ERR_SMB_SYSTEM_BUSY ((byte)0x92) +#define ERR_SMB_DEVICE_ERROR ((byte)0xA0) +#define ERR_SMB_DEVICE_BUSY ((byte)0xA1) +#define ERR_SMB_DEVICE_NOT_ATTACHED ((byte)0xA2) +#define ERR_SMB_DEVICE_DISABLED ((byte)0xA3) +#define ERR_SMB_PARM_INVALID ((byte)0x81) +#define ERR_SMB_PARM_OUT_OF_RANGE ((byte)0xA4) +#define ERR_SMB_PARM_NOT_ACCEPTED ((byte)0xA5) +#define ERR_SMB_MAX ((byte)0xFF) + +/* The following structure definitions come from the ThinkPad 560Z Technical Reference */ + +/*** SMAPI BIOS header ***/ +typedef struct _smb_header { + byte bSig[4]; /* signature */ + byte bVerMajor; /* major version */ + byte bVerMinor; /* minor version */ + byte bLen; /* length */ + byte bChksum; /* checksum */ + word wInfo; /* information word */ + word wRsv1; /* reserve 1 */ + word wR_offset; /* real mode offset */ + word wR_segment; /* real mode segment */ + word wRsv2; /* reserve 2 */ + word wP16_offset; /* 16-bit protect mode offset */ + dword dwP16_base; /* 16-bit protect mode base address */ + dword dwP32_offset; /* 32-bit protect mode offset */ + dword dwP32_base; /* 32-bit protect mode base address */ +} smb_header_t; + +/*** SMAPI BIOS call input parameters ***/ +typedef struct _smb_inparm { + byte bFunc; + byte bSubFunc; + word wParm1; + word wParm2; + word wParm3; + dword dwParm4; + dword dwParm5; +} smb_inparm_t; + + +/*** SMAPI BIOS call output parameters ***/ +typedef struct _smb_outparm { + byte bRc; + byte bSubRc; + word wParm1; + word wParm2; + word wParm3; + dword dwParm4; + dword dwParm5; +} smb_outparm_t; + +#endif diff -urNp thinkpad/drivers/char/thinkpad/superio.c 2.4.20pre8aa2/drivers/char/thinkpad/superio.c --- thinkpad/drivers/char/thinkpad/superio.c Thu Jan 1 01:00:00 1970 +++ 2.4.20pre8aa2/drivers/char/thinkpad/superio.c Wed Oct 2 06:42:00 2002 @@ -0,0 +1,1011 @@ + +/********************************************************************* + * + * Filename: superio.c + * Description: kernel module that configures the PC97338 + * Super I/O chip present in some ThinkPads + * Author: Thomas Hood + * Reference: National Semiconductor PC87338/PC97338 data sheet. November, 1998. + * Created: 19 July 1999 + * + * Please report bugs to the author ASAP. + * + * Copyright (c) 1999 J.D. Thomas Hood, All rights reserved + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * To receive a copy of the GNU General Public License, please write + * to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA + * + ********************************************************************/ + +#include "thinkpad_driver.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include "thinkpad_common.h" +#include "superio.h" + + +/****** definitions ******/ + + +/****** declarations ******/ + +extern struct proc_dir_entry *thinkpad_ppde; + +#ifdef CONFIG_DEVFS_FS +static int superio_open( + struct inode * pinodeThe, + struct file * pfileThe +); +static int superio_release( + struct inode * pinodeThe, + struct file * pfileThe +); +static int superio_ioctl( + struct inode * pinodeThe, + struct file * pfileThe, + unsigned int uintIoctlNum, + unsigned long ulongIoctlArg +); +#endif + +/****** variables ******/ +static const char _szMyName[] = "superio"; +static const char _szImName[] = "superio_do"; +static const char _szMyVersion[] = "3.0"; +static const char _szProcfile[] = "driver/thinkpad/superio"; +static word _wPortIndex, _wPortData; +static struct resource *_presourceSuperio; + +MODULE_AUTHOR( "Thomas Hood" ); +MODULE_DESCRIPTION( "Driver for the Super I/O chip on IBM ThinkPads" ); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,10) +MODULE_LICENSE( "GPL" ); +#endif + +#ifdef CONFIG_DEVFS_FS +static struct file_operations _fileopsSuperio = { + ioctl: superio_ioctl, + open: superio_open, + release: superio_release, + owner: THIS_MODULE +}; + +static devfs_handle_t _devfs_handleSuperio; +#endif + +/****** functions ******/ + +/* + * We use _p variant of outb just for safety + * getregb and putregb use the global variables + * _wPortIndex and _wPortData + */ +static byte getregb( byte bWhere ) +{ + byte bGot; + unsigned long flags; + + save_flags( flags ); cli(); + outb_p( bWhere, _wPortIndex ); + bGot = inb( _wPortData ); + restore_flags( flags ); + + return bGot; +} + + +static void putregb( byte bWhat, byte bWhere ) +{ + unsigned long flags; + + save_flags( flags ); cli(); + outb_p( bWhere, _wPortIndex ); + outb( bWhat, _wPortData ); + restore_flags( flags ); + + return; +} + + +static int get_leg_regs( superio_outparm_t *poutparmThe ) +{ + byte bTmp, bID, bRev; + + poutparmThe->dwParm1 = 0; + poutparmThe->dwParm2 = 0; + + bTmp = getregb( 8 ); /* chip ID and rev */ + bID = bTmp & ~7; + bRev = bTmp & 7; + poutparmThe->wParm0 = (((word)bID)<<8) | bRev; + + bTmp = getregb( 0 ); /* enable */ + poutparmThe->dwParm1 |= (dword)bTmp; + + bTmp = getregb( 1 ); /* address */ + poutparmThe->dwParm1 |= ((dword)bTmp) << 8; + + bTmp = getregb( 2 ); /* power and test */ + poutparmThe->dwParm1 |= ((dword)bTmp) << 16; + + bTmp = getregb( 3 ); /* function control */ + poutparmThe->dwParm1 |= ((dword)bTmp) << 24; + + bTmp = getregb( 4 ); /* printer control */ + poutparmThe->dwParm2 |= (dword)bTmp; + +#if 0 + bTmp = getregb( 5 ); /* not used */ + poutparmThe->dwParm2 |= ((dword)bTmp) << 8; +#endif + + bTmp = getregb( 6 ); /* power management */ + poutparmThe->dwParm2 |= ((dword)bTmp) << 16; + + bTmp = getregb( 7 ); /* tape, ser, par config */ + poutparmThe->dwParm2 |= ((dword)bTmp) << 24; + + return 0; +} + + +/* + * This should always be done by read-modify-write. + */ +static int set_leg_regs( superio_inparm_t *pinparmThe ) +{ + byte bTmp; + + bTmp = pinparmThe->dwParm1 & 0xFF; + putregb( bTmp, 0 ); /* enable */ + + bTmp = (pinparmThe->dwParm1 >> 8) & 0xFF; + putregb( bTmp, 1 ); /* address */ + + bTmp = (pinparmThe->dwParm1 >> 16) & 0xFF; + putregb( bTmp, 2 ); /* power and test */ + + bTmp = (pinparmThe->dwParm1 >> 24) & 0xFF; + putregb( bTmp, 3 ); /* function control */ + + bTmp = pinparmThe->dwParm2 & 0xFF; + putregb( bTmp, 4 ); /* printer control */ + +#if 0 + bTmp = (pinparmThe->dwParm2 >> 8) & 0xFF; + putregb( bTmp, 5 ); /* not used */ +#endif + + bTmp = (pinparmThe->dwParm2 >> 16) & 0xFF; + putregb( bTmp, 6 ); /* power management */ + + bTmp = (pinparmThe->dwParm2 >> 24) & 0xFF; + putregb( bTmp, 7 ); /* tape, ser, par config */ + + return 0; +} + + +static int get_pnp_regs( dword *pdwRegs ) +{ + + *pdwRegs = (dword)getregb( 0x1b ) ; + *pdwRegs |= ((dword)getregb( 0x1c )) << 8 ; + *pdwRegs |= ((dword)getregb( 0x41 )) << 16; + *pdwRegs |= ((dword)getregb( 0x4F )) << 24; + + return 0; +} + + +static flag_t is_in_pnp_mode( word wPortIndex, word wPortData ) +{ + byte bGot; + unsigned long flags; + + save_flags( flags ); cli(); + outb_p( 0x1b, wPortIndex ); + bGot = inb( wPortData ); + restore_flags( flags ); + + return (flag_t)( (bGot >> 3) & 1 ); +} + + +static byte irq_whose_pnp_code_is( byte bCode ) +{ + + switch ( bCode ) { + case 0: return 0; /* "disable" */ + case 1: return 0xFF; + case 2: return 0xFF; + case 3: return 3; + case 4: return 4; + case 5: return 5; + case 6: return 6; + case 7: return 7; + case 8: return 0xFF; /* "invalid" */ + case 9: return 9; + case 10: return 10; + case 11: return 11; + case 12: return 12; + case 13: return 0xFF; /* "invalid" */ + case 14: return 0xFF; /* "invalid" */ + case 15: return 15; + } + + return 0xfe; /* we shouldn't reach here */ +} + + +/* + * returns -EINVAL if can't encode IRQ + */ +static int int_pnp_code_for_irq( byte bIRQ ) +{ + + switch ( bIRQ ) { + case 0: return 0; /* "disable" */ + case 3: return 3; + case 4: return 4; + case 5: return 5; + case 6: return 6; + case 7: return 7; + case 9: return 9; + case 10: return 10; + case 11: return 11; + case 12: return 12; + case 15: return 15; + default: return -EINVAL; + } + + return -EINVAL; +} + + +static flag_t disable_par_tmp( void ) +{ + byte bFER; + flag_t fWasEnabled; + + /*** disable ***/ + bFER = getregb( 0 ); /* FER */ + fWasEnabled = bFER & 1; + putregb( bFER & ~1, 0 ); + + return fWasEnabled; +} + + +static flag_t disable_ser_tmp( byte bWhich ) +{ + byte bFER, bMaskFER; + flag_t fWasEnabled; + + switch ( bWhich ) { + case 1: bMaskFER=2; break; + case 2: bMaskFER=4; break; + default: bMaskFER=0; break; + } + + /*** disable ***/ + bFER = getregb( 0 ); /* FER */ + fWasEnabled = (bFER & bMaskFER) ? 1 : 0; + putregb( bFER & ~bMaskFER, 0 ); + + return fWasEnabled; +} + + +static int get_fdd_irq( byte *pbIRQ ) +{ + byte bTmp; + + bTmp = getregb( 0x41 ) & 0x0F; + + *pbIRQ = irq_whose_pnp_code_is( bTmp ); + + return 0; +} + + +static int get_fdd_base_address( word *pwAdrs) +{ + + *pwAdrs = ((word)getregb( 0x48 ) & ~1) << 2; /* low */ + *pwAdrs |= (((word)getregb( 0x49 ) & ~3) << 8); /* high */ + + return 0; +} + + +static int ablify_par( flag_t fEnable ) +{ + byte bFER; + + bFER = getregb( 0 ); /* FER */ + if ( fEnable ) + putregb( bFER | 1, 0 ); + else + putregb( bFER & ~1, 0 ); + + return 0; +} + + + +static int get_par_irq_legacymode( byte *pbIRQ ) +{ + byte bTmp; + + bTmp = getregb( 0x1b ) & 7; + switch ( bTmp ) { + case 0: *pbIRQ = 0xFF; break; + case 1: *pbIRQ = 7; break; + case 2: *pbIRQ = 9; break; + case 3: *pbIRQ = 10; break; + case 4: *pbIRQ = 11; break; + case 5: *pbIRQ = 14; break; + case 6: *pbIRQ = 15; break; + case 7: *pbIRQ = 5; break; + } + + return 0; +} + + +static int set_par_irq_legacymode( byte bIRQ ) +{ + byte bCode, bPPCR0; + flag_t fWasEnabled; + + /*** compute code ***/ + switch ( bIRQ ) { + case 7: bCode = 1; break; + case 9: bCode = 2; break; + case 10: bCode = 3; break; + case 11: bCode = 4; break; + case 14: bCode = 5; break; + case 15: bCode = 6; break; + case 5: bCode = 7; break; + default: + return -EINVAL; + } + + fWasEnabled = disable_par_tmp(); + + /*** set ***/ + bPPCR0 = getregb( 0x1b ); + putregb( (bPPCR0 & ~7) | (bCode & 7), 0x1b ); + + ablify_par( fWasEnabled ); + + return 0; +} + + +static int get_par_irq_pnpmode( byte *pbIRQ ) +{ + byte bTmp; + + bTmp = getregb( 0x1b ) >> 4; + + *pbIRQ = irq_whose_pnp_code_is( bTmp ); + + return 0; +} + + +static int set_par_irq_pnpmode( byte bIRQ ) +{ + int intCode; + byte bPPCR0, bCode; + flag_t fWasEnabled; + + /*** compute code ***/ + intCode = int_pnp_code_for_irq( bIRQ ); + if ( intCode == -EINVAL ) return -EINVAL; + bCode = (byte)intCode; + + fWasEnabled = disable_par_tmp(); + + /*** set ***/ + bPPCR0 = getregb( 0x1b ); + putregb( (bPPCR0 & 0x0F) | (bCode << 4), 0x1b ); + + ablify_par( fWasEnabled ); + + return 0; +} + + +static int get_par_base_address( word *pwAdrs) +{ + + *pwAdrs = ((word)getregb( 0x42 )) << 2; + *pwAdrs |= (((word)getregb( 0x43 ) & ~3) << 8); + + return 0; +} + + +/* + * When we write we take care not to alter the "reserved" bits + */ +static int set_par_base_address( word wAdrs ) +{ + byte bTmp; + flag_t fWasEnabled; + + fWasEnabled = disable_par_tmp(); + + /*** set ***/ + putregb( (byte)(wAdrs>>2), 0x42 ); /* low */ + + bTmp = getregb( 0x43 ) & 3; + putregb( ((byte)(wAdrs>>8)&~3) | bTmp, 0x43 ); /* high */ + + ablify_par( fWasEnabled ); + + return 0; +} + + +static int get_par_mode( superio_par_mode_t *pmode ) +{ + byte bPCR, bPTR; + + bPCR = getregb( 4 ); + bPTR = getregb( 2 ); + + if ( (bPCR & 5) == 0 && (bPTR & 0x80) == 0 ) { + *pmode = SUPERIO_PAR_MODE_COMPATIBLE; + return 0; + } else if ( (bPCR & 5) == 0 && (bPTR & 0x80) ) { + *pmode = SUPERIO_PAR_MODE_EXTENDED; + return 0; + } else if ( (bPCR & 5) == 1 && (bPTR & 0x80) == 0 && (bPCR & 2) == 0 ) { + *pmode = SUPERIO_PAR_MODE_EPP_1_7; + return 0; + } else if ( (bPCR & 5) == 1 && (bPTR & 0x80) == 0 && (bPCR & 2) ) { + *pmode = SUPERIO_PAR_MODE_EPP_1_9; + return 0; + } else if ( (bPCR & 5) == 4 ) { + *pmode = SUPERIO_PAR_MODE_ECP; + return 0; + } + + printk(KERN_INFO + "%s: Parallel port mode not recognized: PCR = 0x%x PTR = 0x%x\n", + _szMyName, + bPCR, bPTR + ); + *pmode = SUPERIO_PAR_MODE_UNRECOGNIZED; + + return 0; +} + + +static int set_par_mode( superio_par_mode_t mode ) +{ + byte bPCR, bPTR; + + bPCR = getregb( 4 ); + bPTR = getregb( 2 ); + + switch( mode ) { + case SUPERIO_PAR_MODE_COMPATIBLE: + bPCR &= ~5; + bPTR &= ~0x80; + break; + case SUPERIO_PAR_MODE_EXTENDED: + bPCR &= ~5; + bPTR |= 0x80; + break; + case SUPERIO_PAR_MODE_EPP_1_7: + bPCR &= ~4; bPCR |= 1; + bPCR &= ~2; /* EPP version 1.7 */ + bPTR &= ~0x80; + break; + case SUPERIO_PAR_MODE_EPP_1_9: + bPCR &= ~4; bPCR |= 1; + bPCR |= 2; /* EPP version 1.9 */ + bPTR &= ~0x80; + break; + case SUPERIO_PAR_MODE_ECP: + bPCR &= ~1; bPCR |= 4; + break; + case SUPERIO_PAR_MODE_UNRECOGNIZED: + return -EINVAL; + } + + putregb( bPCR, 4 ); + putregb( bPTR, 2 ); + + return 0; +} + + +static int ablify_ser( byte bWhich, flag_t fEnable ) +{ + byte bFER, bMaskFER; + + switch ( bWhich ) { + case 1: bMaskFER=2; break; + case 2: bMaskFER=4; break; + default: + return -EINVAL; + } + + bFER = getregb( 0 ); /* FER */ + if ( fEnable ) + putregb( (bFER | bMaskFER), 0 ); + else + putregb( (bFER & ~bMaskFER), 0 ); + + return 0; +} + + +static int get_ser_irq( byte bWhich, byte *pbIRQ ) +{ + byte bTmp, bCode; + + bTmp = getregb( 0x1c ); + + switch ( bWhich ) { + case 1: bCode = bTmp & 0xF; break; + case 2: bCode = bTmp >> 4; break; + default: + return -EINVAL; + } + + *pbIRQ = irq_whose_pnp_code_is( bCode ); + + return 0; +} + + +static int set_ser_irq( byte bWhich, byte bIRQ ) +{ + int intCode; + byte bPPCR1, bCode; + flag_t fWasEnabled; + + intCode = int_pnp_code_for_irq( bIRQ ); + if ( intCode == -EINVAL ) return -EINVAL; + bCode = (byte)intCode; + + fWasEnabled = disable_ser_tmp( bWhich ); + + /*** set ***/ + bPPCR1 = getregb( 0x1c ); + switch( bWhich ) { + case 1: putregb( (bPPCR1 & 0xF0) | bCode, 0x1c ); break; + case 2: putregb( (bPPCR1 & 0x0F) | (bCode << 4), 0x1c ); break; + default: + return -EINVAL; + } + + ablify_ser( bWhich, fWasEnabled ); + + return 0; +} + + +static int get_ser_base_address( + byte bWhich, + word *pwAdrs +) { + byte bIndexL, bIndexH; + + switch ( bWhich ) { + case 1: bIndexL = 0x44; bIndexH = 0x45; break; + case 2: bIndexL = 0x46; bIndexH = 0x47; break; + default: + return -EINVAL; + } + + *pwAdrs = ((word)getregb( bIndexL ) & ~1) << 2; + *pwAdrs |= (((word)getregb( bIndexH ) & ~3) << 8); + + return 0; +} + + +/* + * When we write we take care not to alter the "reserved" bits + */ +static int set_ser_base_address( + byte bWhich, + word wAdrs +) { + byte bIndexL, bIndexH, bTmp; + flag_t fWasEnabled; + + switch ( bWhich ) { + case 1: bIndexL = 0x44; bIndexH = 0x45; break; + case 2: bIndexL = 0x46; bIndexH = 0x47; break; + default: + return -EINVAL; + } + + fWasEnabled = disable_ser_tmp( bWhich ); + + /*** set ***/ + bTmp = getregb( bIndexL ) & 1; + putregb( ((byte)(wAdrs>>2)&~1) | bTmp, bIndexL ); + + bTmp = getregb( bIndexH ) & 3; + putregb( ((byte)(wAdrs>>8)&~3) | bTmp, bIndexH ); + + ablify_ser( bWhich, fWasEnabled ); + + return 0; +} + + +static int superio_read_proc( + char *pchBuf, + char **ppchStart, + off_t off, + int intCount, + int *pintEof, + void *data +) { + return snprintf( + pchBuf, intCount, + "%s version %s controlling Super I/O chip at ioports 0x%x, 0x%x\n", + _szMyName, _szMyVersion, + _wPortIndex, _wPortData + ); +} + +static int superio_do_func( + superio_inparm_t *pinparmThe, + superio_outparm_t *poutparmThe, + flag_t fHasWritePerm +) { + + switch ( pinparmThe->wFunc ) { + case SUPERIO_FUNC_LEG_REGS_GET: + return get_leg_regs( poutparmThe ); + case SUPERIO_FUNC_LEG_REGS_SET: + if ( !fHasWritePerm ) return -EACCES; + return set_leg_regs( pinparmThe ); + case SUPERIO_FUNC_PNP_REGS_GET: + return get_pnp_regs( &(poutparmThe->dwParm1) ); + case SUPERIO_FUNC_FDD_IRQ_GET: + return get_fdd_irq( (byte *)&(poutparmThe->dwParm1) ); + case SUPERIO_FUNC_FDD_BASE_GET: + return get_fdd_base_address( (word *)&(poutparmThe->dwParm1) ); + case SUPERIO_FUNC_PAR_IRQ_GET: + if ( is_in_pnp_mode( _wPortIndex, _wPortData ) ) { + return get_par_irq_pnpmode( (byte *)&(poutparmThe->dwParm1) ); + } else { + printk(KERN_INFO + "%s: Super I/O chip is in legacy mode!\n", + _szMyName + ); + return get_par_irq_legacymode( (byte *)&(poutparmThe->dwParm1) ); + } + case SUPERIO_FUNC_PAR_IRQ_SET: + if ( !fHasWritePerm ) return -EACCES; + set_par_irq_legacymode( (byte)(pinparmThe->dwParm1) ); + return set_par_irq_pnpmode( (byte)(pinparmThe->dwParm1) ); + case SUPERIO_FUNC_PAR_BASE_GET: + return get_par_base_address( (word *)&(poutparmThe->dwParm1) ); + case SUPERIO_FUNC_PAR_BASE_SET: + if ( !fHasWritePerm ) return -EACCES; + return set_par_base_address( (word)(pinparmThe->dwParm1) ); + case SUPERIO_FUNC_PAR_MODE_GET: + return get_par_mode( (superio_par_mode_t *)&(poutparmThe->dwParm1) ); + case SUPERIO_FUNC_PAR_MODE_SET: + if ( !fHasWritePerm ) return -EACCES; + return set_par_mode( (superio_par_mode_t)(pinparmThe->dwParm1) ); + + case SUPERIO_FUNC_PAR_ABLIFY: + if ( !fHasWritePerm ) return -EACCES; + return ablify_par( (flag_t)(pinparmThe->dwParm1) ); + case SUPERIO_FUNC_SER_IRQ_GET: + return get_ser_irq( (byte)pinparmThe->wParm0, (byte *)&(poutparmThe->dwParm1) ); + case SUPERIO_FUNC_SER_IRQ_SET: + if ( !fHasWritePerm ) return -EACCES; + return set_ser_irq( (byte)pinparmThe->wParm0, (byte)(pinparmThe->dwParm1) ); + case SUPERIO_FUNC_SER_BASE_GET: + return get_ser_base_address( pinparmThe->wParm0, (word *)&(poutparmThe->dwParm1) ); + case SUPERIO_FUNC_SER_BASE_SET: + if ( !fHasWritePerm ) return -EACCES; + return set_ser_base_address( pinparmThe->wParm0, (word)(pinparmThe->dwParm1) ); + case SUPERIO_FUNC_SER_ABLIFY: + if ( !fHasWritePerm ) return -EACCES; + return ablify_ser( pinparmThe->wParm0, (flag_t)(pinparmThe->dwParm1) ); + default: + return -EINVAL; + } +} + + +int superio_do( + unsigned long ulongIoctlArg, + flag_t fCallerHasWritePerm +) { + superio_inparm_t inparmThe; + superio_outparm_t outparmThe; + unsigned long ulRtnCopy; + int intRtnDo; + + ulRtnCopy = copy_from_user( + &inparmThe, + (byte *)&(((superio_ioparm_t *)ulongIoctlArg)->in), + sizeof( inparmThe ) + ); + if ( ulRtnCopy ) return -EFAULT; + + intRtnDo = superio_do_func( &inparmThe, &outparmThe, fCallerHasWritePerm ); + + if ( intRtnDo == -EACCES ) { + printk(KERN_ERR + "%s: caller does not have permission to do this to the Super IO device\n", + _szMyName + ); + return intRtnDo; + } + + ulRtnCopy = copy_to_user( + (byte *)&(((superio_ioparm_t *)ulongIoctlArg)->out), + &outparmThe, + sizeof( outparmThe ) + ); + if ( ulRtnCopy ) return -EFAULT; + + return intRtnDo; /* Should be either 0 or -EACCES or -EINVAL */ +} + +#ifdef CONFIG_DEVFS_FS +static int superio_open( + struct inode * pinodeThe, + struct file * pfileThe +) { + + return 0; +} + + +static int superio_release( + struct inode * pinodeThe, + struct file * pfileThe +) { + + return 0; +} + + +static flag_t caller_has_w( struct file * pfileThe ) +{ + return ((pfileThe->f_mode) & FMODE_WRITE) ? 1 : 0; +} + + +static int superio_ioctl( + struct inode * pinodeThe, + struct file * pfileThe, + unsigned int uintIoctlNum, + unsigned long ulongIoctlArg +) { + +#ifdef DEBUG_VERBOSE + printk( "%s: Doing ioctl number 0x%x\n", _szMyName, uintIoctlNum ); +#endif + + switch ( uintIoctlNum ) { + /* should return at the end of each case block */ + + case IOCTL_SUPERIO_REQUEST: + return superio_do( + ulongIoctlArg, + caller_has_w( pfileThe ) + ); + + default: + /* ioctl number not recognized -- do nothing */ + return -ENOTTY; + + } /* switch */ + + return -ETHINKPAD_PROGRAMMING; /* We should never arrive here */ +} +#endif /* defined(CONFIG_DEVFS_FS) */ + + +/* + * We write to nonsense port 0x80 in order to + * protect against false positives due to + * ISA bus float + */ +static flag_t a_super_io_chip_appears_to_be_at( word wPort ) +{ + byte bSave, bID; + unsigned long flags; + + save_flags( flags ); cli(); + + bSave = inb( wPort ); + + /*** Check for a register ***/ + outb( 0x0a, wPort ); + outb( ~0x0a, 0x080 ); + if ( inb( wPort ) != 0x0a ) { goto No; } + outb( 0x11, wPort ); + outb( ~0x11, 0x080 ); + if ( inb( wPort ) != 0x11 ) { goto No; } + outb( 0x44, wPort ); + outb( ~0x44, 0x080 ); + if ( inb( wPort ) != 0x44 ) { goto No; } + + /* There's a register */ + + /*** Check for chip ID ***/ + outb( 0x08, wPort ); + bID = inb( wPort + 1 ); + if ( (bID & ~3) != 0xb0 ) { goto No; } + +/* Yes: */ + /* No need to restore index port's contents */ + restore_flags( flags ); + return 1; + +No: + outb( bSave, wPort ); /* restore the port's contents */ + restore_flags( flags ); + return 0; +} + + +static word locate_chip( void ) +{ + + if ( a_super_io_chip_appears_to_be_at( 0x26e ) ) return 0x26e; + if ( a_super_io_chip_appears_to_be_at( 0x2e ) ) return 0x2e; + return 0; +} + + +static flag_t see_index_ID( word wPort ) +{ + if ( inb( wPort ) == 0x88 ) if ( inb( wPort ) == 0 ) return 1; + return 0; +} + + +static int __init superio_init( void ) +{ + word wPortBase; + flag_t fVirgin; + + fVirgin = see_index_ID( 0x2e ); + + wPortBase = locate_chip(); + + if ( wPortBase == 0 ) { + printk(KERN_ERR + "%s: Super I/O chip not found. :-(\n", + _szMyName + ); + return -ETHINKPAD_HW_NOT_FOUND; + } + + /* chip found at wPortBase */ + + if ( !is_in_pnp_mode( wPortBase, wPortBase+1 ) ) { + printk(KERN_ERR + "%s: Super I/O chip found at port base 0x%x is not in plug-n-play mode. :-(\n", + _szMyName, wPortBase + ); + return -ETHINKPAD_HW_NOT_FOUND; + } + + printk(KERN_INFO + "%s: Super I/O chip (%svirgin) %sin plug-n-play mode found at port base 0x%x. :-)\n", + _szMyName, + fVirgin ? "" : "non-", + is_in_pnp_mode( wPortBase, wPortBase+1 ) ? "" : "not ", + wPortBase + ); + + /* At this point we assume we have found a working chip at wPortBase */ + + /*** request the io ports ***/ + _presourceSuperio = request_region( wPortBase, 2, "superio" ); + if ( _presourceSuperio == NULL ) { +/* + * The region is claimed by the programmable interrupt controller "pic1" + * as part of the range 0x20--0x3f. + */ +#if 0 + printk(KERN_ERR + "%s: I/O ports for Super I/O chip not available -- aborting.\n", + _szMyName + ); + return -ETHINKPAD_HW_NOT_FOUND; +#else + printk(KERN_INFO + "%s: I/O ports for Super I/O chip not available, but ignoring this.\n", + _szMyName + ); +#endif + } + + _wPortIndex = wPortBase; + _wPortData = wPortBase + 1; + + if ( !thinkpad_ppde || !create_proc_read_entry( + _szProcfile, + S_IFREG | S_IRUGO, + NULL, + superio_read_proc, + NULL + ) ) { + printk(KERN_ERR "%s: Could not create_proc_read_entry() /proc/%s\n", _szMyName, _szProcfile ); + } + /* proc entry created */ + +#ifdef CONFIG_DEVFS_FS + _devfs_handleSuperio = devfs_register( + NULL /* dir */, + "thinkpad/superio", + DEVFS_FL_DEFAULT | DEVFS_FL_AUTO_DEVNUM, + 0 /* major */, 0 /* minor */, + S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH, + &_fileopsSuperio, + NULL /* info */ + ); + if ( _devfs_handleSuperio == NULL ) { + printk(KERN_ERR "%s: Could not devfs_register(). Aborting.\n", _szMyName ); + return -EIO; + } + /* devfs entry created */ +#endif + + inter_module_register( _szImName, THIS_MODULE, &superio_do ); + + return 0; +} + + +static void __exit superio_exit( void ) +{ + + inter_module_unregister( _szImName ); + +#ifdef CONFIG_DEVFS_FS + devfs_unregister( _devfs_handleSuperio ); +#endif + + remove_proc_entry( _szProcfile, NULL ); + + if ( _presourceSuperio != NULL ) release_resource( _presourceSuperio ); + + return; +} + +module_init(superio_init); +module_exit(superio_exit); diff -urNp thinkpad/drivers/char/thinkpad/superio.h 2.4.20pre8aa2/drivers/char/thinkpad/superio.h --- thinkpad/drivers/char/thinkpad/superio.h Thu Jan 1 01:00:00 1970 +++ 2.4.20pre8aa2/drivers/char/thinkpad/superio.h Wed Oct 2 06:42:00 2002 @@ -0,0 +1,92 @@ + +/********************************************************************* + * + * Filename: superio.h + * Description: header file for the superio driver + * Author: Thomas Hood + * Created: 19 July 1999 + * + * Please report bugs to the author ASAP. + * + * Copyright (c) 1999 J.D. Thomas Hood, All rights reserved + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * To receive a copy of the GNU General Public License, please write + * to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA + * + ********************************************************************/ + +#ifndef __SUPERIO_H__ +#define __SUPERIO_H__ + +/****** defines ******/ + +#define SUPERIO_FUNC_LEG_REGS_GET ((word)0x100) +#define SUPERIO_FUNC_LEG_REGS_SET ((word)0x101) +#define SUPERIO_FUNC_PNP_REGS_GET ((word)0x200) +#define SUPERIO_FUNC_FDD_IRQ_GET ((word)0x310) +#define SUPERIO_FUNC_FDD_BASE_GET ((word)0x320) +#define SUPERIO_FUNC_PAR_ABLIFY ((word)0x400) +#define SUPERIO_FUNC_PAR_IRQ_GET ((word)0x413) +#define SUPERIO_FUNC_PAR_IRQ_SET ((word)0x411) +#define SUPERIO_FUNC_PAR_BASE_GET ((word)0x420) +#define SUPERIO_FUNC_PAR_BASE_SET ((word)0x421) +#define SUPERIO_FUNC_PAR_MODE_GET ((word)0x430) +#define SUPERIO_FUNC_PAR_MODE_SET ((word)0x431) +#define SUPERIO_FUNC_SER_ABLIFY ((word)0x500) +#define SUPERIO_FUNC_SER_IRQ_GET ((word)0x510) +#define SUPERIO_FUNC_SER_IRQ_SET ((word)0x511) +#define SUPERIO_FUNC_SER_BASE_GET ((word)0x520) +#define SUPERIO_FUNC_SER_BASE_SET ((word)0x521) + +/****** typedefs ******/ + +/*** superio module input parameters ***/ +typedef struct _superio_inparm { + word wFunc; + word wParm0; + dword dwParm1; + dword dwParm2; +} superio_inparm_t; + +/*** superio module output parameters ***/ +typedef struct _superio_outparm { + word wRc; + word wParm0; + dword dwParm1; + dword dwParm2; +} superio_outparm_t; + +typedef union _superio_ioparm_t { + superio_inparm_t in; + superio_inparm_t out; +} superio_ioparm_t; + +typedef enum _superio_par_mode { + SUPERIO_PAR_MODE_COMPATIBLE=0, + SUPERIO_PAR_MODE_EXTENDED, + SUPERIO_PAR_MODE_EPP_1_7, + SUPERIO_PAR_MODE_EPP_1_9, + SUPERIO_PAR_MODE_ECP, + SUPERIO_PAR_MODE_UNRECOGNIZED +} superio_par_mode_t; + +/****** declarations ******/ + +int superio_do( + unsigned long ulongIoctlArg, + flag_t fCallerHasWritePerm +); + + +#endif diff -urNp thinkpad/drivers/char/thinkpad/thinkpad.c 2.4.20pre8aa2/drivers/char/thinkpad/thinkpad.c --- thinkpad/drivers/char/thinkpad/thinkpad.c Thu Jan 1 01:00:00 1970 +++ 2.4.20pre8aa2/drivers/char/thinkpad/thinkpad.c Wed Oct 2 06:42:00 2002 @@ -0,0 +1,420 @@ + +/********************************************************************* + * + * Filename: thinkpad.c + * Description: loadable kernel module that serves as a router of ioctl + * requests to other modules that control various hardware + * features of IBM ThinkPads + * Author: Thomas Hood + * Created: 19 July 1999 + * + * Notes: This driver exists so that several thinkpad devices can be + * driven with only a single permanent misc device minor number + * allocated. With the advent of devfs, such tricks are no longer + * necessary. The elegant thing to do, under devfs, would be + * for each driver to have its own device file under /dev/thinkpad. + * However, the present scheme continues to work under devfs and + * will not be changed unless there is a pressing need, since it + * would involve substantial changes both to the drivers and to + * the tpctl program that uses them. + * + * Please report bugs to the author ASAP. + * + * Copyright (c) 1999 J.D. Thomas Hood, All rights reserved + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * To receive a copy of the GNU General Public License, please write + * to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA + * + ********************************************************************/ + +#include "thinkpad_driver.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "thinkpad_common.h" +#include "thinkpad.h" +#include "smapi.h" +#include "superio.h" +#include "rtcmosram.h" +#include "thinkpadpm.h" + +/****** definitions ******/ + +#define MINOR_THINKPAD 170 + +/****** forward declarations ******/ +static int thinkpad_open( + struct inode * pinodeThe, + struct file * pfileThe +); +static int thinkpad_release( + struct inode * pinodeThe, + struct file * pfileThe +); +static int thinkpad_ioctl( + struct inode * pinodeThe, + struct file * pfileThe, + unsigned int uintIoctlNum, + unsigned long ulongIoctlArg +); + +typedef enum _mod_t { + MOD_SMAPI, + MOD_SUPERIO, + MOD_RTCMOSRAM, + MOD_THINKPADPM +} mod_t; + +/* pointer to an executable "do" function returning an integer */ +typedef int (* pxint_do_t)( unsigned long, flag_t ); + +/****** variables ******/ + +/*** global ***/ +struct proc_dir_entry *thinkpad_ppde; + +/*** module parameters ***/ +static int enable_smapi = 1; +static int enable_superio = 1; +static int enable_rtcmosram = 1; +static int enable_thinkpadpm = 1; +MODULE_PARM( enable_smapi, "i" ); +MODULE_PARM( enable_superio, "i" ); +MODULE_PARM( enable_rtcmosram, "i" ); +MODULE_PARM( enable_thinkpadpm, "i" ); +MODULE_AUTHOR( "Thomas Hood" ); +MODULE_DESCRIPTION( "Metadriver for IBM ThinkPad hardware drivers" ); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,10) +MODULE_LICENSE( "GPL" ); +#endif + +/*** local ***/ +static const char _szMyName[] = "thinkpad"; +static const char _szMyVersion[] = "3.0"; +static const char _szSmapiName[] = "smapi"; +static const char _szSuperioName[] = "superio"; +static const char _szRtcmosramName[] = "rtcmosram"; +static const char _szThinkpadpmName[] = "thinkpadpm"; +static flag_t _fInUse = 1; + +static struct file_operations _fileopsThinkpad = { + ioctl: thinkpad_ioctl, + open: thinkpad_open, + release: thinkpad_release, + owner: THIS_MODULE +}; + +#ifdef CONFIG_DEVFS_FS +static devfs_handle_t _devfs_handleThinkpadDir; +static devfs_handle_t _devfs_handleThinkpadDev; +#endif + + +/****** functions ******/ + +static int thinkpad_read_proc( + char *pchBuf, + char **ppchStart, + off_t off, + int intCount, + int *pintEof, + void *pdata +) { + return snprintf( + pchBuf, intCount, + "%s version %s enabled to access modules: %s %s %s %s.\n", + _szMyName, _szMyVersion, + enable_smapi ? _szSmapiName : "", + enable_superio ? _szSuperioName : "", + enable_rtcmosram ? _szRtcmosramName : "", + enable_thinkpadpm ? _szThinkpadpmName : "" + ); +} + +static int thinkpad_open( + struct inode * pinodeThe, + struct file * pfileThe +) { + + if ( _fInUse ) return -EBUSY; + + _fInUse = 1; + + return 0; +} + + +static int thinkpad_release( + struct inode * pinodeThe, + struct file * pfileThe +) { + + _fInUse = 0; + + return 0; +} + + +static flag_t caller_has_w( struct file * pfileThe ) +{ + return ((pfileThe->f_mode) & FMODE_WRITE) ? 1 : 0; +} + + +static int thinkpad_ioctl( + struct inode * pinodeThe, + struct file * pfileThe, + unsigned int uintIoctlNum, + unsigned long ulongIoctlArg +) { + unsigned long ulRtnCopy; + +#ifdef DEBUG_VERBOSE + printk( "%s: Doing ioctl number 0x%x\n", _szMyName, uintIoctlNum ); +#endif + + switch ( uintIoctlNum ) { + /* should return at the end of each case block */ + + case IOCTL_THINKPAD_GETVER: + ulRtnCopy = copy_to_user( + (byte *)ulongIoctlArg, + _szMyVersion, + strlen( _szMyVersion ) + 1 + ); + if ( ulRtnCopy ) return -EFAULT; + return 0; + + case IOCTL_THINKPAD_ENABLE: + case IOCTL_THINKPAD_DISABLE: { + long lRes; + char szBuf[LEN_NAME_MAX+1]; + flag_t fEnable; + + fEnable = ( uintIoctlNum == IOCTL_THINKPAD_ENABLE ) ? 1 : 0; + + if ( !caller_has_w( pfileThe ) ) return -EACCES; + + lRes = strncpy_from_user( + szBuf, + (char *)ulongIoctlArg, + LEN_NAME_MAX + ); + szBuf[LEN_NAME_MAX] = '\0'; /* ensure termination */ + + printk(KERN_INFO + "%s: %sabling %s\n", _szMyName, fEnable?"En":"Dis", szBuf + ); + + if ( strnicmp( szBuf, _szSmapiName, LEN_NAME_MAX ) == 0 ) { + enable_smapi = fEnable; return 0; + } else if ( strnicmp( szBuf, _szSuperioName, LEN_NAME_MAX ) == 0 ) { + enable_superio = fEnable; return 0; + } else if ( strnicmp( szBuf, _szRtcmosramName, LEN_NAME_MAX ) == 0 ) { + enable_rtcmosram = fEnable; return 0; + } else if ( strnicmp( szBuf, _szThinkpadpmName, LEN_NAME_MAX ) == 0 ) { + enable_thinkpadpm = fEnable; return 0; + } + return -EINVAL; + } + + case IOCTL_SMAPI_REQUEST: { + pxint_do_t pxint_doSmapi; + int intRet; + if ( ! enable_smapi ) return -ETHINKPAD_MODULE_DISABLED; + pxint_doSmapi = (pxint_do_t)inter_module_get_request( "smapi_do" , _szSmapiName ); + if ( pxint_doSmapi == NULL ) return -ETHINKPAD_MODULE_NOT_FOUND; + intRet = (*pxint_doSmapi)( + ulongIoctlArg, + caller_has_w( pfileThe ) + ); + inter_module_put("smapi_do"); + if ( intRet > 0 ) intRet = -ETHINKPAD_PROGRAMMING; + return intRet; + } + + case IOCTL_SUPERIO_REQUEST: { + pxint_do_t pxint_doSuperio; + int intRet; + if ( ! enable_superio ) return -ETHINKPAD_MODULE_DISABLED; + pxint_doSuperio = (pxint_do_t)inter_module_get_request( "superio_do" , _szSuperioName ); + if ( pxint_doSuperio == NULL ) return -ETHINKPAD_MODULE_NOT_FOUND; + intRet = (*pxint_doSuperio)( + ulongIoctlArg, + caller_has_w( pfileThe ) + ); + inter_module_put("superio_do"); + if ( intRet > 0 ) intRet = -ETHINKPAD_PROGRAMMING; + return intRet; + } + + case IOCTL_RTCMOSRAM_REQUEST: { + pxint_do_t pxint_doRtcmosram; + int intRet; + if ( ! enable_rtcmosram ) return -ETHINKPAD_MODULE_DISABLED; + pxint_doRtcmosram = (pxint_do_t)inter_module_get_request( "rtcmosram_do" , _szRtcmosramName ); + if ( pxint_doRtcmosram == NULL ) return -ETHINKPAD_MODULE_NOT_FOUND; + intRet = (*pxint_doRtcmosram)( + ulongIoctlArg, + caller_has_w( pfileThe ) + ); + inter_module_put("rtcmosram_do"); + if ( intRet > 0 ) intRet = -ETHINKPAD_PROGRAMMING; + return intRet; + } + + case IOCTL_THINKPADPM_REQUEST: { + pxint_do_t pxint_doThinkpadpm; + int intRet; + if ( ! enable_thinkpadpm ) return -ETHINKPAD_MODULE_DISABLED; + pxint_doThinkpadpm = (pxint_do_t)inter_module_get_request( "thinkpadpm_do" , _szThinkpadpmName ); + if ( pxint_doThinkpadpm == NULL ) return -ETHINKPAD_MODULE_NOT_FOUND; + intRet = (*pxint_doThinkpadpm)( + ulongIoctlArg, + caller_has_w( pfileThe ) + ); + inter_module_put("thinkpadpm_do"); + if ( intRet > 0 ) intRet = -ETHINKPAD_PROGRAMMING; + return intRet; + } + + default: + /* ioctl number not recognized -- do nothing */ + return -ENOTTY; + + } /* switch */ + + return -ETHINKPAD_PROGRAMMING; /* We should never arrive here */ +} + + +#ifndef CONFIG_DEVFS_FS +static struct miscdevice _structmiscdeviceThinkpad = { + MINOR_THINKPAD, + "thinkpad", + &_fileopsThinkpad +}; +#endif + +static int __init thinkpad_init( void ) +{ +#ifdef CONFIG_DEVFS_FS + _devfs_handleThinkpadDir = devfs_mk_dir( + NULL, /* dir */ + "thinkpad", + NULL /* info */ + ); + if ( _devfs_handleThinkpadDir == NULL ) { + printk(KERN_ERR + "%s: Could not devfs_mkdir(). Aborting.\n", + _szMyName + ); + return -EIO; + } + + _devfs_handleThinkpadDev = devfs_register( + _devfs_handleThinkpadDir, + "thinkpad", + DEVFS_FL_DEFAULT, + 10 /* major */, 170 /* minor */, + S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH, + &_fileopsThinkpad, + NULL /* info */ + ); + if ( _devfs_handleThinkpadDev == NULL ) { + printk(KERN_ERR + "%s: Could not devfs_register(). Aborting.\n", + _szMyName + ); + devfs_unregister( _devfs_handleThinkpadDir ); + return -EIO; + } + /* dev entry created */ +#else + int intRtnMiscRegister; + + intRtnMiscRegister = misc_register( &_structmiscdeviceThinkpad ); + if ( intRtnMiscRegister ) { + if ( intRtnMiscRegister == -EBUSY ) { + printk(KERN_ERR + "%s: Error %d was returned by misc_register(): device is busy\n", + _szMyName, intRtnMiscRegister + ); + } else { + printk(KERN_ERR + "%s: Error %d was returned by misc_register()\n", + _szMyName, intRtnMiscRegister + ); + } + return intRtnMiscRegister; + } +#endif /* ifdef CONFIG_DEVFS_FS */ + + /* this module has been registered successfully */ + + printk(KERN_INFO + "%s: I have registered to handle major: %d minor: %d.\n", + _szMyName, 10, MINOR_THINKPAD + ); + + if ( (thinkpad_ppde = proc_mkdir( "driver/thinkpad", NULL )) == NULL ) { + printk(KERN_ERR "%s: Could not proc_mkdir() /proc/driver/thinkpad/\n", _szMyName ); + } else { /* /proc/thinkpad was created. */ + if ( !create_proc_read_entry( "driver/thinkpad/thinkpad", S_IFREG | S_IRUGO, NULL, thinkpad_read_proc, NULL )) { + printk(KERN_ERR "%s: Could not create_proc_read_entry() /proc/driver/thinkpad/thinkpad\n", _szMyName ); + } + } + /* proc entries created */ + + _fInUse = 0; + + return 0; +} + + +static void __exit thinkpad_exit( void ) +{ + + remove_proc_entry( "driver/thinkpad/thinkpad", NULL ); + remove_proc_entry( "driver/thinkpad", NULL ); + +#ifndef CONFIG_DEVFS_FS + { + int intRtn; + + intRtn = misc_deregister( &_structmiscdeviceThinkpad ); + if ( intRtn != 0 ) printk(KERN_ERR "%s: Error reported by misc_deregister: %d\n", _szMyName, intRtn ); + } +#else + devfs_unregister( _devfs_handleThinkpadDev ); + devfs_unregister( _devfs_handleThinkpadDir ); +#endif + + printk(KERN_INFO + "%s: I have cleaned up.\n", + _szMyName + ); + + return; +} + +module_init(thinkpad_init); +module_exit(thinkpad_exit); diff -urNp thinkpad/drivers/char/thinkpad/thinkpad.h 2.4.20pre8aa2/drivers/char/thinkpad/thinkpad.h --- thinkpad/drivers/char/thinkpad/thinkpad.h Thu Jan 1 01:00:00 1970 +++ 2.4.20pre8aa2/drivers/char/thinkpad/thinkpad.h Wed Oct 2 06:42:00 2002 @@ -0,0 +1,39 @@ + +/********************************************************************* + * + * Filename: thinkpad.h + * Description: header file for the thinkpad driver + * Author: Thomas Hood + * Created: 19 July 1999 + * + * Please report bugs to the author ASAP. + * + * Copyright (c) 1999 J.D. Thomas Hood, All rights reserved + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * To receive a copy of the GNU General Public License, please write + * to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA + * + ********************************************************************/ + +#ifndef __THINKPAD_H__ +#define __THINKPAD_H__ + +/*** thinkpad module input/output parameters ***/ +typedef union _thinkpad_ioparm { + char szVersion[ LEN_VERSION_MAX+1 ]; + char szName[ LEN_NAME_MAX+1 ]; +} thinkpad_ioparm_t; + +#endif /* THINKPAD_H */ + diff -urNp thinkpad/drivers/char/thinkpad/thinkpad_common.h 2.4.20pre8aa2/drivers/char/thinkpad/thinkpad_common.h --- thinkpad/drivers/char/thinkpad/thinkpad_common.h Thu Jan 1 01:00:00 1970 +++ 2.4.20pre8aa2/drivers/char/thinkpad/thinkpad_common.h Wed Oct 2 06:42:00 2002 @@ -0,0 +1,124 @@ + +/********************************************************************* + * + * Filename: thinkpad_common.h + * Description: stuff required by the "thinkpad" drivers and + * by programs accessing them + * Author: Thomas Hood + * Created: 19 July 1999 + * + * Please report bugs to the author ASAP. + * + * Copyright (c) 1999 J.D. Thomas Hood, All rights reserved + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * To receive a copy of the GNU General Public License, please write + * to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA + * + ********************************************************************/ + +#ifndef __THINKPAD_COMMON_H__ +#define __THINKPAD_COMMON_H__ + +/* All module (etc.) names should be no longer than this: */ +#define LEN_NAME_MAX 80 + +/* All version strings should be no longer than this: */ +#define LEN_VERSION_MAX 30 + +/****** macros ******/ + +#ifdef DEBUG_IOPARM +#define DEBUG_PRINT_OUTPARMS( ioparmThe ) { \ + printf( "bRc: 0x%x\n", ioparmThe.out.bRc ); \ + printf( "bSubRc: 0x%x\n", ioparmThe.out.bSubRc ); \ + printf( "wParm1: 0x%x\n", ioparmThe.out.wParm1 ); \ + printf( "wParm2: 0x%x\n", ioparmThe.out.wParm2 ); \ + printf( "wParm3: 0x%x\n", ioparmThe.out.wParm3 ); \ + printf( "dwParm4: 0x%lx\n", (unsigned long) ioparmThe.out.dwParm4 ); \ + printf( "dwParm5: 0x%lx\n", (unsigned long) ioparmThe.out.dwParm5 ); \ +} +#define DEBUG_PRINT_INPARMS( ioparmThe ) { \ + printf( "bFunc: 0x%x\n", ioparmThe.in.bFunc ); \ + printf( "bSubFunc: 0x%x\n", ioparmThe.in.bSubFunc ); \ + printf( "wParm1: 0x%x\n", ioparmThe.in.wParm1 ); \ + printf( "wParm2: 0x%x\n", ioparmThe.in.wParm2 ); \ + printf( "wParm3: 0x%x\n", ioparmThe.in.wParm3 ); \ + printf( "dwParm4: 0x%lx\n", (unsigned long) ioparmThe.in.dwParm4 ); \ + printf( "dwParm5: 0x%lx\n", (unsigned long) ioparmThe.in.dwParm5 ); \ +} +#else +#define DEBUG_PRINT_OUTPARMS( ioparmThe ) +#define DEBUG_PRINT_INPARMS( ioparmThe ) +#endif + + +/****** types ******/ + +typedef __u8 byte; +typedef __u16 word; +typedef __u32 dword; +typedef char flag_t; +typedef byte bcd8_t; + + +/*** ioctl commands ***/ + +#include "thinkpad.h" +#include "smapi.h" +#include "superio.h" +#include "rtcmosram.h" +#include "thinkpadpm.h" + +#define MAGIC_THINKPAD_IOCTL ('(') +#define IOCTL_THINKPAD_GETVER _IOR (MAGIC_THINKPAD_IOCTL,0x1,thinkpad_ioparm_t) +#define IOCTL_THINKPAD_ENABLE _IOWR(MAGIC_THINKPAD_IOCTL,0x2,thinkpad_ioparm_t) +#define IOCTL_THINKPAD_DISABLE _IOWR(MAGIC_THINKPAD_IOCTL,0x3,thinkpad_ioparm_t) +#define IOCTL_SMAPI_REQUEST _IOWR(MAGIC_THINKPAD_IOCTL,0x10,smapi_ioparm_t) +#define IOCTL_SUPERIO_REQUEST _IOWR(MAGIC_THINKPAD_IOCTL,0x11,superio_ioparm_t) +#define IOCTL_RTCMOSRAM_REQUEST _IOWR(MAGIC_THINKPAD_IOCTL,0x12,rtcmosram_ioparm_t) +#define IOCTL_THINKPADPM_REQUEST _IOWR(MAGIC_THINKPAD_IOCTL,0x20,thinkpadpm_ioparm_t) + +/****** return values ******/ + +/* 0 as a return value always means OK */ + +/* + * We use the following standard UNIX errno's, defined in + * EFAULT memory error + * EBUSY device is already open + * EINVAL function code not recognized + * ENOTTY ioctl code not recognized + * EACCESS inadequate permission to perform action + * + * We use the following standard errnos under names more descriptive + * of our circumstances. Remember that the ioctl handler in the + * driver returns the negatives of these, but they turn up positive + * in user space in errno after an ioctl() call. Our convention + * for ioctl_blah() wrapper functions is to return the errno as a + * negative number. + */ +#define ETHINKPAD_EXECUTION (EILSEQ) +#define ETHINKPAD_PROGRAMMING (ENOSYS) +#define ETHINKPAD_HW_NOT_FOUND (ENXIO) +#define ETHINKPAD_MODULE_DISABLED (ESPIPE) +#define ETHINKPAD_MODULE_NOT_FOUND (ENODEV) +#define ETHINKPAD_SUBDRIVER (EPIPE) + +/* + * Subdriver error codes are returned in the parameter block + * and errno is set to THINKPAD_SUBDRIVER + * + */ + +#endif /* __THINKPAD_COMMON_H__ */ diff -urNp thinkpad/drivers/char/thinkpad/thinkpad_driver.h 2.4.20pre8aa2/drivers/char/thinkpad/thinkpad_driver.h --- thinkpad/drivers/char/thinkpad/thinkpad_driver.h Thu Jan 1 01:00:00 1970 +++ 2.4.20pre8aa2/drivers/char/thinkpad/thinkpad_driver.h Wed Oct 2 06:42:00 2002 @@ -0,0 +1,44 @@ + +/********************************************************************* + * + * Filename: thinkpad_driver.h + * Description: common header for all "thinkpad" drivers + * Author: Thomas Hood + * Created: 28 July 1999 + * + * Please report bugs to the author ASAP. + * + * Copyright (c) 1999 J.D. Thomas Hood, All rights reserved + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * To receive a copy of the GNU General Public License, please write + * to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA + * + ********************************************************************/ + +#ifndef __THINKPAD_DRIVER_H__ +#define __THINKPAD_DRIVER_H__ + +#include + +#if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS) +# define MODVERSIONS +#endif + +#ifdef MODVERSIONS + /* This has to follow something that includes config.h and precede + * headers that declare kernel functions that we use */ +#include +#endif + +#endif /* THINKPAD_DRIVER_H */ diff -urNp thinkpad/drivers/char/thinkpad/thinkpadpm.c 2.4.20pre8aa2/drivers/char/thinkpad/thinkpadpm.c --- thinkpad/drivers/char/thinkpad/thinkpadpm.c Thu Jan 1 01:00:00 1970 +++ 2.4.20pre8aa2/drivers/char/thinkpad/thinkpadpm.c Wed Oct 2 06:42:00 2002 @@ -0,0 +1,569 @@ + +/********************************************************************* + * + * Filename: thinkpadpm.c + * Description: thinkpadpm.o is a kernel module that serves as + * an interface between the thinkpad module and the + * kernel power management drivers + * Author: Thomas Hood + * Created: 27 January 2001 + * + * Please report bugs to the author ASAP. + * + * Copyright (c) 1999 J.D. Thomas Hood, All rights reserved + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * To receive a copy of the GNU General Public License, please write + * to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA + * + ********************************************************************/ + +#include "thinkpad_driver.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "thinkpad_common.h" +#include "thinkpadpm.h" + + +/****** definitions ******/ + + +/****** declarations ******/ + +extern struct proc_dir_entry *thinkpad_ppde; + +#ifdef CONFIG_DEVFS_FS +static int thinkpadpm_open( + struct inode * pinodeThe, + struct file * pfileThe +); +static int thinkpadpm_release( + struct inode * pinodeThe, + struct file * pfileThe +); +static int thinkpadpm_ioctl( + struct inode * pinodeThe, + struct file * pfileThe, + unsigned int uintIoctlNum, + unsigned long ulongIoctlArg +); +#endif + +/****** variables ******/ + +static const char _szMyName[] = "thinkpadpm"; +static const char _szImName[] = "thinkpadpm_do"; +static const char _szMyVersion[] = "3.0"; +static const char _szProcfile[] = "driver/thinkpad/thinkpadpm"; + +MODULE_AUTHOR( "Thomas Hood" ); +MODULE_DESCRIPTION( "Driver for managing power on IBM ThinkPads" ); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,10) +MODULE_LICENSE( "GPL" ); +#endif + +#ifdef CONFIG_DEVFS_FS +static struct file_operations _fileopsThinkpadpm = { + ioctl: thinkpadpm_ioctl, + open: thinkpadpm_open, + release: thinkpadpm_release, + owner: THIS_MODULE +}; + +static devfs_handle_t _devfs_handleThinkpadpm; +#endif + +/* + * ----------------------------------------------------------------------- + * THE FOLLOWING SECTION WAS COPIED VERBATIM OUT OF THE APM DRIVER v. 1.15 + * ... because the apm driver doesn't export these functions + * ----------------------------------------------------------------------- + */ +#include +#include + +/* + * Define to make the APM BIOS calls zero all data segment registers (so + * that an incorrect BIOS implementation will cause a kernel panic if it + * tries to write to arbitrary memory). + */ +#define APM_ZERO_SEGS + +/* + * Save a segment register away + */ +#define savesegment(seg, where) \ + __asm__ __volatile__("movl %%" #seg ",%0" : "=m" (where)) + +static struct { + unsigned long offset; + unsigned short segment; +} apm_bios_entry; + +/* + * These are the actual BIOS calls. Depending on APM_ZERO_SEGS and + * CONFIG_APM_ALLOW_INTS, we are being really paranoid here! Not only + * are interrupts disabled, but all the segment registers (except SS) + * are saved and zeroed this means that if the BIOS tries to reference + * any data without explicitly loading the segment registers, the kernel + * will fault immediately rather than have some unforeseen circumstances + * for the rest of the kernel. And it will be very obvious! :-) Doing + * this depends on CS referring to the same physical memory as DS so that + * DS can be zeroed before the call. Unfortunately, we can't do anything + * about the stack segment/pointer. Also, we tell the compiler that + * everything could change. + * + * Also, we KNOW that for the non error case of apm_bios_call, there + * is no useful data returned in the low order 8 bits of eax. + */ +#define APM_DO_CLI \ + if (apm_info.allow_ints) \ + __sti(); \ + else \ + __cli(); + +#ifdef APM_ZERO_SEGS +# define APM_DECL_SEGS \ + unsigned int saved_fs; unsigned int saved_gs; +# define APM_DO_SAVE_SEGS \ + savesegment(fs, saved_fs); savesegment(gs, saved_gs) +# define APM_DO_ZERO_SEGS \ + "pushl %%ds\n\t" \ + "pushl %%es\n\t" \ + "xorl %%edx, %%edx\n\t" \ + "mov %%dx, %%ds\n\t" \ + "mov %%dx, %%es\n\t" \ + "mov %%dx, %%fs\n\t" \ + "mov %%dx, %%gs\n\t" +# define APM_DO_POP_SEGS \ + "popl %%es\n\t" \ + "popl %%ds\n\t" +# define APM_DO_RESTORE_SEGS \ + loadsegment(fs, saved_fs); loadsegment(gs, saved_gs) +#else +# define APM_DECL_SEGS +# define APM_DO_SAVE_SEGS +# define APM_DO_ZERO_SEGS +# define APM_DO_POP_SEGS +# define APM_DO_RESTORE_SEGS +#endif + +/** + * apm_bios_call - Make an APM BIOS 32bit call + * @func: APM function to execute + * @ebx_in: EBX register for call entry + * @ecx_in: ECX register for call entry + * @eax: EAX register return + * @ebx: EBX register return + * @ecx: ECX register return + * @edx: EDX register return + * @esi: ESI register return + * + * Make an APM call using the 32bit protected mode interface. The + * caller is responsible for knowing if APM BIOS is configured and + * enabled. This call can disable interrupts for a long period of + * time on some laptops. The return value is in AH and the carry + * flag is loaded into AL. If there is an error, then the error + * code is returned in AH (bits 8-15 of eax) and this function + * returns non-zero. + */ + +static u8 apm_bios_call(u32 func, u32 ebx_in, u32 ecx_in, + u32 *eax, u32 *ebx, u32 *ecx, u32 *edx, u32 *esi) +{ + APM_DECL_SEGS + unsigned long flags; + + __save_flags(flags); + APM_DO_CLI; + APM_DO_SAVE_SEGS; + /* + * N.B. We do NOT need a cld after the BIOS call + * because we always save and restore the flags. + */ + __asm__ __volatile__(APM_DO_ZERO_SEGS + "pushl %%edi\n\t" + "pushl %%ebp\n\t" + "lcall %%cs:" SYMBOL_NAME_STR(apm_bios_entry) "\n\t" + "setc %%al\n\t" + "popl %%ebp\n\t" + "popl %%edi\n\t" + APM_DO_POP_SEGS + : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx), + "=S" (*esi) + : "a" (func), "b" (ebx_in), "c" (ecx_in) + : "memory", "cc"); + APM_DO_RESTORE_SEGS; + __restore_flags(flags); + return *eax & 0xff; +} + +/** + * apm_bios_call_simple - make a simple APM BIOS 32bit call + * @func: APM function to invoke + * @ebx_in: EBX register value for BIOS call + * @ecx_in: ECX register value for BIOS call + * @eax: EAX register on return from the BIOS call + * + * Make a BIOS call that does only returns one value, or just status. + * If there is an error, then the error code is returned in AH + * (bits 8-15 of eax) and this function returns non-zero. This is + * used for simpler BIOS operations. This call may hold interrupts + * off for a long time on some laptops. + */ + +static u8 apm_bios_call_simple(u32 func, u32 ebx_in, u32 ecx_in, u32 *eax) +{ + u8 error; + APM_DECL_SEGS + unsigned long flags; + + __save_flags(flags); + APM_DO_CLI; + APM_DO_SAVE_SEGS; + { + int cx, dx, si; + + /* + * N.B. We do NOT need a cld after the BIOS call + * because we always save and restore the flags. + */ + __asm__ __volatile__(APM_DO_ZERO_SEGS + "pushl %%edi\n\t" + "pushl %%ebp\n\t" + "lcall %%cs:" SYMBOL_NAME_STR(apm_bios_entry) "\n\t" + "setc %%bl\n\t" + "popl %%ebp\n\t" + "popl %%edi\n\t" + APM_DO_POP_SEGS + : "=a" (*eax), "=b" (error), "=c" (cx), "=d" (dx), + "=S" (si) + : "a" (func), "b" (ebx_in), "c" (ecx_in) + : "memory", "cc"); + } + APM_DO_RESTORE_SEGS; + __restore_flags(flags); + return error; +} + +/** + * set_power_state - set the power management state + * @what: which items to transition + * @state: state to transition to + * + * Request an APM change of state for one or more system devices. The + * processor state must be transitioned last of all. what holds the + * class of device in the upper byte and the device number (0xFF for + * all) for the object to be transitioned. + * + * The state holds the state to transition to, which may in fact + * be an acceptance of a BIOS requested state change. + */ + +static int set_power_state(u_short what, u_short state) +{ + u32 eax; + + if (apm_bios_call_simple(APM_FUNC_SET_STATE, what, state, &eax)) + return (eax >> 8) & 0xff; + return APM_SUCCESS; +} + +/* ----------------------------------------------------------------------- */ +/* END OF SECTION COPIED VERBATIM OUT OF THE APM DRIVER */ +/* ----------------------------------------------------------------------- */ + +static int get_power_state(u_short what, u_short *state) +{ + u32 eax; + u32 ecx; + u32 dummy; + + if (apm_bios_call(APM_FUNC_GET_STATE, what, 0, &eax, &dummy, &ecx, + &dummy, &dummy)) + return (eax >> 8) & 0xff; + *state = ecx; + + return APM_SUCCESS; +} + +/* ----------------------------------------------------------------------- */ + + +/****** functions *******/ + +static int thinkpadpm_read_proc( + char *pchBuf, + char **ppchStart, + off_t off, + int intCount, + int *pintEof, + void *data +) { + return snprintf( + pchBuf, intCount, + "%s version %s accessing APM BIOS at 0x%x:0x%lx\n", + _szMyName, _szMyVersion, + apm_bios_entry.segment, + apm_bios_entry.offset + ); +} + +static int get_state( word wWhat, word *pwState ) +{ + int intRtn; + +#ifdef DEBUG + printk(KERN_INFO + "%s: Getting power state for device 0x%x\n", + _szMyName, wWhat + ); +#endif + *pwState = 0x9999; /* ... so we can tell when *pwState wasn't changed */ + intRtn = get_power_state( wWhat, pwState ); + if ( intRtn ) { + printk(KERN_INFO + "%s: Power state of device 0x%x could not be got; 0x%x was returned as the state -- APM error 0x%x\n", + _szMyName, wWhat, *pwState, intRtn + ); + } else { +#ifdef DEBUG + printk(KERN_INFO + "%s: Power state of device 0x%x is 0x%x\n", + _szMyName, wWhat, *pwState + ); +#endif + } + + return intRtn; +} + +static int set_state( word wWhat, word wState ) +{ + int intRtn; + +#ifdef DEBUG + printk(KERN_INFO + "%s: Setting power state for device 0x%x to 0x%x\n", + _szMyName, wWhat, wState + ); +#endif + intRtn = set_power_state( wWhat, wState ); +#ifdef DEBUG + if ( intRtn ) { + printk(KERN_INFO + "%s: Power state of device 0x%x could not be set -- APM error 0x%x\n", + _szMyName, wWhat, intRtn + ); + } +#endif + + return intRtn; +} + +static int thinkpadpm_do_func( + thinkpadpm_inparm_t *pinparmThe, + thinkpadpm_outparm_t *poutparmThe, + flag_t fHasWritePerm +) { + + switch ( pinparmThe->wFunc ) { + case THINKPADPM_FUNC_STATE_GET: + return get_state( pinparmThe->wParm0, (word *)&(poutparmThe->dwParm1) ); + case THINKPADPM_FUNC_STATE_SET: + if ( !fHasWritePerm ) return -EACCES; + return set_state( pinparmThe->wParm0, (word)pinparmThe->dwParm1 ); + default: + return -EINVAL; + } +} + + +int thinkpadpm_do( + unsigned long ulongIoctlArg, + flag_t fCallerHasWritePerm +) { + thinkpadpm_inparm_t inparmThe; + thinkpadpm_outparm_t outparmThe; + unsigned long ulRtnCopy; + int intRtnDo; + + ulRtnCopy = copy_from_user( + &inparmThe, + (byte *)&(((thinkpadpm_ioparm_t *)ulongIoctlArg)->in), + sizeof( inparmThe ) + ); + if ( ulRtnCopy ) return -EFAULT; + + intRtnDo = thinkpadpm_do_func( &inparmThe, &outparmThe, fCallerHasWritePerm ); + + if ( intRtnDo == -EACCES ) { + printk(KERN_ERR + "%s: Caller does not have permission to do this power management act\n", + _szMyName + ); + return -EACCES; + } + + outparmThe.wRc = intRtnDo; + + ulRtnCopy = copy_to_user( + (byte *)&(((thinkpadpm_ioparm_t *)ulongIoctlArg)->out), + &outparmThe, + sizeof( outparmThe ) + ); + if ( ulRtnCopy ) return -EFAULT; + + return outparmThe.wRc ? -ETHINKPAD_SUBDRIVER : 0; +} + +#ifdef CONFIG_DEVFS_FS +static int thinkpadpm_open( + struct inode * pinodeThe, + struct file * pfileThe +) { + + return 0; +} + + +static int thinkpadpm_release( + struct inode * pinodeThe, + struct file * pfileThe +) { + + return 0; +} + + +static flag_t caller_has_w( struct file * pfileThe ) +{ + return ((pfileThe->f_mode) & FMODE_WRITE) ? 1 : 0; +} + + +static int thinkpadpm_ioctl( + struct inode * pinodeThe, + struct file * pfileThe, + unsigned int uintIoctlNum, + unsigned long ulongIoctlArg +) { + +#ifdef DEBUG_VERBOSE + printk( "%s: Doing ioctl number 0x%x\n", _szMyName, uintIoctlNum ); +#endif + + switch ( uintIoctlNum ) { + /* should return at the end of each case block */ + + case IOCTL_THINKPADPM_REQUEST: + return thinkpadpm_do( + ulongIoctlArg, + caller_has_w( pfileThe ) + ); + + default: + /* ioctl number not recognized -- do nothing */ + return -ENOTTY; + + } /* switch */ + + return -ETHINKPAD_PROGRAMMING; /* We should never arrive here */ +} +#endif /* defined(CONFIG_DEVFS_FS) */ + +static int __init thinkpadpm_init( void ) +{ + + /*** Set up APM BIOS interface ***/ + if ( !pm_active ) { + printk(KERN_INFO "thinkpadpm: Power management not active. :-(\n"); + return -ENODEV; + } + if (apm_info.bios.version == 0) { + printk(KERN_INFO "thinkpadpm: No APM BIOS. :-(\n"); + return -ENODEV; + } + if ((apm_info.bios.flags & APM_32_BIT_SUPPORT) == 0) { + printk(KERN_INFO "thinkpadpm: No 32 bit APM BIOS support. :-(\n"); + return -ENODEV; + } + apm_bios_entry.segment = APM_CS; + apm_bios_entry.offset = apm_info.bios.offset; + printk(KERN_INFO + "thinkpadpm: Found APM BIOS version %d.%d flags 0x%02x entry 0x%x:0x%lx. :-)\n", + ((apm_info.bios.version >> 8) & 0xff), + (apm_info.bios.version & 0xff), + apm_info.bios.flags, + apm_bios_entry.segment, + apm_bios_entry.offset + ); + + if ( !thinkpad_ppde || !create_proc_read_entry( + _szProcfile, + S_IFREG | S_IRUGO, + NULL, + thinkpadpm_read_proc, + NULL + ) ) { + printk(KERN_ERR "%s: Could not create_proc_read_entry() /proc/%s\n", _szMyName, _szProcfile ); + } + /* proc entry created */ + +#ifdef CONFIG_DEVFS_FS + _devfs_handleThinkpadpm = devfs_register( + NULL /* dir */, + "thinkpad/thinkpadpm", + DEVFS_FL_DEFAULT | DEVFS_FL_AUTO_DEVNUM, + 0 /* major */, 0 /* minor */, + S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH, + &_fileopsThinkpadpm, + NULL /* info */ + ); + if ( _devfs_handleThinkpadpm == NULL ) { + printk(KERN_ERR "%s: Could not devfs_register(). Aborting.\n", _szMyName ); + return -EIO; + } + /* dev entry created */ +#endif + + inter_module_register( _szImName, THIS_MODULE, &thinkpadpm_do ); + + return 0; +} + + +static void __exit thinkpadpm_exit( void ) +{ + + inter_module_unregister( _szImName ); + +#ifdef CONFIG_DEVFS_FS + devfs_unregister( _devfs_handleThinkpadpm ); +#endif + + remove_proc_entry( _szProcfile, NULL ); + + return; +} + +module_init(thinkpadpm_init); +module_exit(thinkpadpm_exit); diff -urNp thinkpad/drivers/char/thinkpad/thinkpadpm.h 2.4.20pre8aa2/drivers/char/thinkpad/thinkpadpm.h --- thinkpad/drivers/char/thinkpad/thinkpadpm.h Thu Jan 1 01:00:00 1970 +++ 2.4.20pre8aa2/drivers/char/thinkpad/thinkpadpm.h Wed Oct 2 06:42:00 2002 @@ -0,0 +1,73 @@ + +/********************************************************************* + * + * Filename: thinkpadpm.h + * Description: header file for the thinkpadpm driver + * Author: Thomas Hood + * Created: 27 January 2001 + * + * Please report bugs to the author ASAP. + * + * Copyright (c) 2001 J.D. Thomas Hood, All rights reserved + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * To receive a copy of the GNU General Public License, please write + * to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA + * + ********************************************************************/ + +#ifndef __THINKPADPM_H__ +#define __THINKPADPM_H__ + +#include + +/****** defines ******/ + +#define THINKPADPM_FUNC_STATE_GET ((word)0x100) +#define THINKPADPM_FUNC_STATE_SET ((word)0x101) + +#define THINKPADPM_DEVICE_SERIAL_1 (APM_DEVICE_SERIAL) +#define THINKPADPM_DEVICE_SERIAL_2 (APM_DEVICE_SERIAL | 0x0001) +#define THINKPADPM_DEVICE_PARALLEL (APM_DEVICE_PARALLEL) + +#define THINKPADPM_STATE_READY (APM_STATE_READY) +#define THINKPADPM_STATE_OFF (APM_STATE_OFF) + + +/*** thinpadpm module input parameters ***/ +typedef struct _thinkpadpm_inparm { + word wFunc; + word wParm0; + dword dwParm1; +} thinkpadpm_inparm_t; + +/*** thinkpadpm module output parameters ***/ +typedef struct _thinkpadpm_outparm { + word wRc; + word wParm0; + dword dwParm1; +} thinkpadpm_outparm_t; + +typedef union _thinkpadpm_ioparm_t { + thinkpadpm_inparm_t in; + thinkpadpm_outparm_t out; +} thinkpadpm_ioparm_t; + +/****** declarations ******/ + +int thinkpadpm_do( + unsigned long ulongIoctlArg, + flag_t fCallerHasWritePerm +); + +#endif /* __THINKPADPM_H__ */