mirror of
https://github.com/linux-thinkpad/tp_smapi.git
synced 2024-10-26 07:34:36 +03:00
import of tp-smapi version 0.32
This commit is contained in:
parent
c422dec63d
commit
04dc589904
14
CHANGES
14
CHANGES
@ -1,5 +1,19 @@
|
||||
Change history for tp_smapi:
|
||||
|
||||
0.32 2007-07-28
|
||||
---------------------
|
||||
- hdaps: Added a second input device which publishes the raw sensor position,
|
||||
without joystick fuzz. In conjunction with a new hdapsd, this lets us
|
||||
avoid the frequent redundant interrupts caused by hdapsd.
|
||||
- hdaps: Stop polling the hardware when no one is listening. This prevents
|
||||
unnecessary interrupts on tickless kernel. (Contributed by Michael Riepe.)
|
||||
- In the patch generated by "make patch", thinkpad_ec and tp_smapi now reside
|
||||
under drivers/misc instead of drivers/platform.
|
||||
- "make patch" fixed for kernel 2.6.22.
|
||||
- Removed kludge for kernels lacking the DMI OEM String decode patch.
|
||||
- Now requires kernel >= 2.6.19 (due to above).
|
||||
- Removed the useless "enable_pci_power_saving_on_boot" sysfs attribute.
|
||||
|
||||
0.31 2007-03-07
|
||||
---------------------
|
||||
Visible changes:
|
||||
|
63
Makefile
63
Makefile
@ -8,7 +8,7 @@ KBUILD := $(KBASE)/build
|
||||
MOD_DIR := $(KBASE)/kernel
|
||||
PWD := $(shell pwd)
|
||||
IDIR := include/linux
|
||||
TP_DIR := drivers/firmware
|
||||
TP_DIR := drivers/misc
|
||||
TP_MODULES := thinkpad_ec.o tp_smapi.o
|
||||
SHELL := /bin/bash
|
||||
|
||||
@ -21,8 +21,8 @@ endif
|
||||
|
||||
DEBUG := 0
|
||||
|
||||
ifneq ($(shell [ -f $(KSRC)/include/linux/platform_device.h ] && echo 1),1)
|
||||
$(error This driver requires kernel 2.6.15 or newer, and matching kernel headers.)
|
||||
ifneq ($(shell [ -f $(KSRC)/include/linux/aio_abi.h ] && echo 1),1)
|
||||
$(error This driver requires kernel 2.6.19 or newer, and matching kernel sources. You may need to set KSRC and KBUILD to find these.)
|
||||
endif
|
||||
|
||||
.PHONY: default clean modules load unload install patch check_hdaps mk-hdaps.diff
|
||||
@ -34,7 +34,7 @@ export TP_MODULES
|
||||
default: modules
|
||||
|
||||
# Build the modules thinkpad_ec.ko, tp_smapi.ko and (if HDAPS=1) hdaps.ko
|
||||
modules: $(KSRC) dmi_ec_oem_string.h $(patsubst %.o,%.c,$(TP_MODULES))
|
||||
modules: $(KSRC) $(patsubst %.o,%.c,$(TP_MODULES))
|
||||
$(MAKE) -C $(KSRC) M=$(PWD) O=$(KBUILD) modules
|
||||
|
||||
clean:
|
||||
@ -44,7 +44,6 @@ clean:
|
||||
rm -f *~ diff/*~ *.orig diff/*.orig *.rej diff/*.rej
|
||||
rm -f tp_smapi-*-for-*.patch
|
||||
rm -fr .tmp_versions Modules.symvers diff/hdaps.diff.tmp
|
||||
rm -f dmi_ec_oem_string.h
|
||||
|
||||
load: check_hdaps unload modules
|
||||
@( [ `id -u` == 0 ] || { echo "Must be root to load modules"; exit 1; } )
|
||||
@ -71,6 +70,7 @@ endif
|
||||
install: modules
|
||||
@( [ `id -u` == 0 ] || { echo "Must be root to install modules"; exit 1; } )
|
||||
rm -f $(MOD_DIR)/$(TP_DIR)/{thinkpad_ec,tp_smapi,tp_base}.ko
|
||||
rm -f $(MOD_DIR)/drivers/firmware/{thinkpad_ec,tp_smapi,tp_base}.ko
|
||||
rm -f $(MOD_DIR)/extra/{thinkpad_ec,tp_smapi,tp_base}.ko
|
||||
ifeq ($(HDAPS),1)
|
||||
rm -f $(MOD_DIR)/drivers/hwmon/hdaps.ko
|
||||
@ -80,29 +80,6 @@ endif
|
||||
depmod -a
|
||||
|
||||
|
||||
# Ugly kludge for kernels that can't report OEM Strings DMI information:
|
||||
ifeq ($(shell grep -q DMI_DEV_TYPE_OEM_STRING $(KSRC)/include/linux/dmi.h || echo 1),1)
|
||||
ifeq ($(shell sudo /usr/sbin/dmidecode | grep -q dmidecode || echo 1),1)
|
||||
$(error Could not run /usr/sbin/dmidecode. Must be root or get sudo password to do that.)
|
||||
endif
|
||||
GEN_DMI_DECODE_PATCH= \
|
||||
cat $(PWD)/diff/dmi-decode-and-save-oem-string-information.patch | \
|
||||
{ [ -f $(KSRC)/drivers/firmware/dmi_scan.c ] && cat || \
|
||||
perl -pe 's@drivers/firmware/dmi_scan.c@arch/i386/kernel/dmi_scan.c@g'; }
|
||||
DMI_EC_OEM_STRING:=$(shell sudo /usr/sbin/dmidecode | grep 'IBM ThinkPad Embedded Controller')
|
||||
dmi_ec_oem_string.h: $(KSRC)/include/linux/dmi.h
|
||||
@echo 'WARNING: Your kernel does not have this patch applied:' >&2
|
||||
@echo ' dmi-decode-and-save-oem-string-information.patch' >&2
|
||||
@echo ' So I am hard-coding machine-specific DMI information into your driver.' >&2
|
||||
echo '/* This is machine-specific DMI information. */' > $@
|
||||
echo '#define DMI_EC_OEM_STRING_KLUDGE "$(DMI_EC_OEM_STRING)"' >> $@
|
||||
else
|
||||
NO_DMI_KLUDGE_DIFF=$(PWD)/diff/thinkpad_ec-no-dmi-kludge.diff
|
||||
GEN_DMI_DECODE_PATCH=cat /dev/null
|
||||
dmi_ec_oem_string.h: $(KSRC)/include/linux/dmi.h
|
||||
echo '/* Intentionally empty. You have proper DMI OEM Strings. */' > $@
|
||||
endif
|
||||
|
||||
#####################################################################
|
||||
# Generate a stand-alone kernel patch
|
||||
|
||||
@ -116,8 +93,8 @@ SMAPI_IN_PATCH := 1
|
||||
HDAPS_IN_PATCH := 1
|
||||
|
||||
patch:
|
||||
TMPDIR=`mktemp -d /tmp/tp_smapi-patch.XXXXXX` &&\
|
||||
echo "Work directory: $$TMPDIR" &&\
|
||||
@TMPDIR=`mktemp -d /tmp/tp_smapi-patch.XXXXXX` &&\
|
||||
echo "Working directory: $$TMPDIR" &&\
|
||||
cd $$TMPDIR &&\
|
||||
mkdir -p $(ORG)/$(TP_DIR) &&\
|
||||
mkdir -p $(ORG)/$(IDIR) &&\
|
||||
@ -127,32 +104,32 @@ patch:
|
||||
cp -r $(ORG) $(NEW) &&\
|
||||
\
|
||||
if [ "$(BASE_IN_PATCH)" == 1 ]; then \
|
||||
patch --no-backup-if-mismatch -s -d $(NEW) -i $(PWD)/diff/Kconfig-thinkpad_ec.diff -p1 &&\
|
||||
cp $(PWD)/thinkpad_ec.c $(NEW)/$(TP_DIR)/thinkpad_ec.c &&\
|
||||
cp $(PWD)/thinkpad_ec.h $(NEW)/$(IDIR)/thinkpad_ec.h &&\
|
||||
patch --no-backup-if-mismatch -s -d $(NEW)/$(TP_DIR) -i $(PWD)/diff/thinkpad_ec-no-dmi-kludge.diff -p1 &&\
|
||||
sed -i -e '$$aobj-$$(CONFIG_THINKPAD_EC) += thinkpad_ec.o' $(NEW)/$(TP_DIR)/Makefile \
|
||||
cp $(PWD)/thinkpad_ec.c $(NEW)/$(TP_DIR)/thinkpad_ec.c &&\
|
||||
cp $(PWD)/thinkpad_ec.h $(NEW)/$(IDIR)/thinkpad_ec.h &&\
|
||||
perl -i -pe 'print `cat $(PWD)/diff/Kconfig-thinkpad_ec.add` if m/^endmenu$$/' $(NEW)/$(TP_DIR)/Kconfig &&\
|
||||
sed -i -e '$$aobj-$$(CONFIG_THINKPAD_EC) += thinkpad_ec.o' $(NEW)/$(TP_DIR)/Makefile \
|
||||
; fi &&\
|
||||
\
|
||||
if [ "$(HDAPS_IN_PATCH)" == 1 ]; then \
|
||||
cp $(PWD)/hdaps.c $(NEW)/drivers/hwmon/ &&\
|
||||
patch --no-backup-if-mismatch -s -d $(NEW) -i $(PWD)/diff/Kconfig-hdaps-select-thinkpad_ec -p1 \
|
||||
cp $(PWD)/hdaps.c $(NEW)/drivers/hwmon/ &&\
|
||||
perl -i -0777 -pe 's/(config SENSORS_HDAPS\n\ttristate [^\n]+\n\tdepends [^\n]+\n)/$$1\tselect THINKPAD_EC\n/' $(NEW)/drivers/hwmon/Kconfig \
|
||||
; fi &&\
|
||||
\
|
||||
if [ "$(SMAPI_IN_PATCH)" == 1 ]; then \
|
||||
sed -i -e '$$aobj-$$(CONFIG_TP_SMAPI) += tp_smapi.o' $(NEW)/$(TP_DIR)/Makefile &&\
|
||||
cp $(PWD)/tp_smapi.c $(NEW)/$(TP_DIR)/tp_smapi.c &&\
|
||||
patch --no-backup-if-mismatch -s -d $(NEW) -i $(PWD)/diff/Kconfig-tp_smapi.diff -p1 &&\
|
||||
mkdir -p $(NEW)/Documentation &&\
|
||||
perl -0777 -pe 's/\n(Installation\n---+|Conflict with HDAPS\n---+|Files in this package\n---+|Setting and getting CD-ROM speed:\n).*?\n(?=[^\n]*\n-----)/\n/gs' $(PWD)/README > $(NEW)/Documentation/tp_smapi.txt \
|
||||
sed -i -e '$$aobj-$$(CONFIG_TP_SMAPI) += tp_smapi.o' $(NEW)/$(TP_DIR)/Makefile &&\
|
||||
perl -i -pe 'print `cat $(PWD)/diff/Kconfig-tp_smapi.add` if m/^endmenu$$/' $(NEW)/$(TP_DIR)/Kconfig &&\
|
||||
cp $(PWD)/tp_smapi.c $(NEW)/$(TP_DIR)/tp_smapi.c &&\
|
||||
mkdir -p $(NEW)/Documentation &&\
|
||||
perl -0777 -pe 's/\n(Installation\n---+|Conflict with HDAPS\n---+|Files in this package\n---+|Setting and getting CD-ROM speed:\n).*?\n(?=[^\n]*\n-----)/\n/gs' $(PWD)/README > $(NEW)/Documentation/tp_smapi.txt \
|
||||
; fi &&\
|
||||
\
|
||||
{ diff -dNurp $(ORG) $(NEW) > patch \
|
||||
|| [ $$? -lt 2 ]; } &&\
|
||||
$(GEN_DMI_DECODE_PATCH) >> patch &&\
|
||||
{ echo "Generated for $(KVER) in $(KSRC)"; echo; diffstat patch; echo; echo; cat patch; } \
|
||||
> $(PWD)/${PATCH} &&\
|
||||
rm -r $$TMPDIR
|
||||
@echo
|
||||
@diffstat ${PATCH}
|
||||
@echo -e "\nPatch file created:\n ${PATCH}"
|
||||
@echo -e "To apply, use:\n patch -p1 -d ${KSRC} < ${PATCH}"
|
||||
|
||||
|
44
README
44
README
@ -1,4 +1,4 @@
|
||||
tp_smapi version 0.31
|
||||
tp_smapi version 0.32
|
||||
IBM ThinkPad hardware functions driver
|
||||
|
||||
Author: Shem Multinymous <multinymous@gmail.com>
|
||||
@ -208,6 +208,26 @@ Some of the battery status is also visible through ACPI (/proc/acpi/battery/).
|
||||
The charging control files (*_charge_thresh, inhibit_charge_minutes and
|
||||
force_discrage*) don't have this problem.
|
||||
|
||||
Beside resolving the conflict with thinkpad_ec and tp_smapi, the modified hdaps
|
||||
has several improvements:
|
||||
|
||||
- It fixes reliability and improves support for recent ThinkPad models (*60 and
|
||||
newer), since unlike the mainline driver, it correctly follows the Embedded
|
||||
Controller communication protocol.
|
||||
- It provides the ability to control polling rate (and several other parameters).
|
||||
- It provides a second input device, which publishes the raw accelerometer
|
||||
measurements (without the fuzzing needed for joystick emulation). This input
|
||||
device can be matched by a udev rule such as the following:
|
||||
KERNEL=="event[0-9]*", ATTRS{phys}=="hdaps/input1",
|
||||
ATTRS{modalias}=="input:b0019v1014p5054e4801-*",
|
||||
SYMLINK+="input/hdaps/accelerometer-event
|
||||
|
||||
|
||||
Licensing note: all my changes to the HDAPS driver are licensed under the
|
||||
GPL version 2 or, at your option and to the extent allowed by derivation from
|
||||
prior works, any later version. My version of hdaps is derived work from the
|
||||
mainline version, which at the time of writing is available only under
|
||||
GPL version 2.
|
||||
|
||||
Bug reporting
|
||||
-------------
|
||||
@ -227,6 +247,8 @@ README
|
||||
This file.
|
||||
CHANGES
|
||||
Change log.
|
||||
TODO
|
||||
Pending improvements.
|
||||
Makefile
|
||||
Makefile (see "Installation" above).
|
||||
tp_smapi.c
|
||||
@ -237,32 +259,12 @@ thinkpad_ec.*
|
||||
hdaps.c
|
||||
Modified version of hdaps.c driver from mainline kernel, patched to use
|
||||
thinkpad_ec and several other improvements.
|
||||
diff/dmi-decode-and-save-oem-string-information
|
||||
A patch from the kernel -mm series, needed for hardware detection.
|
||||
If you don't have it, "make load" and "make install" will use a workaround
|
||||
kludge, and the result of "make patch" will include this patch.
|
||||
diff/* (excluding above)
|
||||
Used by "make patch" to create a clean stand-alone patch.
|
||||
include/
|
||||
Contains a symlink to make gcc happy in kernel builds.
|
||||
|
||||
|
||||
Ideas for improvement
|
||||
---------------------
|
||||
(The best way to get these done is to send a patch.)
|
||||
|
||||
Don't create /sys files for unsupported functions, and don't access those
|
||||
functions on suspend+resume (requires probing on module load or a huge
|
||||
white/blacklist).
|
||||
|
||||
Make inhibit_charge_minutes return the time left, not the time originally
|
||||
set (as returned by the SMAPI BIOS). Requires remembering when
|
||||
inhibit_charge_minutes was set and comparing to current time.
|
||||
|
||||
Save and and restore inhibit_charge_minutes across suspend-to-disk, as done
|
||||
for charge thresholds (requires the above time calculations too).
|
||||
|
||||
|
||||
More about SMAPI
|
||||
----------------
|
||||
|
||||
|
18
TODO
Normal file
18
TODO
Normal file
@ -0,0 +1,18 @@
|
||||
Ideas for improvement
|
||||
---------------------
|
||||
(The best way to get these done is to send a patch.)
|
||||
|
||||
Don't create /sys files for unsupported functions, and don't access those
|
||||
functions on suspend+resume (requires probing on module load or a huge
|
||||
white/blacklist).
|
||||
|
||||
Make inhibit_charge_minutes return the time left, not the time originally
|
||||
set (as returned by the SMAPI BIOS). Requires remembering when
|
||||
inhibit_charge_minutes was set and comparing to current time.
|
||||
|
||||
Save and and restore inhibit_charge_minutes across suspend-to-disk, as done
|
||||
for charge thresholds (requires the above time calculations too).
|
||||
|
||||
Use the new Linux battery model considered (not yet merged into mainline).
|
||||
|
||||
Stop hdaps sampling when neither input devices nor sysfs are being accessed.
|
@ -1,10 +0,0 @@
|
||||
--- a/drivers/hwmon/Kconfig
|
||||
+++ b/drivers/hwmon/Kconfig
|
||||
@@ -494,6 +494,7 @@
|
||||
config SENSORS_HDAPS
|
||||
tristate "IBM Hard Drive Active Protection System (hdaps)"
|
||||
depends on HWMON && INPUT && X86
|
||||
+ select THINKPAD_EC
|
||||
default n
|
||||
help
|
||||
This driver provides support for the IBM Hard Drive Active Protection
|
8
diff/Kconfig-thinkpad_ec.add
Normal file
8
diff/Kconfig-thinkpad_ec.add
Normal file
@ -0,0 +1,8 @@
|
||||
config THINKPAD_EC
|
||||
tristate
|
||||
depends on X86
|
||||
---help---
|
||||
This is a low-level driver for accessing the ThinkPad H8S embedded
|
||||
controller over the LPC bus (not to be confused with the ACPI Embedded
|
||||
Controller interface).
|
||||
|
@ -1,10 +0,0 @@
|
||||
--- a/drivers/firmware/Kconfig
|
||||
+++ b/drivers/firmware/Kconfig
|
||||
@@ -85,4 +85,7 @@
|
||||
Say Y or M here to enable the driver for use by Dell systems
|
||||
management software such as Dell OpenManage.
|
||||
|
||||
+config THINKPAD_EC
|
||||
+ tristate
|
||||
+
|
||||
endmenu
|
12
diff/Kconfig-tp_smapi.add
Normal file
12
diff/Kconfig-tp_smapi.add
Normal file
@ -0,0 +1,12 @@
|
||||
config TP_SMAPI
|
||||
tristate "ThinkPad SMAPI Support"
|
||||
depends on X86
|
||||
select THINKPAD_EC
|
||||
default n
|
||||
help
|
||||
This adds SMAPI support on IBM ThinkPads, mostly used for battery
|
||||
charge control. For more information about this driver see
|
||||
<http://www.thinkwiki.org/wiki/tp_smapi>.
|
||||
|
||||
If you have an IBM ThinkPad laptop, say Y or M here.
|
||||
|
@ -1,19 +0,0 @@
|
||||
--- linux-2.6.15-rc5-orig/drivers/firmware/Kconfig 2005-12-13 19:13:57.000000000 +0200
|
||||
+++ linux-2.6.15-rc5-patched/drivers/firmware/Kconfig 2005-12-21 00:35:13.000000000 +0200
|
||||
@@ -88,4 +88,16 @@
|
||||
config THINKPAD_EC
|
||||
tristate
|
||||
|
||||
+config TP_SMAPI
|
||||
+ tristate "ThinkPad SMAPI Support"
|
||||
+ depends on X86
|
||||
+ select THINKPAD_EC
|
||||
+ default n
|
||||
+ help
|
||||
+ This adds SMAPI support on IBM ThinkPads, mostly used for battery
|
||||
+ charge control. For more information about this driver see
|
||||
+ <http://www.thinkwiki.org/wiki/tp_smapi>.
|
||||
+
|
||||
+ If you have an IBM ThinkPad laptop, say Y or M here.
|
||||
+
|
||||
endmenu
|
@ -1,77 +0,0 @@
|
||||
Subject: DMI: Decode and save OEM String information
|
||||
From: "Shem Multinymous" <multinymous@gmail.com>
|
||||
|
||||
This teaches dmi_decode() how to decode and save OEM Strings (type 11) DMI
|
||||
information, which is currently discarded silently. Existing code using
|
||||
DMI is not affected. Follows the "System Management BIOS (SMBIOS)
|
||||
Specification" (http://www.dmtf.org/standards/smbios), and also the
|
||||
userspace dmidecode.c code.
|
||||
|
||||
OEM Strings are the only safe way to identify some hardware, e.g., the
|
||||
ThinkPad embedded controller used by the soon-to-be-submitted tp_smapi
|
||||
driver. This will also let us eliminate the long whitelist in the mainline
|
||||
hdaps driver (in a future patch).
|
||||
|
||||
Signed-off-by: Shem Multinymous <multinymous@gmail.com>
|
||||
Cc: Bjorn Helgaas <bjorn.helgaas@hp.com>
|
||||
Signed-off-by: Andrew Morton <akpm@osdl.org>
|
||||
---
|
||||
|
||||
drivers/firmware/dmi_scan.c | 23 +++++++++++++++++++++++
|
||||
include/linux/dmi.h | 3 ++-
|
||||
2 files changed, 25 insertions(+), 1 deletion(-)
|
||||
|
||||
diff -puN drivers/firmware/dmi_scan.c~dmi-decode-and-save-oem-string-information drivers/firmware/dmi_scan.c
|
||||
--- a/drivers/firmware/dmi_scan.c~dmi-decode-and-save-oem-string-information
|
||||
+++ a/drivers/firmware/dmi_scan.c
|
||||
@@ -123,6 +123,26 @@ static void __init dmi_save_devices(stru
|
||||
dev->type = *d++ & 0x7f;
|
||||
dev->name = dmi_string(dm, *d);
|
||||
dev->device_data = NULL;
|
||||
+ list_add(&dev->list, &dmi_devices);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static void __init dmi_save_oem_strings_devices(struct dmi_header *dm)
|
||||
+{
|
||||
+ int i, count = *(u8 *)(dm + 1);
|
||||
+ struct dmi_device *dev;
|
||||
+
|
||||
+ for (i = 1; i <= count; i++) {
|
||||
+ dev = dmi_alloc(sizeof(*dev));
|
||||
+ if (!dev) {
|
||||
+ printk(KERN_ERR
|
||||
+ "dmi_save_oem_strings_devices: out of memory.\n");
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ dev->type = DMI_DEV_TYPE_OEM_STRING;
|
||||
+ dev->name = dmi_string(dm, i);
|
||||
+ dev->device_data = NULL;
|
||||
|
||||
list_add(&dev->list, &dmi_devices);
|
||||
}
|
||||
@@ -181,6 +201,9 @@ static void __init dmi_decode(struct dmi
|
||||
case 10: /* Onboard Devices Information */
|
||||
dmi_save_devices(dm);
|
||||
break;
|
||||
+ case 11: /* OEM Strings */
|
||||
+ dmi_save_oem_strings_devices(dm);
|
||||
+ break;
|
||||
case 38: /* IPMI Device Information */
|
||||
dmi_save_ipmi_device(dm);
|
||||
}
|
||||
diff -puN include/linux/dmi.h~dmi-decode-and-save-oem-string-information include/linux/dmi.h
|
||||
--- a/include/linux/dmi.h~dmi-decode-and-save-oem-string-information
|
||||
+++ a/include/linux/dmi.h
|
||||
@@ -27,7 +27,8 @@ enum dmi_device_type {
|
||||
DMI_DEV_TYPE_ETHERNET,
|
||||
DMI_DEV_TYPE_TOKENRING,
|
||||
DMI_DEV_TYPE_SOUND,
|
||||
- DMI_DEV_TYPE_IPMI = -1
|
||||
+ DMI_DEV_TYPE_IPMI = -1,
|
||||
+ DMI_DEV_TYPE_OEM_STRING = -2
|
||||
};
|
||||
|
||||
struct dmi_header {
|
||||
_
|
@ -1,12 +0,0 @@
|
||||
--- orig/thinkpad_ec.c 2006-08-02 00:00:00.000000000 +0000
|
||||
+++ no-dmi-kludge/thinkpad_ec.c 2006-08-02 00:00:00.000000000 +0000
|
||||
@@ -402,9 +402,4 @@ static int __init check_for_embedded_con
|
||||
};
|
||||
-#include "dmi_ec_oem_string.h"
|
||||
-#ifdef DMI_EC_OEM_STRING_KLUDGE
|
||||
- return (strstr(DMI_EC_OEM_STRING_KLUDGE, "IBM ThinkPad Embedded Controller")) ||
|
||||
-#else
|
||||
return dmi_find_substring(DMI_DEV_TYPE_OEM_STRING,
|
||||
"IBM ThinkPad Embedded Controller") ||
|
||||
-#endif
|
||||
dmi_check_system(tp_whitelist);
|
106
hdaps.c
106
hdaps.c
@ -32,9 +32,10 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/dmi.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/thinkpad_ec.h>
|
||||
#include <linux/pci_ids.h>
|
||||
|
||||
/* Embedded controller accelerometer read command and its result: */
|
||||
static const struct thinkpad_ec_row ec_accel_args =
|
||||
@ -62,9 +63,16 @@ static const struct thinkpad_ec_row ec_accel_args =
|
||||
#define HDAPS_INPUT_FLAT 4
|
||||
#define KMACT_REMEMBER_PERIOD (HZ/10) /* keyboard/mouse persistance */
|
||||
|
||||
/* Input IDs */
|
||||
#define HDAPS_INPUT_VENDOR PCI_VENDOR_ID_IBM
|
||||
#define HDAPS_INPUT_PRODUCT 0x5054 /* "TP", shared with thinkpad_acpi */
|
||||
#define HDAPS_INPUT_JS_VERSION 0x6801 /* Joystick emulation input device */
|
||||
#define HDAPS_INPUT_RAW_VERSION 0x4801 /* Raw accelerometer input device */
|
||||
|
||||
static struct timer_list hdaps_timer;
|
||||
static struct platform_device *pdev;
|
||||
static struct input_dev *hdaps_idev;
|
||||
static struct input_dev *hdaps_idev; /* joystick-like device with fuzz */
|
||||
static struct input_dev *hdaps_idev_raw; /* raw hdaps sensor readouts */
|
||||
static unsigned int hdaps_invert;
|
||||
static int needs_calibration;
|
||||
|
||||
@ -84,6 +92,11 @@ static int rest_x, rest_y; /* calibrated rest position */
|
||||
/* Last time we saw keyboard and mouse activity: */
|
||||
static u64 last_keyboard_jiffies = INITIAL_JIFFIES;
|
||||
static u64 last_mouse_jiffies = INITIAL_JIFFIES;
|
||||
static u64 last_update_jiffies = INITIAL_JIFFIES;
|
||||
|
||||
/* input device use count */
|
||||
static int hdaps_users;
|
||||
static DEFINE_MUTEX(hdaps_users_mtx);
|
||||
|
||||
/* Some models require an axis transformation to the standard reprsentation */
|
||||
static void transform_axes(int *x, int *y)
|
||||
@ -144,6 +157,7 @@ static int __hdaps_update(int fast)
|
||||
|
||||
temperature = data.val[EC_ACCEL_IDX_TEMP1];
|
||||
|
||||
last_update_jiffies = get_jiffies_64();
|
||||
stale_readout = 0;
|
||||
if (needs_calibration) {
|
||||
rest_x = pos_x;
|
||||
@ -164,9 +178,11 @@ static int __hdaps_update(int fast)
|
||||
*/
|
||||
static int hdaps_update(void)
|
||||
{
|
||||
u64 age = get_jiffies_64() - last_update_jiffies;
|
||||
int total, ret;
|
||||
if (!stale_readout) /* already updated recently? */
|
||||
return 0;
|
||||
|
||||
if (!stale_readout && age < (9*HZ)/(10*sampling_rate))
|
||||
return 0; /* already updated recently */
|
||||
for (total=0; total<READ_TIMEOUT_MSECS; total+=RETRY_MSECS) {
|
||||
ret = thinkpad_ec_lock();
|
||||
if (ret)
|
||||
@ -419,7 +435,11 @@ static int hdaps_resume(struct platform_device *dev)
|
||||
int ret = hdaps_device_init();
|
||||
if (ret)
|
||||
return ret;
|
||||
mod_timer(&hdaps_timer, jiffies + HZ/sampling_rate);
|
||||
|
||||
mutex_lock(&hdaps_users_mtx);
|
||||
if (hdaps_users)
|
||||
mod_timer(&hdaps_timer, jiffies + HZ/sampling_rate);
|
||||
mutex_unlock(&hdaps_users_mtx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -471,6 +491,9 @@ keep_active:
|
||||
input_report_abs(hdaps_idev, ABS_X, pos_x - rest_x);
|
||||
input_report_abs(hdaps_idev, ABS_Y, pos_y - rest_y);
|
||||
input_sync(hdaps_idev);
|
||||
input_report_abs(hdaps_idev_raw, ABS_X, pos_x);
|
||||
input_report_abs(hdaps_idev_raw, ABS_Y, pos_y);
|
||||
input_sync(hdaps_idev_raw);
|
||||
mod_timer(&hdaps_timer, jiffies + HZ/sampling_rate);
|
||||
}
|
||||
|
||||
@ -563,7 +586,7 @@ static ssize_t hdaps_sampling_rate_store(
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
int rate, ret;
|
||||
if (sscanf(buf, "%d", &rate) != 1 || rate>HZ || rate<0) {
|
||||
if (sscanf(buf, "%d", &rate) != 1 || rate>HZ || rate<=0) {
|
||||
printk(KERN_WARNING
|
||||
"must have 0<input_sampling_rate<=HZ=%d\n", HZ);
|
||||
return -EINVAL;
|
||||
@ -645,6 +668,28 @@ static ssize_t hdaps_fake_data_mode_show(
|
||||
return sprintf(buf, "%d\n", fake_data_mode);
|
||||
}
|
||||
|
||||
static int hdaps_mousedev_open(struct input_dev *dev)
|
||||
{
|
||||
if (!try_module_get(THIS_MODULE))
|
||||
return -ENODEV;
|
||||
|
||||
mutex_lock(&hdaps_users_mtx);
|
||||
if (hdaps_users++ == 0) /* first input user */
|
||||
mod_timer(&hdaps_timer, jiffies + HZ/sampling_rate);
|
||||
mutex_unlock(&hdaps_users_mtx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void hdaps_mousedev_close(struct input_dev *dev)
|
||||
{
|
||||
mutex_lock(&hdaps_users_mtx);
|
||||
if (--hdaps_users == 0) /* no input users left */
|
||||
del_timer_sync(&hdaps_timer);
|
||||
mutex_unlock(&hdaps_users_mtx);
|
||||
|
||||
module_put(THIS_MODULE);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(position, 0444, hdaps_position_show, NULL);
|
||||
static DEVICE_ATTR(temp1, 0444, hdaps_temp1_show, NULL);
|
||||
/* "temp1" instead of "temperature" is hwmon convention */
|
||||
@ -685,7 +730,7 @@ static struct attribute_group hdaps_attribute_group = {
|
||||
/* Module stuff */
|
||||
|
||||
/* hdaps_dmi_match_invert - found an inverted match. */
|
||||
static int hdaps_dmi_match_invert(struct dmi_system_id *id)
|
||||
static int __init hdaps_dmi_match_invert(struct dmi_system_id *id)
|
||||
{
|
||||
hdaps_invert = 1;
|
||||
printk(KERN_INFO "hdaps: %s detected, inverting axes\n",
|
||||
@ -693,7 +738,7 @@ static int hdaps_dmi_match_invert(struct dmi_system_id *id)
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define HDAPS_DMI_MATCH_INVERT(vendor,model) { \
|
||||
#define HDAPS_DMI_MATCH_INVERT(vendor, model) { \
|
||||
.ident = vendor " " model, \
|
||||
.callback = hdaps_dmi_match_invert, \
|
||||
.matches = { \
|
||||
@ -706,9 +751,7 @@ static int __init hdaps_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* List of models with abnormal axis configuration.
|
||||
Note that HDAPS_DMI_MATCH_NORMAL("ThinkPad T42") would match
|
||||
"ThinkPad T42p", so the order of the entries matters */
|
||||
/* List of models with abnormal axis configuration. */
|
||||
struct dmi_system_id hdaps_whitelist[] = {
|
||||
HDAPS_DMI_MATCH_INVERT("IBM","ThinkPad R50p"),
|
||||
HDAPS_DMI_MATCH_INVERT("IBM","ThinkPad T41p"),
|
||||
@ -743,13 +786,26 @@ static int __init hdaps_init(void)
|
||||
goto out_group;
|
||||
}
|
||||
|
||||
hdaps_idev_raw = input_allocate_device();
|
||||
if (!hdaps_idev_raw) {
|
||||
ret = -ENOMEM;
|
||||
goto out_idev_first;
|
||||
}
|
||||
|
||||
/* calibration for the input device (deferred to avoid delay) */
|
||||
needs_calibration = 1;
|
||||
|
||||
/* initialize the input class */
|
||||
hdaps_idev->name = "hdaps";
|
||||
/* initialize the joystick-like fuzzed input device */
|
||||
hdaps_idev->name = "ThinkPad HDAPS joystick emulation";
|
||||
hdaps_idev->phys = "hdaps/input0";
|
||||
hdaps_idev->id.bustype = BUS_HOST;
|
||||
hdaps_idev->id.vendor = HDAPS_INPUT_VENDOR;
|
||||
hdaps_idev->id.product = HDAPS_INPUT_PRODUCT;
|
||||
hdaps_idev->id.version = HDAPS_INPUT_JS_VERSION;
|
||||
hdaps_idev->cdev.dev = &pdev->dev;
|
||||
hdaps_idev->evbit[0] = BIT(EV_ABS);
|
||||
hdaps_idev->open = hdaps_mousedev_open;
|
||||
hdaps_idev->close = hdaps_mousedev_close;
|
||||
input_set_abs_params(hdaps_idev, ABS_X,
|
||||
-256, 256, HDAPS_INPUT_FUZZ, HDAPS_INPUT_FLAT);
|
||||
input_set_abs_params(hdaps_idev, ABS_Y,
|
||||
@ -759,12 +815,32 @@ static int __init hdaps_init(void)
|
||||
if (ret)
|
||||
goto out_idev;
|
||||
|
||||
mod_timer(&hdaps_timer, jiffies + HZ/sampling_rate);
|
||||
/* initialize the raw data input device */
|
||||
hdaps_idev_raw->name = "ThinkPad HDAPS accelerometer data";
|
||||
hdaps_idev_raw->phys = "hdaps/input1";
|
||||
hdaps_idev_raw->id.bustype = BUS_HOST;
|
||||
hdaps_idev_raw->id.vendor = HDAPS_INPUT_VENDOR;
|
||||
hdaps_idev_raw->id.product = HDAPS_INPUT_PRODUCT;
|
||||
hdaps_idev_raw->id.version = HDAPS_INPUT_RAW_VERSION;
|
||||
hdaps_idev_raw->cdev.dev = &pdev->dev;
|
||||
hdaps_idev_raw->evbit[0] = BIT(EV_ABS);
|
||||
hdaps_idev_raw->open = hdaps_mousedev_open;
|
||||
hdaps_idev_raw->close = hdaps_mousedev_close;
|
||||
input_set_abs_params(hdaps_idev_raw, ABS_X, -32768, 32767, 0, 0);
|
||||
input_set_abs_params(hdaps_idev_raw, ABS_Y, -32768, 32767, 0, 0);
|
||||
|
||||
ret = input_register_device(hdaps_idev_raw);
|
||||
if (ret)
|
||||
goto out_idev_reg_first;
|
||||
|
||||
printk(KERN_INFO "hdaps: driver successfully loaded.\n");
|
||||
return 0;
|
||||
|
||||
out_idev_reg_first:
|
||||
input_unregister_device(hdaps_idev);
|
||||
out_idev:
|
||||
input_free_device(hdaps_idev_raw);
|
||||
out_idev_first:
|
||||
input_free_device(hdaps_idev);
|
||||
out_group:
|
||||
sysfs_remove_group(&pdev->dev.kobj, &hdaps_attribute_group);
|
||||
@ -780,7 +856,7 @@ out:
|
||||
|
||||
static void __exit hdaps_exit(void)
|
||||
{
|
||||
del_timer_sync(&hdaps_timer);
|
||||
input_unregister_device(hdaps_idev_raw);
|
||||
input_unregister_device(hdaps_idev);
|
||||
hdaps_device_shutdown(); /* ignore errors, effect is negligible */
|
||||
sysfs_remove_group(&pdev->dev.kobj, &hdaps_attribute_group);
|
||||
|
@ -6,11 +6,12 @@
|
||||
* The interface provides various system management services (currently
|
||||
* known: battery information and accelerometer readouts). This driver
|
||||
* provides access and mutual exclusion for the EC interface.
|
||||
* For information about the LPC protocol and terminology, see:
|
||||
*
|
||||
* The LPC protocol and terminology is documented here:
|
||||
* "H8S/2104B Group Hardware Manual",
|
||||
* http://documentation.renesas.com/eng/products/mpumcu/rej09b0300_2140bhm.pdf
|
||||
*
|
||||
* Copyright (C) 2006 Shem Multinymous <multinymous@gmail.com>
|
||||
* Copyright (C) 2006-2007 Shem Multinymous <multinymous@gmail.com>
|
||||
*
|
||||
* 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
|
||||
@ -37,7 +38,7 @@
|
||||
#include <asm/semaphore.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#define TP_VERSION "0.31"
|
||||
#define TP_VERSION "0.32"
|
||||
|
||||
MODULE_AUTHOR("Shem Multinymous");
|
||||
MODULE_DESCRIPTION("ThinkPad embedded controller hardware access");
|
||||
@ -125,7 +126,14 @@ void thinkpad_ec_unlock(void)
|
||||
|
||||
EXPORT_SYMBOL_GPL(thinkpad_ec_unlock);
|
||||
|
||||
/* Tell embedded controller to prepare a row */
|
||||
/**
|
||||
* thinkpad_ec_request_row - tell embedded controller to prepare a row
|
||||
* @args Input register arguments
|
||||
*
|
||||
* Requests a data row by writing to H8S LPC registers TRW0 through TWR15 (or
|
||||
* a subset thereof) following the protocol prescribed by the "H8S/2104B Group
|
||||
* Hardware Manual". Does sanity checks via status register STR3.
|
||||
*/
|
||||
static int thinkpad_ec_request_row(const struct thinkpad_ec_row *args)
|
||||
{
|
||||
u8 str3;
|
||||
@ -193,8 +201,13 @@ static int thinkpad_ec_request_row(const struct thinkpad_ec_row *args)
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* Read current row data from the controller, assuming it's already
|
||||
* requested.
|
||||
/**
|
||||
* thinkpad_ec_read_data - read pre-requested row-data from EC
|
||||
* @args Input register arguments of pre-requested rows
|
||||
* @data Output register values
|
||||
*
|
||||
* Reads current row data from the controller, assuming it's already
|
||||
* requested. Follows the H8S spec for register access and status checks.
|
||||
*/
|
||||
static int thinkpad_ec_read_data(const struct thinkpad_ec_row *args,
|
||||
struct thinkpad_ec_row *data)
|
||||
@ -383,9 +396,13 @@ EXPORT_SYMBOL_GPL(thinkpad_ec_invalidate);
|
||||
|
||||
/*** Checking for EC hardware ***/
|
||||
|
||||
/* thinkpad_ec_test:
|
||||
/**
|
||||
* thinkpad_ec_test - verify the EC is present and follows protocol
|
||||
*
|
||||
* Ensure the EC LPC3 channel really works on this machine by making
|
||||
* an arbitrary harmless EC request and seeing if the EC follows protocol.
|
||||
* an EC request and seeing if the EC follows the documented H8S protocol.
|
||||
* The requested row just reads battery status, so it should be harmless to
|
||||
* access it (on a correct EC).
|
||||
* This test writes to IO ports, so execute only after checking DMI.
|
||||
*/
|
||||
static int __init thinkpad_ec_test(void)
|
||||
@ -431,13 +448,8 @@ static int __init check_dmi_for_ec(void)
|
||||
TP_DMI_MATCH("IBM","ThinkPad X24"),
|
||||
{ .ident = NULL }
|
||||
};
|
||||
#include "dmi_ec_oem_string.h"
|
||||
#ifdef DMI_EC_OEM_STRING_KLUDGE
|
||||
return (strstr(DMI_EC_OEM_STRING_KLUDGE, "IBM ThinkPad Embedded Controller")) ||
|
||||
#else
|
||||
return dmi_find_substring(DMI_DEV_TYPE_OEM_STRING,
|
||||
"IBM ThinkPad Embedded Controller") ||
|
||||
#endif
|
||||
dmi_check_system(tp_whitelist);
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* thinkpad_ec.h - interface to ThinkPad embedded controller LPC3 functions
|
||||
*
|
||||
*
|
||||
* Copyright (C) 2005 Shem Multinymous <multinymous@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@ -31,8 +31,8 @@ struct thinkpad_ec_row {
|
||||
u8 val[TP_CONTROLLER_ROW_LEN];
|
||||
};
|
||||
|
||||
extern int thinkpad_ec_lock(void);
|
||||
extern int thinkpad_ec_try_lock(void);
|
||||
extern int __must_check thinkpad_ec_lock(void);
|
||||
extern int __must_check thinkpad_ec_try_lock(void);
|
||||
extern void thinkpad_ec_unlock(void);
|
||||
|
||||
extern int thinkpad_ec_read_row(const struct thinkpad_ec_row *args,
|
||||
|
76
tp_smapi.c
76
tp_smapi.c
@ -41,7 +41,7 @@
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#define TP_VERSION "0.31"
|
||||
#define TP_VERSION "0.32"
|
||||
#define TP_DESC "ThinkPad SMAPI Support"
|
||||
#define TP_DIR "smapi"
|
||||
|
||||
@ -75,8 +75,6 @@ MODULE_PARM_DESC(debug, "Debug level (0=off, 1=on)");
|
||||
#define SMAPI_SET_FORCE_DISCHARGE 0x2119
|
||||
#define SMAPI_GET_THRESH_STOP 0x211a
|
||||
#define SMAPI_SET_THRESH_STOP 0x211b
|
||||
#define SMAPI_GET_PCI_BUS_POWER_SAVING 0x4004
|
||||
#define SMAPI_SET_PCI_BUS_POWER_SAVING 0x4005
|
||||
|
||||
/* SMAPI error codes (see ThinkPad 770 Technical Reference Manual p.83 at
|
||||
http://www-307.ibm.com/pc/support/site.wss/document.do?lndocid=PFAN-3TUQQD */
|
||||
@ -439,51 +437,6 @@ static int set_force_discharge(int bat, int enabled)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* get_enable_pci_power_saving_on_boot - get PCI power enable status via SMAPI
|
||||
* @on: 1 iff PCI bus power saving will be enabled in the next reboot
|
||||
*/
|
||||
static int get_enable_pci_power_saving_on_boot(int *on)
|
||||
{
|
||||
u32 ebx, esi;
|
||||
const char* msg;
|
||||
int ret = smapi_request(SMAPI_GET_PCI_BUS_POWER_SAVING, 0,0,0,
|
||||
&ebx, NULL, NULL, NULL, &esi, &msg);
|
||||
if (ret) {
|
||||
TPRINTK(KERN_NOTICE, "failed: %s",msg);
|
||||
return ret;
|
||||
}
|
||||
if (!(ebx & 0x00000001)) {
|
||||
TPRINTK(KERN_NOTICE, "unknown status ebx==0x%x esi==0x%x",
|
||||
ebx, esi);
|
||||
return -EIO;
|
||||
}
|
||||
*on = esi & 0x00000001;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* set_enable_pci_power_saving_on_boot - set PCI power enable status via SMAPI
|
||||
* @on: 1 iff PCI bus power saving should be enabled in the next reboot
|
||||
*/
|
||||
static int set_enable_pci_power_saving_on_boot(int on)
|
||||
{
|
||||
u32 ecx, edi, esi;
|
||||
const char* msg;
|
||||
int ret = smapi_request(SMAPI_GET_PCI_BUS_POWER_SAVING, 0,0,0,
|
||||
NULL, &ecx, NULL, &edi, &esi, &msg);
|
||||
if (ret) {
|
||||
TPRINTK(KERN_NOTICE, "get failed: %s", msg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
esi = (esi & 0xFFFE) | (on ? 0x0001 : 0x0000);
|
||||
ret = smapi_write(SMAPI_SET_PCI_BUS_POWER_SAVING,
|
||||
ecx, edi, esi, &msg);
|
||||
if (ret)
|
||||
TPRINTK(KERN_NOTICE, "set failed: %s", msg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* Wrappers to threshold-related SMAPI functions, which handle default
|
||||
@ -1142,29 +1095,6 @@ static ssize_t show_ac_connected(
|
||||
return sprintf(buf, "%d\n", ret); /* type: boolean */
|
||||
}
|
||||
|
||||
static ssize_t show_enable_pci_power_saving_on_boot(
|
||||
struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
int on;
|
||||
int ret = get_enable_pci_power_saving_on_boot(&on);
|
||||
if (ret)
|
||||
return ret;
|
||||
return sprintf(buf, "%d\n", on); /* type: boolean */
|
||||
}
|
||||
|
||||
static ssize_t store_enable_pci_power_saving_on_boot(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
int ret;
|
||||
int on;
|
||||
if (sscanf(buf, "%d", &on)!=1 || on<0 || on>1)
|
||||
return -EINVAL;
|
||||
ret = set_enable_pci_power_saving_on_boot(on);
|
||||
if (ret)
|
||||
return ret;
|
||||
return count;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* The the "smapi_request" sysfs attribute executes a raw SMAPI call.
|
||||
* You write to make a request and read to get the result. The state
|
||||
@ -1268,15 +1198,11 @@ static struct platform_driver tp_driver = {
|
||||
/* Attributes in /sys/devices/platform/smapi/ */
|
||||
|
||||
static DEVICE_ATTR(ac_connected, 0444, show_ac_connected, NULL);
|
||||
static DEVICE_ATTR(enable_pci_power_saving_on_boot, 0644,
|
||||
show_enable_pci_power_saving_on_boot,
|
||||
store_enable_pci_power_saving_on_boot);
|
||||
static DEVICE_ATTR(smapi_request, 0600, show_smapi_request,
|
||||
store_smapi_request);
|
||||
|
||||
static struct attribute *tp_root_attributes[] = {
|
||||
&dev_attr_ac_connected.attr,
|
||||
&dev_attr_enable_pci_power_saving_on_boot.attr,
|
||||
&dev_attr_smapi_request.attr,
|
||||
NULL
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user