From 04dc589904e46758583aebe3ed2dbd1b82e6202b Mon Sep 17 00:00:00 2001 From: Shem Multinymous Date: Thu, 8 Mar 2007 00:50:50 +0100 Subject: [PATCH] import of tp-smapi version 0.32 --- CHANGES | 14 +++ Makefile | 63 ++++------- README | 44 ++++---- TODO | 18 +++ diff/Kconfig-hdaps-select-thinkpad_ec | 10 -- diff/Kconfig-thinkpad_ec.add | 8 ++ diff/Kconfig-thinkpad_ec.diff | 10 -- diff/Kconfig-tp_smapi.add | 12 ++ diff/Kconfig-tp_smapi.diff | 19 ---- ...code-and-save-oem-string-information.patch | 77 ------------- diff/thinkpad_ec-no-dmi-kludge.diff | 12 -- hdaps.c | 106 +++++++++++++++--- thinkpad_ec.c | 38 ++++--- thinkpad_ec.h | 6 +- tp_smapi.c | 76 +------------ 15 files changed, 215 insertions(+), 298 deletions(-) create mode 100644 TODO delete mode 100644 diff/Kconfig-hdaps-select-thinkpad_ec create mode 100644 diff/Kconfig-thinkpad_ec.add delete mode 100644 diff/Kconfig-thinkpad_ec.diff create mode 100644 diff/Kconfig-tp_smapi.add delete mode 100644 diff/Kconfig-tp_smapi.diff delete mode 100644 diff/dmi-decode-and-save-oem-string-information.patch delete mode 100644 diff/thinkpad_ec-no-dmi-kludge.diff diff --git a/CHANGES b/CHANGES index 1c3fe1b..24ac32c 100644 --- a/CHANGES +++ b/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: diff --git a/Makefile b/Makefile index 57b55fb..1f4a4e2 100644 --- a/Makefile +++ b/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}" diff --git a/README b/README index 062eb46..779fe17 100644 --- a/README +++ b/README @@ -1,4 +1,4 @@ -tp_smapi version 0.31 +tp_smapi version 0.32 IBM ThinkPad hardware functions driver Author: Shem Multinymous @@ -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 ---------------- diff --git a/TODO b/TODO new file mode 100644 index 0000000..322c7a7 --- /dev/null +++ b/TODO @@ -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. diff --git a/diff/Kconfig-hdaps-select-thinkpad_ec b/diff/Kconfig-hdaps-select-thinkpad_ec deleted file mode 100644 index 09fea34..0000000 --- a/diff/Kconfig-hdaps-select-thinkpad_ec +++ /dev/null @@ -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 diff --git a/diff/Kconfig-thinkpad_ec.add b/diff/Kconfig-thinkpad_ec.add new file mode 100644 index 0000000..9176585 --- /dev/null +++ b/diff/Kconfig-thinkpad_ec.add @@ -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). + diff --git a/diff/Kconfig-thinkpad_ec.diff b/diff/Kconfig-thinkpad_ec.diff deleted file mode 100644 index e63ec9c..0000000 --- a/diff/Kconfig-thinkpad_ec.diff +++ /dev/null @@ -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 diff --git a/diff/Kconfig-tp_smapi.add b/diff/Kconfig-tp_smapi.add new file mode 100644 index 0000000..a6247a8 --- /dev/null +++ b/diff/Kconfig-tp_smapi.add @@ -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 + . + + If you have an IBM ThinkPad laptop, say Y or M here. + diff --git a/diff/Kconfig-tp_smapi.diff b/diff/Kconfig-tp_smapi.diff deleted file mode 100644 index e44ef91..0000000 --- a/diff/Kconfig-tp_smapi.diff +++ /dev/null @@ -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 -+ . -+ -+ If you have an IBM ThinkPad laptop, say Y or M here. -+ - endmenu diff --git a/diff/dmi-decode-and-save-oem-string-information.patch b/diff/dmi-decode-and-save-oem-string-information.patch deleted file mode 100644 index 925c433..0000000 --- a/diff/dmi-decode-and-save-oem-string-information.patch +++ /dev/null @@ -1,77 +0,0 @@ -Subject: DMI: Decode and save OEM String information -From: "Shem Multinymous" - -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 -Cc: Bjorn Helgaas -Signed-off-by: Andrew Morton ---- - - 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 { -_ diff --git a/diff/thinkpad_ec-no-dmi-kludge.diff b/diff/thinkpad_ec-no-dmi-kludge.diff deleted file mode 100644 index 2a2cf20..0000000 --- a/diff/thinkpad_ec-no-dmi-kludge.diff +++ /dev/null @@ -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); diff --git a/hdaps.c b/hdaps.c index d5ede81..5ec7385 100644 --- a/hdaps.c +++ b/hdaps.c @@ -32,9 +32,10 @@ #include #include #include -#include #include +#include #include +#include /* 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; totalHZ || rate<0) { + if (sscanf(buf, "%d", &rate) != 1 || rate>HZ || rate<=0) { printk(KERN_WARNING "must have 0name = "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); diff --git a/thinkpad_ec.c b/thinkpad_ec.c index 85c9342..f96d7fe 100644 --- a/thinkpad_ec.c +++ b/thinkpad_ec.c @@ -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 + * Copyright (C) 2006-2007 Shem Multinymous * * 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 #include -#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); } diff --git a/thinkpad_ec.h b/thinkpad_ec.h index 092ecdb..89dc960 100644 --- a/thinkpad_ec.h +++ b/thinkpad_ec.h @@ -1,6 +1,6 @@ /* * thinkpad_ec.h - interface to ThinkPad embedded controller LPC3 functions - * + * * Copyright (C) 2005 Shem Multinymous * * 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, diff --git a/tp_smapi.c b/tp_smapi.c index 9e29600..4b7ea4f 100644 --- a/tp_smapi.c +++ b/tp_smapi.c @@ -41,7 +41,7 @@ #include #include -#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 };