import of tp-smapi version 0.27

This commit is contained in:
Shem Multinymous 2006-08-04 17:21:10 +02:00 committed by Evgeni Golov
parent 840646759a
commit ee4b50c735
15 changed files with 259 additions and 277 deletions

17
CHANGES
View File

@ -1,5 +1,22 @@
Change history for tp_smapi:
0.27 2006-08-05
---------------------
Visible changes:
- Renamed tp_base.* to thinkpad_ec.*.
NOTE: If you have manual modprobe commands or configuration mentioning
tp_base, you'll need to change them.
- hdaps: All HDAPS-equippedThinkPads should be now be automatically
recognized. Whitelisting is needed only for changing the axis
configuration.
- hdaps: Removed 'force' module parameter, it's no longer needed.
Internal changes:
- Renamed all tp_controller_* functions to thinkpad_ec_*.
- Small change to invalidation in hdaps_device_init().
- Separate Kconfig changes into separate patches.
- Clean up generated patch format a bit.
0.26 2006-08-04
---------------------
- The modified hdaps.c is now included as a full file (based on linux git)

View File

@ -7,7 +7,7 @@ MOD_DIR := /lib/modules/$(KVER)/kernel
PWD := $(shell pwd)
IDIR := include/linux
TP_DIR := drivers/firmware
TP_MODULES := tp_base.o tp_smapi.o
TP_MODULES := thinkpad_ec.o tp_smapi.o
SHELL := /bin/bash
ifeq ($(HDAPS),1)
@ -31,13 +31,13 @@ export TP_MODULES
default: modules
# Build the modules tp_base.ko, tp_smapi.ko and (if HDAPS=1) hdaps.ko
# 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))
$(MAKE) -C $(KSRC) M=$(PWD) modules
clean:
rm -f tp_smapi.mod.* tp_smapi.o tp_smapi.ko .tp_smapi.*.cmd
rm -f tp_base.mod.* tp_base.o tp_base.ko .tp_base.*.cmd
rm -f thinkpad_ec.mod.* thinkpad_ec.o thinkpad_ec.ko .thinkpad_ec.*.cmd
rm -f hdaps.mod.* hdaps.o hdaps.ko .hdaps.*.cmd
rm -f *~ diff/*~ *.orig diff/*.orig *.rej diff/*.rej
rm -f tp_smapi-*-for-*.patch
@ -46,7 +46,7 @@ clean:
load: check_hdaps unload modules
@( [ `id -u` == 0 ] || { echo "Must be root to load modules"; exit 1; } )
{ insmod ./tp_base.ko debug=$(DEBUG) &&\
{ insmod ./thinkpad_ec.ko debug=$(DEBUG) &&\
insmod ./tp_smapi.ko debug=$(DEBUG) &&\
$(LOAD_HDAPS); }; :
@echo -e '\nRecent dmesg output:' ; dmesg | tail -10
@ -55,7 +55,8 @@ unload:
@( [ `id -u` == 0 ] || { echo "Must be root to unload modules"; exit 1; } )
if lsmod | grep -q '^hdaps '; then rmmod hdaps; fi
if lsmod | grep -q '^tp_smapi '; then rmmod tp_smapi; fi
if lsmod | grep -q '^tp_base '; then rmmod tp_base; fi
if lsmod | grep -q '^thinkpad_ec '; then rmmod thinkpad_ec; fi
if lsmod | grep -q '^tp_base '; then rmmod tp_base; fi # old thinkpad_ec
check_hdaps:
ifneq ($(HDAPS),1)
@ -67,9 +68,11 @@ endif
install: modules
@( [ `id -u` == 0 ] || { echo "Must be root to install modules"; exit 1; } )
rm -f $(MOD_DIR)/$(TP_DIR)/{tp_base,tp_smapi}.ko
rm -f $(MOD_DIR)/$(TP_DIR)/{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
rm -f $(MOD_DIR)/extra/hdaps.ko
endif
$(MAKE) -C $(KSRC) M=$(PWD) modules_install
depmod -a
@ -92,7 +95,7 @@ dmi_ec_oem_string.h: $(KSRC)/include/linux/dmi.h
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/tp_base-no-dmi-kludge.diff
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. */' > $@
@ -102,12 +105,13 @@ endif
# Generate a stand-alone kernel patch
TP_VER := ${shell sed -ne 's/^\#define TP_VERSION \"\(.*\)\"/\1/gp' tp_smapi.c}
ORG := linux-$(KVER)-orig
NEW := linux-$(KVER)-patched
ORG := a
NEW := b
PATCH := tp_smapi-$(TP_VER)-for-$(KVER).patch
BASE_IN_PATCH := 1
SMAPI_IN_PATCH := 1
HDAPS_IN_PATCH := 1
patch:
TMPDIR=`mktemp -d /tmp/tp_smapi-patch.XXXXXX` &&\
@ -121,18 +125,22 @@ patch:
cp -r $(ORG) $(NEW) &&\
\
if [ "$(BASE_IN_PATCH)" == 1 ]; then \
patch --no-backup-if-mismatch -s -d $(NEW) -i $(PWD)/diff/Kconfig-tp_base.diff -p1 &&\
cp $(PWD)/tp_base.c $(NEW)/$(TP_DIR)/tp_base.c &&\
cp $(PWD)/tp_base.h $(NEW)/$(IDIR)/tp_base.h &&\
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 \
; fi &&\
\
if [ "$(HDAPS_IN_PATCH)" == 1 ]; then \
cp $(PWD)/hdaps.c $(NEW)/drivers/hwmon/ &&\
sed -i -e '$$aobj-$$(CONFIG_TP_BASE) += tp_base.o' $(NEW)/$(TP_DIR)/Makefile \
patch --no-backup-if-mismatch -s -d $(NEW) -i $(PWD)/diff/Kconfig-hdaps-select-thinkpad_ec -p1 \
; 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)/$(TP_DIR) -i $(PWD)/diff/tp_smapi-no_cd.diff -p1 &&\
patch --no-backup-if-mismatch -s -d $(NEW)/$(TP_DIR) -i $(PWD)/diff/tp_base-no-dmi-kludge.diff -p1 &&\
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 \
@ -141,7 +149,7 @@ patch:
{ diff -dNurp $(ORG) $(NEW) > patch \
|| [ $$? -lt 2 ]; } &&\
$(GEN_DMI_DECODE_PATCH) >> patch &&\
{ diffstat patch; echo; echo; cat patch; } \
{ echo "Generated for $(KVER) in $(KSRC)"; echo; diffstat patch; echo; echo; cat patch; } \
> $(PWD)/${PATCH} &&\
rm -r $$TMPDIR
@echo -e "\nPatch file created:\n ${PATCH}"
@ -152,7 +160,7 @@ patch:
set-version:
perl -i -pe 's/^(tp_smapi version ).*/$${1}$(VER)/' README
perl -i -pe 's/^(#define TP_VERSION ").*/$${1}$(VER)"/' tp_base.c tp_smapi.c
perl -i -pe 's/^(#define TP_VERSION ").*/$${1}$(VER)"/' thinkpad_ec.c tp_smapi.c
else
#####################################################################

16
README
View File

@ -1,4 +1,4 @@
tp_smapi version 0.26
tp_smapi version 0.27
IBM ThinkPad hardware functions driver
Author: Shem Multinymous <multinymous@gmail.com>
@ -51,7 +51,7 @@ To prepare a stand-alone patch against another kernel, follow this example:
To delete all autogenerated files:
# make clean
Append "DEBUG=1" to "make load" to load tp_base and tp_smapi with debug
Append "DEBUG=1" to "make load" to load thinkpad_ec and tp_smapi with debug
dmesg output enabled.
The original kernel tree is never modified by any these commands.
@ -61,7 +61,7 @@ The /lib/modules directory is modified only by "make install".
Module parameters
-----------------
tp_base module:
thinkpad_ec module:
debug=1 enables verbose dmesg output.
tp_smapi module:
@ -217,7 +217,7 @@ Bug reporting
Mail <multinymous@gmail.com>. Please include:
* Details about your model,
* Relevant "dmesg" output. Make sure tp_base and tp_smapi are loaded with
* Relevant "dmesg" output. Make sure thinkpad_ec and tp_smapi are loaded with
the "debug=1" parameter (e.g., use "make load HDAPS=1 DEBUG=1").
* Output of "dmidecode | grep -C5 Product"
* Does the failed functionality works under Windows?
@ -234,12 +234,12 @@ Makefile
Makefile (see "Installation" above).
tp_smapi.c
tp_smapi driver module (main code).
tp_base.*
tp_base driver module (coordinates hardware access between tp_smapi and
thinkpad_ec.*
thinkpad_ec driver module (coordinates hardware access between tp_smapi and
hdaps)
hdaps.c
Modified version of hdaps.c driver from mainline kernel, patched to use
tp_base and several other improvements.
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
@ -298,5 +298,5 @@ In addition, the embedded controller on ThinkPad laptops has a non-standard
interface at IO ports 0x1600-0x161F (mapped to LCP channel 3 of the H8S chip).
The interface provides various system management services (currently known:
battery information and accelerometer readouts). For more information see the
tp_base modul and the H8S hardware documentation:
thinkpad_ec modul and the H8S hardware documentation:
http://documentation.renesas.com/eng/products/mpumcu/rej09b0300_2140bhm.pdf

View File

@ -0,0 +1,10 @@
--- 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

View File

@ -0,0 +1,10 @@
--- 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

View File

@ -1,20 +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
@@ -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 TP_BASE
+ tristate
+
endmenu
--- linux-2.6.15-rc5-orig/drivers/hwmon/Kconfig 2005-10-28 02:02:08.000000000 +0200
+++ linux-2.6.15-rc5-patched/drivers/hwmon/Kconfig 2005-12-21 00:42:22.000000000 +0200
@@ -437,6 +437,7 @@
config SENSORS_HDAPS
tristate "IBM Hard Drive Active Protection System (hdaps)"
depends on HWMON && INPUT && X86
+ select TP_BASE
default n
help
This driver provides support for the IBM Hard Drive Active Protection

View File

@ -1,13 +1,13 @@
--- 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 TP_BASE
config THINKPAD_EC
tristate
+config TP_SMAPI
+ tristate "ThinkPad SMAPI Support"
+ depends on X86
+ select TP_BASE
+ select THINKPAD_EC
+ default n
+ help
+ This adds SMAPI support on IBM ThinkPads, mostly used for battery

View File

@ -1,5 +1,5 @@
--- orig/tp_base.c 2006-08-02 00:00:00.000000000 +0000
+++ no-dmi-kludge/tp_base.c 2006-08-02 00:00:00.000000000 +0000
--- 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"

View File

@ -59,7 +59,7 @@
- * driver instead, and may get in the ATAPI driver's way.
- */
-
-static int cd_speed_show(struct device *dev,
-static int show_cd_speed(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- int speed;
@ -69,7 +69,7 @@
- return sprintf(buf, "%d\n", speed);
-}
-
-static int cd_speed_store(struct device *dev,
-static int store_cd_speed(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
@ -90,7 +90,7 @@
-
@@ -1235,3 +1149,0 @@
-#ifdef PROVIDE_CD_SPEED
-static DEVICE_ATTR(cd_speed, 0644, cd_speed_show, cd_speed_store);
-static DEVICE_ATTR(cd_speed, 0644, show_cd_speed, store_cd_speed);
-#endif
@@ -1243,3 +1154,0 @@
-#ifdef PROVIDE_CD_SPEED

163
hdaps.c
View File

@ -33,11 +33,10 @@
#include <linux/module.h>
#include <linux/timer.h>
#include <linux/dmi.h>
#include <linux/tp_base.h>
#include <linux/jiffies.h>
#include <linux/thinkpad_ec.h>
/* Embedded controller accelerometer read command and its result: */
static const struct tp_controller_row ec_accel_args =
static const struct thinkpad_ec_row ec_accel_args =
{ .mask=0x0001, .val={0x11} };
#define EC_ACCEL_IDX_READOUTS 0x1 /* readouts included in this read */
/* First readout, if READOUTS>=1: */
@ -60,14 +59,12 @@ static const struct tp_controller_row ec_accel_args =
#define HDAPS_INPUT_FUZZ 4 /* input event threshold */
#define HDAPS_INPUT_FLAT 4
#define KMACT_REMEMBER_PERIOD (HZ/10) /* keyboard/mouse persistance */
static struct timer_list hdaps_timer;
static struct platform_device *pdev;
static struct input_dev *hdaps_idev;
static unsigned int hdaps_invert;
static unsigned int hdaps_force;
static int needs_calibration = 0;
/* Configuration: */
@ -80,12 +77,12 @@ static int fake_data_mode = 0; /* Enable EC fake data mode? */
/* Latest state readout: */
static int pos_x, pos_y; /* position */
static int temperature; /* temperature */
static int stale_readout = 1; /* last read failed */
static int stale_readout = 1; /* last read invalid */
static int rest_x, rest_y; /* calibrated rest position */
/* Last time we saw keyboard and mouse activity: */
u64 last_keyboard_jiffies = INITIAL_JIFFIES;
u64 last_mouse_jiffies = INITIAL_JIFFIES;
static u64 last_keyboard_jiffies = INITIAL_JIFFIES;
static u64 last_mouse_jiffies = INITIAL_JIFFIES;
/* __hdaps_update - read current state and update global state variables.
* Also prefetches the next read, to reduce udelay busy-waiting.
@ -95,17 +92,17 @@ u64 last_mouse_jiffies = INITIAL_JIFFIES;
static int __hdaps_update(int fast)
{
/* Read data: */
struct tp_controller_row data;
struct thinkpad_ec_row data;
int ret;
data.mask = (1 << EC_ACCEL_IDX_READOUTS) | (1 << EC_ACCEL_IDX_KMACT) |
(3 << EC_ACCEL_IDX_YPOS1) | (3 << EC_ACCEL_IDX_XPOS1) |
(1 << EC_ACCEL_IDX_TEMP1) | (1 << EC_ACCEL_IDX_RETVAL);
if (fast)
ret = tp_controller_try_read_row(&ec_accel_args, &data);
ret = thinkpad_ec_try_read_row(&ec_accel_args, &data);
else
ret = tp_controller_read_row(&ec_accel_args, &data);
tp_controller_prefetch_row(&ec_accel_args); /* Prefetch even if error */
ret = thinkpad_ec_read_row(&ec_accel_args, &data);
thinkpad_ec_prefetch_row(&ec_accel_args); /* Prefetch even if error */
if (ret)
return ret;
@ -144,11 +141,10 @@ static int __hdaps_update(int fast)
return 0;
}
/*
* hdaps_read_pair - reads the values from a pair of ports, placing the values
* in the given pointers. Returns zero on success. Can sleep.
/* hdaps_update - read current state and update global state variables.
* Also prefetches the next read, to reduce udelay busy-waiting.
* Retries until timeout if the accelerometer is not in ready status (common).
* Does internal locking.
* Does its own locking.
*/
static int hdaps_update(void)
{
@ -156,11 +152,11 @@ static int hdaps_update(void)
if (!stale_readout) /* already updated recently? */
return 0;
for (total=READ_TIMEOUT_MSECS; total>0; total-=RETRY_MSECS) {
ret = tp_controller_lock();
ret = thinkpad_ec_lock();
if (ret)
return ret;
ret = __hdaps_update(0);
tp_controller_unlock();
thinkpad_ec_unlock();
if (!ret)
return 0;
@ -176,10 +172,10 @@ static int hdaps_update(void)
* Returns zero on success and negative error code on failure. Can sleep.
*/
static int hdaps_set_power(int on) {
struct tp_controller_row args =
struct thinkpad_ec_row args =
{ .mask=0x0003, .val={0x14, on?0x01:0x00} };
struct tp_controller_row data = { .mask = 0x8000 };
int ret = tp_controller_read_row(&args, &data);
struct thinkpad_ec_row data = { .mask = 0x8000 };
int ret = thinkpad_ec_read_row(&args, &data);
if (ret)
return ret;
if (data.val[0xF]!=0x00)
@ -193,10 +189,10 @@ static int hdaps_set_power(int on) {
* Returns zero on success and negative error code on failure. Can sleep.
*/
static int hdaps_set_fake_data_mode(int on) {
struct tp_controller_row args =
struct thinkpad_ec_row args =
{ .mask=0x0007, .val={0x17, 0x83, on?0x01:0x00} };
struct tp_controller_row data = { .mask = 0x8000 };
int ret = tp_controller_read_row(&args, &data);
struct thinkpad_ec_row data = { .mask = 0x8000 };
int ret = thinkpad_ec_read_row(&args, &data);
if (ret)
return ret;
if (data.val[0xF]!=0x00) {
@ -216,10 +212,10 @@ static int hdaps_set_fake_data_mode(int on) {
* Returns zero on success and negative error code on failure. Can sleep.
*/
static int hdaps_set_ec_config(int ec_rate, int order) {
struct tp_controller_row args = { .mask=0x000F,
struct thinkpad_ec_row args = { .mask=0x000F,
.val={0x10, (u8)ec_rate, (u8)(ec_rate>>8), order} };
struct tp_controller_row data = { .mask = 0x8000 };
int ret = tp_controller_read_row(&args, &data);
struct thinkpad_ec_row data = { .mask = 0x8000 };
int ret = thinkpad_ec_read_row(&args, &data);
printk(KERN_DEBUG "hdaps: setting ec_rate=%d, filter_order=%d\n",
ec_rate, order);
if (ret)
@ -247,10 +243,10 @@ static int hdaps_set_ec_config(int ec_rate, int order) {
* Returns zero on success and negative error code on failure. Can sleep.
*/
static int hdaps_get_ec_config(int *ec_rate, int *order) {
const struct tp_controller_row args =
const struct thinkpad_ec_row args =
{ .mask=0x0003, .val={0x17, 0x82} };
struct tp_controller_row data = { .mask = 0x801F };
int ret = tp_controller_read_row(&args, &data);
struct thinkpad_ec_row data = { .mask = 0x801F };
int ret = thinkpad_ec_read_row(&args, &data);
if (ret)
return ret;
if (data.val[0xF]!=0x00)
@ -269,9 +265,9 @@ static int hdaps_get_ec_config(int *ec_rate, int *order) {
* Returns zero on success and negative error code on failure. Can sleep.
*/
static int hdaps_get_ec_mode(u8 *mode) {
const struct tp_controller_row args = { .mask=0x0001, .val={0x13} };
struct tp_controller_row data = { .mask = 0x8002 };
int ret = tp_controller_read_row(&args, &data);
const struct thinkpad_ec_row args = { .mask=0x0001, .val={0x13} };
struct thinkpad_ec_row data = { .mask = 0x8002 };
int ret = thinkpad_ec_read_row(&args, &data);
if (ret)
return ret;
if (data.val[0xF]!=0x00) {
@ -290,10 +286,10 @@ static int hdaps_get_ec_mode(u8 *mode) {
* Returns zero on success and negative error code on failure. Can sleep.
*/
static int __init hdaps_check_ec(u8 *mode) {
const struct tp_controller_row args =
const struct thinkpad_ec_row args =
{ .mask=0x0003, .val={0x17, 0x81} };
struct tp_controller_row data = { .mask = 0x800E };
int ret = tp_controller_read_row(&args, &data);
struct thinkpad_ec_row data = { .mask = 0x800E };
int ret = thinkpad_ec_read_row(&args, &data);
if (ret)
return ret;
if (data.val[0x1]!=0x00 || data.val[0x2]!=0x60 ||
@ -312,7 +308,7 @@ static int hdaps_device_init(void)
int ret;
u8 mode;
ret = tp_controller_lock();
ret = thinkpad_ec_lock();
if (ret)
return ret;
@ -335,19 +331,20 @@ static int hdaps_device_init(void)
if (hdaps_set_fake_data_mode(fake_data_mode))
ABORT_INIT("hdaps_set_fake_data_mode failed");
tp_controller_invalidate();
thinkpad_ec_invalidate();
udelay(200);
/* Just prefetch instead of reading, to avoid ~1sec delay on load */
ret = tp_controller_prefetch_row(&ec_accel_args);
ret = thinkpad_ec_prefetch_row(&ec_accel_args);
if (ret)
ABORT_INIT("initial prefetch failed");
goto good;
bad:
thinkpad_ec_invalidate();
ret = -ENXIO;
good:
tp_controller_invalidate();
tp_controller_unlock();
stale_readout = 1;
thinkpad_ec_unlock();
return ret;
}
@ -377,7 +374,7 @@ static int hdaps_probe(struct platform_device *dev)
static int hdaps_suspend(struct platform_device *dev, pm_message_t state)
{
/* Don't do mouse polls until resume re-initializes the sensor. */
/* Don't do hdaps polls until resume re-initializes the sensor. */
del_timer_sync(&hdaps_timer);
hdaps_device_shutdown();
return 0;
@ -403,8 +400,7 @@ static struct platform_driver hdaps_driver = {
};
/*
* hdaps_calibrate - Set our "resting" values.
* Does its own locking.
* hdaps_calibrate - Set our "resting" values. Does its own locking.
*/
static void hdaps_calibrate(void)
{
@ -423,11 +419,11 @@ static void hdaps_mousedev_poll(unsigned long unused)
stale_readout = 1;
/* Cannot sleep. Try nonblockingly. If we fail, try again later. */
if (tp_controller_try_lock())
if (thinkpad_ec_try_lock())
goto keep_active;
ret = __hdaps_update(1); /* fast update, we're in softirq context */
tp_controller_unlock();
thinkpad_ec_unlock();
/* Any of "successful", "not yet ready" and "not prefetched"? */
if (ret!=0 && ret!=-EBUSY && ret!=-ENODATA) {
printk(KERN_ERR
@ -455,7 +451,7 @@ static ssize_t hdaps_position_show(struct device *dev,
return sprintf(buf, "(%d,%d)\n", pos_x, pos_y);
}
static ssize_t hdaps_temperature_show(struct device *dev,
static ssize_t hdaps_temp1_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
int ret = hdaps_update();
@ -618,8 +614,8 @@ static ssize_t hdaps_fake_data_mode_show(
}
static DEVICE_ATTR(position, 0444, hdaps_position_show, NULL);
static DEVICE_ATTR(temp1, 0444, hdaps_temperature_show, NULL);
/* named temp1 instead of temperature for backward compatibility */
static DEVICE_ATTR(temp1, 0444, hdaps_temp1_show, NULL);
/* "temp1" instead of "temperature" is hwmon convention */
static DEVICE_ATTR(keyboard_activity, 0444, hdaps_keyboard_activity_show, NULL);
static DEVICE_ATTR(mouse_activity, 0444, hdaps_mouse_activity_show, NULL);
static DEVICE_ATTR(calibrate, 0644, hdaps_calibrate_show,hdaps_calibrate_store);
@ -656,79 +652,41 @@ static struct attribute_group hdaps_attribute_group = {
/* Module stuff */
/* hdaps_dmi_match - found a match. return one, short-circuiting the hunt. */
static int hdaps_dmi_match(struct dmi_system_id *id)
{
printk(KERN_INFO "hdaps: %s detected.\n", id->ident);
return 1;
}
/* hdaps_dmi_match_invert - found an inverted match. */
static int hdaps_dmi_match_invert(struct dmi_system_id *id)
{
hdaps_invert = 1;
printk(KERN_INFO "hdaps: inverting axis readings.\n");
return hdaps_dmi_match(id);
printk(KERN_INFO "hdaps: %s detected, inverting axes\n",
id->ident);
return 1;
}
#define HDAPS_DMI_MATCH_NORMAL(model) { \
.ident = "IBM " model, \
.callback = hdaps_dmi_match, \
.matches = { \
DMI_MATCH(DMI_BOARD_VENDOR, "IBM"), \
DMI_MATCH(DMI_PRODUCT_VERSION, model) \
} \
}
#define HDAPS_DMI_MATCH_INVERT(model) { \
.ident = "IBM " model, \
#define HDAPS_DMI_MATCH_INVERT(vendor,model) { \
.ident = vendor " " model, \
.callback = hdaps_dmi_match_invert, \
.matches = { \
DMI_MATCH(DMI_BOARD_VENDOR, "IBM"), \
DMI_MATCH(DMI_BOARD_VENDOR, vendor), \
DMI_MATCH(DMI_PRODUCT_VERSION, model) \
} \
}
#define HDAPS_DMI_MATCH_LENOVO(model) { \
.ident = "Lenovo " model, \
.callback = hdaps_dmi_match_invert, \
.matches = { \
DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), \
DMI_MATCH(DMI_PRODUCT_VERSION, model) \
} \
}
static int __init hdaps_init(void)
{
int ret;
/* Note that HDAPS_DMI_MATCH_NORMAL("ThinkPad T42") would match
/* 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 */
struct dmi_system_id hdaps_whitelist[] = {
HDAPS_DMI_MATCH_NORMAL("ThinkPad H"),
HDAPS_DMI_MATCH_INVERT("ThinkPad R50p"),
HDAPS_DMI_MATCH_NORMAL("ThinkPad R50"),
HDAPS_DMI_MATCH_NORMAL("ThinkPad R51"),
HDAPS_DMI_MATCH_NORMAL("ThinkPad R52"),
HDAPS_DMI_MATCH_NORMAL("ThinkPad H"), /* R52 (1846AQG) */
HDAPS_DMI_MATCH_INVERT("ThinkPad T41p"),
HDAPS_DMI_MATCH_NORMAL("ThinkPad T41"),
HDAPS_DMI_MATCH_INVERT("ThinkPad T42p"),
HDAPS_DMI_MATCH_NORMAL("ThinkPad T42"),
HDAPS_DMI_MATCH_NORMAL("ThinkPad T43"),
HDAPS_DMI_MATCH_LENOVO("ThinkPad T60p"),
HDAPS_DMI_MATCH_NORMAL("ThinkPad X40"),
HDAPS_DMI_MATCH_NORMAL("ThinkPad X41"),
HDAPS_DMI_MATCH_LENOVO("ThinkPad X60"),
HDAPS_DMI_MATCH_NORMAL("ThinkPad Z60m"),
HDAPS_DMI_MATCH_INVERT("IBM","ThinkPad R50p"),
HDAPS_DMI_MATCH_INVERT("IBM","ThinkPad T41p"),
HDAPS_DMI_MATCH_INVERT("IBM","ThinkPad T42p"),
HDAPS_DMI_MATCH_INVERT("LENOVO","ThinkPad T60p"),
HDAPS_DMI_MATCH_INVERT("LENOVO","ThinkPad X60"),
{ .ident = NULL }
};
if (!(dmi_check_system(hdaps_whitelist) || hdaps_force)) {
printk(KERN_WARNING "hdaps: supported laptop not found!\n");
ret = -ENODEV;
goto out;
}
dmi_check_system(hdaps_whitelist); /* default to normal axes */
/* Init timer before platform_driver_register, in case of suspend */
init_timer(&hdaps_timer);
@ -801,9 +759,6 @@ module_exit(hdaps_exit);
module_param_named(invert, hdaps_invert, bool, 0);
MODULE_PARM_DESC(invert, "invert data along each axis");
module_param_named(force, hdaps_force, bool, 0);
MODULE_PARM_DESC(force, "force loading on non whitelisted laptops");
MODULE_AUTHOR("Robert Love");
MODULE_DESCRIPTION("IBM Hard Drive Active Protection System (HDAPS) driver");
MODULE_LICENSE("GPL v2");

1
include/linux/thinkpad_ec.h Symbolic link
View File

@ -0,0 +1 @@
../../thinkpad_ec.h

View File

@ -1 +0,0 @@
../../tp_base.h

View File

@ -1,12 +1,12 @@
/*
* tp_base.c - coordinate access to ThinkPad-specific hardware resources
* thinkpad_ec.c - coordinate access to ThinkPad-specific hardware resources
*
* The embedded controller on ThinkPad laptops has a non-standard interface
* at IO ports 0x1600-0x161F (mapped to LCP channel 3 of the H8S chip).
* 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.
* H8S hardware documentation and terminology is used in this file:
* For information about the LPC protocol and terminology, see:
* "H8S/2104B Group Hardware Manual",
* http://documentation.renesas.com/eng/products/mpumcu/rej09b0300_2140bhm.pdf
*
@ -32,11 +32,11 @@
#include <linux/dmi.h>
#include <linux/ioport.h>
#include <linux/delay.h>
#include <linux/tp_base.h>
#include <linux/thinkpad_ec.h>
#include <linux/jiffies.h>
#include <asm/io.h>
#define TP_VERSION "0.26"
#define TP_VERSION "0.27"
MODULE_AUTHOR("Shem Multinymous");
MODULE_DESCRIPTION("ThinkPad embedded controller hardware access");
@ -48,10 +48,10 @@ MODULE_LICENSE("GPL");
#define TPC_NUM_PORTS 0x20
#define TPC_STR3_PORT 0x1604 /* Reads H8S EC register STR3 */
#define TPC_TWR0_PORT 0x1610 /* Mapped to H8S EC register TWR0MW/SW */
#define TPC_TWR15_PORT 0x161F /* Mapped to H8S EC register TWR15 */
/* port 1610+i is mapped to H8S reg TWRi for 0<i<16 */
#define TPC_TWR15_PORT 0x161F /* Mapped to H8S EC register TWR15. */
/* (and port TPC_TWR0_PORT+i is mapped to H8S reg TWRi for 0<i<16) */
/* H8S STR3 status flags (see H8S/2104B Group Hardware Manual p.549) */
/* H8S STR3 status flags (see "H8S/2104B Group Hardware Manual" p.549) */
#define H8S_STR3_IBF3B 0x80 /* Bidi. Data Register Input Buffer Full */
#define H8S_STR3_OBF3B 0x40 /* Bidi. Data Register Output Buffer Full */
#define H8S_STR3_MWMF 0x20 /* Master Write Mode Flag */
@ -74,8 +74,8 @@ MODULE_PARM_DESC(debug, "Debug level (0=off, 1=on)");
#define DPRINTK(fmt, args...) \
do { if (tp_debug) printk(KERN_DEBUG fmt, ## args); } while (0)
#define MSG_FMT(fmt, args...) \
"tp_base: %s: " fmt "\n", __func__, ## args
#define ARG_FMT(msg,code) \
"thinkpad_ec: %s: " fmt "\n", __func__, ## args
#define REQ_FMT(msg, code) \
MSG_FMT("%s: (0x%02x:0x%02x)->0x%02x", \
msg, args->val[0x0], args->val[0xF], code)
@ -87,46 +87,46 @@ static u64 prefetch_jiffies; /* time of prefetch, or: */
/* Locking: */
static DECLARE_MUTEX(tp_controller_mutex);
static DECLARE_MUTEX(thinkpad_ec_mutex);
/* tp_controller_lock:
/* thinkpad_ec_lock:
* Get exclusive lock for accesing the controller. May sleep.
* Returns 0 iff lock acquired .
*/
int tp_controller_lock(void)
int thinkpad_ec_lock(void)
{
int ret;
ret = down_interruptible(&tp_controller_mutex);
ret = down_interruptible(&thinkpad_ec_mutex);
if (ret)
DPRINTK("tp_controller mutex down interrupted: %d\n", ret);
return ret;
}
EXPORT_SYMBOL_GPL(tp_controller_lock);
EXPORT_SYMBOL_GPL(thinkpad_ec_lock);
/* tp_controller_try_lock:
/* thinkpad_ec_try_lock:
* Get exclusive lock for accesing the controller but only if it's available.
* Does not block, does not sleep. Returns 0 iff lock acquired .
*/
int tp_controller_try_lock(void)
int thinkpad_ec_try_lock(void)
{
return down_trylock(&tp_controller_mutex);
return down_trylock(&thinkpad_ec_mutex);
}
EXPORT_SYMBOL_GPL(tp_controller_try_lock);
EXPORT_SYMBOL_GPL(thinkpad_ec_try_lock);
/* tp_controller_unlock:
/* thinkpad_ec_unlock:
* Release a previously acquired controller lock.
*/
void tp_controller_unlock(void)
void thinkpad_ec_unlock(void)
{
up(&tp_controller_mutex);
up(&thinkpad_ec_mutex);
}
EXPORT_SYMBOL_GPL(tp_controller_unlock);
EXPORT_SYMBOL_GPL(thinkpad_ec_unlock);
/* Tell embedded controller to prepare a row */
static int tp_controller_request_row(const struct tp_controller_row *args)
static int thinkpad_ec_request_row(const struct thinkpad_ec_row *args)
{
u8 str3;
int i;
@ -143,15 +143,15 @@ static int tp_controller_request_row(const struct tp_controller_row *args)
inb(TPC_TWR15_PORT); /* marks end of previous transaction */
if (prefetch_jiffies == TPC_PREFETCH_NONE)
printk(KERN_WARNING
ARG_FMT("readout already pending", str3));
REQ_FMT("readout already pending", str3));
return -EBUSY; /* EC will be ready in a few usecs */
} else if (str3 == H8S_STR3_SWMF) { /* busy with previous request */
if (prefetch_jiffies == TPC_PREFETCH_NONE)
printk(KERN_WARNING
ARG_FMT("EC handles previous request", str3));
REQ_FMT("EC handles previous request", str3));
return -EBUSY; /* data will be pending in a few usecs */
} else if (str3 != 0x00) { /* unexpected status? */
printk(KERN_WARNING ARG_FMT("bad initial STR3", str3));
printk(KERN_WARNING REQ_FMT("bad initial STR3", str3));
return -EIO;
}
@ -159,7 +159,7 @@ static int tp_controller_request_row(const struct tp_controller_row *args)
outb(args->val[0], TPC_TWR0_PORT);
str3 = inb(TPC_STR3_PORT) & H8S_STR3_MASK;
if (str3 != H8S_STR3_MWMF) { /* not accepted? */
printk(KERN_WARNING ARG_FMT("arg0 rejected", str3));
printk(KERN_WARNING REQ_FMT("arg0 rejected", str3));
return -EIO;
}
@ -184,30 +184,30 @@ static int tp_controller_request_row(const struct tp_controller_row *args)
ndelay(TPC_REQUEST_NDELAY);
else { /* weird EC status */
printk(KERN_WARNING
ARG_FMT("bad end STR3", str3));
REQ_FMT("bad end STR3", str3));
return -EIO;
}
}
printk(KERN_WARNING ARG_FMT("EC is mysteriously silent", str3));
printk(KERN_WARNING REQ_FMT("EC is mysteriously silent", str3));
return -EIO;
}
/* Read current row data from the controller, assuming it's already
/* Read current row data from the controller, assuming it's already
* requested.
*/
static int tp_controller_read_data(struct tp_controller_row *data)
static int thinkpad_ec_read_data(struct thinkpad_ec_row *data)
{
int i;
u8 str3 = inb(TPC_STR3_PORT) & H8S_STR3_MASK;
/* Once we make a request, STR3 assumes the following sequence of
* values as it reads the request and writes its data.
/* Once we make a request, STR3 assumes the sequence of values listed
* in the following 'if' as it reads the request and writes its data.
* It takes about a few dozen nanosecs total, with very high variance.
*/
if (str3==(H8S_STR3_IBF3B|H8S_STR3_MWMF) ||
str3==0x00 ||
str3==0x00 || /* the 0x00 is indistinguishable from idle EC! */
str3==H8S_STR3_SWMF )
return -EBUSY; /* not ready yet */
/* Finally, it signals output buffer full: */
/* Finally, the EC signals output buffer full: */
if (str3 != (H8S_STR3_OBF3B|H8S_STR3_SWMF)) {
printk(KERN_WARNING
MSG_FMT("bad initial STR3 (0x%02x)", str3));
@ -234,7 +234,7 @@ static int tp_controller_read_data(struct tp_controller_row *data)
/* Is the given row currently prefetched?
* To keep things simple we compare only the first and last args;
* in practice this suffices .*/
static int tp_controller_is_row_fetched(const struct tp_controller_row *args)
static int thinkpad_ec_is_row_fetched(const struct thinkpad_ec_row *args)
{
return (prefetch_jiffies != TPC_PREFETCH_NONE) &&
(prefetch_jiffies != TPC_PREFETCH_JUNK) &&
@ -243,41 +243,41 @@ static int tp_controller_is_row_fetched(const struct tp_controller_row *args)
(get_jiffies_64() < prefetch_jiffies + TPC_PREFETCH_TIMEOUT);
}
/* tp_controller_read_row:
/* thinkpad_ec_read_row:
* Read a data row from the controller, fetching and retrying if needed.
* The row args are specified by 16 byte arguments, some of which may be
* missing (but the first and last are mandatory). These are given in
* args->val[], args->val[i] is used iff (args->mask>>i)&1).
* args->val[], where args->val[i] is used iff (args->mask>>i)&1).
* The rows's data is stored in data->val[], but is only guaranteed to be
* valid for indices corresponding to set bit in data->maska. That is,
* if (data->mask>>i)&1==0 then data->val[i] may not be filled (to save time).
* Returns -EBUSY on transient error and -EIO on abnormal condition.
* Caller must hold controller lock.
*/
int tp_controller_read_row(const struct tp_controller_row *args,
struct tp_controller_row *data)
int thinkpad_ec_read_row(const struct thinkpad_ec_row *args,
struct thinkpad_ec_row *data)
{
int retries, ret;
if (tp_controller_is_row_fetched(args))
if (thinkpad_ec_is_row_fetched(args))
goto read_row; /* already requested */
/* Request the row */
for (retries=0; retries<TPC_READ_RETRIES; ++retries) {
ret = tp_controller_request_row(args);
ret = thinkpad_ec_request_row(args);
if (!ret)
goto read_row;
if (ret != -EBUSY)
break;
ndelay(TPC_READ_NDELAY);
}
printk(KERN_ERR ARG_FMT("failed requesting row", ret));
printk(KERN_ERR REQ_FMT("failed requesting row", ret));
goto out;
read_row:
/* Read the row's data */
for (retries=0; retries<TPC_READ_RETRIES; ++retries) {
ret = tp_controller_read_data(data);
ret = thinkpad_ec_read_data(data);
if (!ret)
goto out;
if (ret!=-EBUSY)
@ -285,50 +285,50 @@ read_row:
ndelay(TPC_READ_NDELAY);
}
printk(KERN_ERR ARG_FMT("failed waiting for data", ret));
printk(KERN_ERR REQ_FMT("failed waiting for data", ret));
out:
prefetch_jiffies = TPC_PREFETCH_JUNK;
return ret;
}
EXPORT_SYMBOL_GPL(tp_controller_read_row);
EXPORT_SYMBOL_GPL(thinkpad_ec_read_row);
/* tp_controller_try_read_row:
/* thinkpad_ec_try_read_row:
* Try read a prefetched row from the controller. Don't fetch or retry.
* See tp_controller_read_row above for the meaning of the arguments.
* See thinkpad_ec_read_row above for the meaning of the arguments.
* Returns -EBUSY is data not ready and -ENODATA if row not prefetched.
* Caller must hold controller lock.
*/
int tp_controller_try_read_row(const struct tp_controller_row *args,
struct tp_controller_row *data)
int thinkpad_ec_try_read_row(const struct thinkpad_ec_row *args,
struct thinkpad_ec_row *data)
{
int ret;
if (!tp_controller_is_row_fetched(args)) {
if (!thinkpad_ec_is_row_fetched(args)) {
ret = -ENODATA;
} else {
ret = tp_controller_read_data(data);
ret = thinkpad_ec_read_data(data);
if (!ret)
prefetch_jiffies = TPC_PREFETCH_NONE; /* eaten up */
}
return ret;
}
EXPORT_SYMBOL_GPL(tp_controller_try_read_row);
EXPORT_SYMBOL_GPL(thinkpad_ec_try_read_row);
/* tp_controller_prefetch_row:
/* thinkpad_ec_prefetch_row:
* Prefetch data row from the controller. A subsequent call to
* tp_controller_read_row() with the same arguments will be faster,
* and a subsequent call to tp_controller_try_read_row stands a
* thinkpad_ec_read_row() with the same arguments will be faster,
* and a subsequent call to thinkpad_ec_try_read_row stands a
* good chance of succeeding if done neither too soon nor too late.
* See tp_controller_read_row above for the meaning of the arguments.
* See thinkpad_ec_read_row above for the meaning of the arguments.
* Returns -EBUSY on transient error and -EIO on abnormal condition.
* Caller must hold controller lock.
*/
int tp_controller_prefetch_row(const struct tp_controller_row *args)
int thinkpad_ec_prefetch_row(const struct thinkpad_ec_row *args)
{
int ret;
ret = tp_controller_request_row(args);
ret = thinkpad_ec_request_row(args);
if (ret) {
prefetch_jiffies = TPC_PREFETCH_JUNK;
} else {
@ -339,47 +339,41 @@ int tp_controller_prefetch_row(const struct tp_controller_row *args)
return ret;
}
EXPORT_SYMBOL_GPL(tp_controller_prefetch_row);
EXPORT_SYMBOL_GPL(thinkpad_ec_prefetch_row);
/* tp_controller_invalidate:
/* thinkpad_ec_invalidate:
* Invalidate the prefetched controller data.
* Must be called before unlocking by any code that accesses the controller
* ports directly.
*/
void tp_controller_invalidate(void)
void thinkpad_ec_invalidate(void)
{
prefetch_jiffies = TPC_PREFETCH_JUNK;
}
EXPORT_SYMBOL_GPL(tp_controller_invalidate);
EXPORT_SYMBOL_GPL(thinkpad_ec_invalidate);
/* tp_controller_test:
* Ensure the EC LPC3 channel really exists on this machine by making
/*** Checking for EC hardware ***/
/* thinkpad_ec_test:
* Ensure the EC LPC3 channel really works on this machine by making
* an arbitrary harmless EC request and seeing if the EC follows protocol.
* This test writes to IO ports, so execute only after checking DMI.
*/
static int tp_controller_test(void) {
static int thinkpad_ec_test(void) {
int ret;
const struct tp_controller_row args = /* battery 0 basic status */
const struct thinkpad_ec_row args = /* battery 0 basic status */
{ .mask=0x8001, .val={0x01,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x00} };
struct tp_controller_row data = { .mask = 0x0000 };
ret = tp_controller_lock();
struct thinkpad_ec_row data = { .mask = 0x0000 };
ret = thinkpad_ec_lock();
if (ret)
return ret;
ret = tp_controller_read_row(&args, &data);
tp_controller_unlock();
ret = thinkpad_ec_read_row(&args, &data);
thinkpad_ec_unlock();
return ret;
}
/*** Model whitelist ***/
#define TP_DMI_MATCH(vendor,model) { \
.ident = vendor " " model, \
.matches = { \
DMI_MATCH(DMI_BOARD_VENDOR, vendor), \
DMI_MATCH(DMI_PRODUCT_VERSION, model) \
} \
}
/* Search all DMI device names for a given type for a substrng */
static int __init dmi_find_substring(int type, const char *substr) {
struct dmi_device *dev = NULL;
@ -390,8 +384,16 @@ static int __init dmi_find_substring(int type, const char *substr) {
return 0;
}
#define TP_DMI_MATCH(vendor,model) { \
.ident = vendor " " model, \
.matches = { \
DMI_MATCH(DMI_BOARD_VENDOR, vendor), \
DMI_MATCH(DMI_PRODUCT_VERSION, model) \
} \
}
/* Check DMI for existence of ThinkPad embedded controller */
static int __init check_for_embedded_controller(void)
static int __init check_dmi_for_ec(void)
{
/* A few old models that have a good EC but don't report it in DMI */
struct dmi_system_id tp_whitelist[] = {
@ -412,36 +414,36 @@ static int __init check_for_embedded_controller(void)
/*** Init and cleanup ***/
static int __init tp_base_init(void)
static int __init thinkpad_ec_init(void)
{
if (!check_for_embedded_controller()) {
printk(KERN_ERR "tp_base: no ThinkPad embedded controller!\n");
if (!check_dmi_for_ec()) {
printk(KERN_ERR "thinkpad_ec: no ThinkPad embedded controller!\n");
return -ENODEV;
}
if (!request_region(TPC_BASE_PORT, TPC_NUM_PORTS,
"thinkpad_ec"))
{
printk(KERN_ERR "tp_base: cannot claim io ports %#x-%#x\n",
printk(KERN_ERR "thinkpad_ec: cannot claim io ports %#x-%#x\n",
TPC_BASE_PORT,
TPC_BASE_PORT + TPC_NUM_PORTS -1);
return -ENXIO;
}
prefetch_jiffies = TPC_PREFETCH_JUNK;
if (tp_controller_test()) {
printk(KERN_INFO "tp_base: init test failed\n");
if (thinkpad_ec_test()) {
printk(KERN_INFO "thinkpad_ec: initial ec test failed\n");
release_region(TPC_BASE_PORT, TPC_NUM_PORTS);
return -ENXIO;
}
printk(KERN_INFO "tp_base: tp_base " TP_VERSION " loaded.\n");
printk(KERN_INFO "thinkpad_ec: thinkpad_ec " TP_VERSION " loaded.\n");
return 0;
}
static void __exit tp_base_exit(void)
static void __exit thinkpad_ec_exit(void)
{
release_region(TPC_BASE_PORT, TPC_NUM_PORTS);
printk(KERN_INFO "tp_base: unloaded.\n");
printk(KERN_INFO "thinkpad_ec: unloaded.\n");
}
module_init(tp_base_init);
module_exit(tp_base_exit);
module_init(thinkpad_ec_init);
module_exit(thinkpad_ec_exit);

View File

@ -1,5 +1,5 @@
/*
* tp_base.h - interface to the ThinkPad embedded controller LPC3 functions
* thinkpad_ec.h - interface to ThinkPad embedded controller LPC3 functions
*
* Copyright (C) 2005 Shem Multinymous <multinymous@gmail.com>
*
@ -18,29 +18,30 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _TP_BASE_H
#define _TP_BASE_H
#ifndef _THINKPAD_EC_H
#define _THINKPAD_EC_H
#ifdef __KERNEL__
#define TP_CONTROLLER_ROW_LEN 16
struct tp_controller_row {
/* EC transactions input and output (possibly partial) vectors of 16 bytes. */
struct thinkpad_ec_row {
u16 mask; /* bitmap of which entries of val[] are meaningful */
u8 val[TP_CONTROLLER_ROW_LEN];
};
extern int tp_controller_lock(void);
extern int tp_controller_try_lock(void);
extern void tp_controller_unlock(void);
extern int thinkpad_ec_lock(void);
extern int thinkpad_ec_try_lock(void);
extern void thinkpad_ec_unlock(void);
extern int tp_controller_read_row(const struct tp_controller_row *args,
struct tp_controller_row *data);
extern int tp_controller_try_read_row(const struct tp_controller_row *args,
struct tp_controller_row *mask);
extern int tp_controller_prefetch_row(const struct tp_controller_row *args);
extern void tp_controller_invalidate(void);
extern int thinkpad_ec_read_row(const struct thinkpad_ec_row *args,
struct thinkpad_ec_row *data);
extern int thinkpad_ec_try_read_row(const struct thinkpad_ec_row *args,
struct thinkpad_ec_row *mask);
extern int thinkpad_ec_prefetch_row(const struct thinkpad_ec_row *args);
extern void thinkpad_ec_invalidate(void);
#endif /* __KERNEL */
#endif /* _TP_BASE_H */
#endif /* _THINKPAD_EC_H */

View File

@ -7,7 +7,7 @@
* to the APM control port 0xB2. Older models use a different interface;
* for those, try the "thinkpad" module.
* It also exposes battery status information, obtained from the ThinkPad
* embedded controller (via the tp_base module).
* embedded controller (via the thinkpad_ec module).
*
*
* Copyright (C) 2006 Shem Multinymous <multinymous@gmail.com>.
@ -36,12 +36,12 @@
#include <linux/mc146818rtc.h> /* CMOS defines */
#include <linux/delay.h>
#include <linux/version.h>
#include <linux/tp_base.h>
#include <linux/thinkpad_ec.h>
#include <linux/platform_device.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#define TP_VERSION "0.26"
#define TP_VERSION "0.27"
#define TP_DESC "ThinkPad SMAPI Support"
#define TP_DIR "smapi"
@ -175,10 +175,9 @@ static int smapi_request(u32 inBX, u32 inCX,
DPRINTK("req_in: BX=%x CX=%x DI=%x SI=%x\n",
inBX, inCX, inDI, inSI);
/* SMAPI's SMBIOS call and tp_base end up using use different
* interfaces to the same chip, so play it safe (necessary?):
*/
ret = tp_controller_lock();
/* SMAPI's SMBIOS call and thinkpad_ec end up using use
* different interfaces to the same chip, so play it safe. */
ret = thinkpad_ec_lock();
if (ret)
return ret;
@ -209,8 +208,8 @@ static int smapi_request(u32 inBX, u32 inCX,
:"%eax", "%ebx", "%ecx", "%edx", "%edi",
"%esi");
tp_controller_invalidate();
tp_controller_unlock();
thinkpad_ec_invalidate();
thinkpad_ec_unlock();
/* Don't let the next SMAPI access happen too quickly,
* may case problems. (We're hold smapi_mutex). */
@ -261,15 +260,15 @@ static int smapi_write(u32 inBX, u32 inCX,
*/
static int tpc_read_row(u8 arg0, int bat, u8 j, u8* dataval) {
int ret;
const struct tp_controller_row args = { .mask=0xFFFF,
const struct thinkpad_ec_row args = { .mask=0xFFFF,
.val={arg0, j,j,j,j,j,j,j,j,j,j,j,j,j,j, (u8)bat} };
struct tp_controller_row data = { .mask = 0xFFFF };
struct thinkpad_ec_row data = { .mask = 0xFFFF };
ret = tp_controller_lock();
ret = thinkpad_ec_lock();
if (ret)
return ret;
ret = tp_controller_read_row(&args, &data);
tp_controller_unlock();
ret = thinkpad_ec_read_row(&args, &data);
thinkpad_ec_unlock();
memcpy(dataval, &data.val, TP_CONTROLLER_ROW_LEN);
return ret;
}