From 76c960fd639d677998acc512a82ef257696e2b9d Mon Sep 17 00:00:00 2001 From: =?utf8?q?Mathieu=20B=C3=A9rard?= Date: Sun, 4 Feb 2007 02:11:15 +0000 Subject: [PATCH] * Merge experimental branch changes (235:HEAD) back to trunk But don't merge fan feature for TSM70, as it is not yet ready --- Makefile | 6 ++-- acpi.c | 58 +++++++++++++++++++++++++++++------ cooling.c | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++ doc/ChangeLog | 8 +++++ dump.c | 8 ++++- hardware.h | 12 ++++++-- muteled.c | 7 ++--- omnibook.h | 9 ------ pio.c | 1 - throttling.c | 83 +++++++++++++++++++++++++++++++++++++++++++++++++ touchpad.c | 9 +++--- 11 files changed, 252 insertions(+), 34 deletions(-) create mode 100644 cooling.c create mode 100644 throttling.c diff --git a/Makefile b/Makefile index 71ec838..bc4b2fd 100644 --- a/Makefile +++ b/Makefile @@ -48,9 +48,9 @@ EXTRA_LDFLAGS += $(src)/sections.lds OBJS = init.o lib.o ec.o kbc.o pio.o compal.o acpi.o nbsmi.o \ - ac.o battery.o blank.o bluetooth.o display.o dock.o dump.o \ - fan.o fan_policy.o hotkeys.o info.o lcd.o muteled.o polling.o \ - temperature.o touchpad.o wireless.o + ac.o battery.o blank.o bluetooth.o cooling.o display.o dock.o \ + dump.o fan.o fan_policy.o hotkeys.o info.o lcd.o muteled.o \ + polling.o temperature.o touchpad.o wireless.o throttling.o obj-m += $(MODULE_NAME).o omnibook-objs := $(OBJS) diff --git a/acpi.c b/acpi.c index f9117fa..457939c 100644 --- a/acpi.c +++ b/acpi.c @@ -44,6 +44,9 @@ #define CRT_CSTE 0x2 #define TVO_CSTE 0x4 +#define GET_THROTTLE_METHOD "THRO" +#define SET_THROTTLE_METHOD "CLCK" + static char ec_dev_list[][20] = { "\\_SB.PCI0.LPCB.EC0", "\\_SB.PCI0.LPC0.EC0", @@ -52,11 +55,11 @@ static char ec_dev_list[][20] = { #define TOSHIBA_ACPI_BT_CLASS "bluetooth" #define TOSHIBA_ACPI_DEVICE_NAME "bluetooth adapter" -#define TOSH_BT_ACTIVATE_USB "AUSB" -#define TOSH_BT_DISABLE_USB "DUSB" -#define TOSH_BT_POWER_ON "BTPO" -#define TOSH_BT_POWER_OFF "BTPF" -#define TOSH_BT_STATUS "BTST" +#define TOSH_BT_ACTIVATE_USB "AUSB" +#define TOSH_BT_DISABLE_USB "DUSB" +#define TOSH_BT_POWER_ON "BTPO" +#define TOSH_BT_POWER_OFF "BTPF" +#define TOSH_BT_STATUS "BTST" #define TOSH_BT_KSST_MASK 0x1 #define TOSH_BT_USB_MASK 0x40 #define TOSH_BT_POWER_MASK 0x80 @@ -175,6 +178,7 @@ struct omnibook_backend acpi_backend; /* * Execute an ACPI method which return either an integer or nothing + * and that require 0 or 1 numerical argument * (acpi_evaluate_object wrapper) */ static int omnibook_acpi_execute(acpi_handle dev_handle, char *method, const int *param, int *result) @@ -246,7 +250,7 @@ static int omnibook_acpi_bt_add(struct acpi_device *device) dprintk("Enabling found Toshiba Bluetooth ACPI device.\n"); strcpy(acpi_device_name(device), TOSHIBA_ACPI_DEVICE_NAME); - strcpy(acpi_device_class(device), TOSHIBA_ACPI_BT_CLASS); + strcpy(acpi_device_class(device), TOSHIBA_ACPI_BT_CLASS); /* Save handle in backend private data structure. ugly. */ priv_data->bt_handle = device->handle; @@ -273,7 +277,7 @@ static int get_bt_status(const struct acpi_backend_data *priv_data, unsigned int int retval = 0; int raw_state; - if ((retval = omnibook_acpi_execute(priv_data->bt_handle, TOSH_BT_STATUS, 0, &raw_state))) + if ((retval = omnibook_acpi_execute(priv_data->bt_handle, TOSH_BT_STATUS, NULL, &raw_state))) return retval; dprintk("BTST raw_state: %x\n", raw_state); @@ -293,7 +297,7 @@ static int get_wireless_status(const struct acpi_backend_data *priv_data, unsign int retval = 0; int raw_state; - if ((retval = omnibook_acpi_execute(priv_data->ec_handle, GET_WIRELESS_METHOD, 0, &raw_state))) + if ((retval = omnibook_acpi_execute(priv_data->ec_handle, GET_WIRELESS_METHOD, NULL, &raw_state))) return retval; dprintk("get_wireless raw_state: %x\n", raw_state); @@ -363,7 +367,7 @@ static int omnibook_acpi_get_display(const struct omnibook_operation *io_op, uns int raw_state = 0; struct acpi_backend_data *priv_data = io_op->backend->data; - retval = omnibook_acpi_execute(priv_data->ec_handle, GET_DISPLAY_METHOD, 0, &raw_state); + retval = omnibook_acpi_execute(priv_data->ec_handle, GET_DISPLAY_METHOD, NULL, &raw_state); if (retval < 0) return retval; @@ -419,6 +423,40 @@ static int omnibook_acpi_set_display(const struct omnibook_operation *io_op, uns return DISPLAY_LCD_ON | DISPLAY_CRT_ON | DISPLAY_TVO_ON; } +static int omnibook_acpi_get_throttle(const struct omnibook_operation *io_op, unsigned int *state) +{ + int retval; + int thtl_en = 0, thtl_dty = 0; + int param; + struct acpi_backend_data *priv_data = io_op->backend->data; + + param = 0; + /* Read THEN aka THTL_EN in ICH6M datasheets */ + retval = omnibook_acpi_execute(priv_data->ec_handle, GET_THROTTLE_METHOD, ¶m, &thtl_en); + if ( thtl_en == 0 ) { + *state = 0; + return retval; + } + param = 1; + /* Read DUTY aka THTL_DTY in ICH6M datasheets */ + retval = omnibook_acpi_execute(priv_data->ec_handle, GET_THROTTLE_METHOD, ¶m, &thtl_dty); + WARN_ON(thtl_dty > 7); /* We shouldn't encounter more than 7 throttling level */ + *state = 8 - thtl_dty; /* THTL_DTY and ACPI T-state are reverse mapped */ + return retval; +} + +static int omnibook_acpi_set_throttle(const struct omnibook_operation *io_op, unsigned int state) +{ + struct acpi_backend_data *priv_data = io_op->backend->data; + /* THTL_DTY and ACPI T-state are reverse mapped */ + /* throttling.c already clamped state between 0 and 7 */ + if (state) + state = 8 - state; + + return omnibook_acpi_execute(priv_data->ec_handle, SET_THROTTLE_METHOD, &state, NULL); +} + + struct omnibook_backend acpi_backend = { .name = "acpi", .init = omnibook_acpi_init, @@ -427,6 +465,8 @@ struct omnibook_backend acpi_backend = { .aerial_set = omnibook_acpi_set_wireless, .display_get = omnibook_acpi_get_display, .display_set = omnibook_acpi_set_display, + .throttle_get = omnibook_acpi_get_throttle, + .throttle_set = omnibook_acpi_set_throttle, }; #else /* CONFIG_ACPI */ diff --git a/cooling.c b/cooling.c new file mode 100644 index 0000000..e2054c6 --- /dev/null +++ b/cooling.c @@ -0,0 +1,85 @@ +/* + * colling.c -- cooling methods feature + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * Written by Mathieu Bérard , 2007 + */ + +#include "omnibook.h" +#include "hardware.h" + +static int omnibook_cooling_read(char *buffer, struct omnibook_operation *io_op) +{ + int len = 0; + + if(mutex_lock_interruptible(&io_op->backend->mutex)) + return -ERESTARTSYS; + + len += sprintf(buffer + len, "Cooling method : %s\n", + io_op->backend->cooling_state ? "Performance" : "Powersave" ); + + mutex_unlock(&io_op->backend->mutex); + return len; +} + +static int omnibook_cooling_write(char *buffer, struct omnibook_operation *io_op) +{ + int retval = 0; + + if (*buffer == '0') { + retval = backend_byte_write(io_op, + TSM70_COOLING_OFFSET + TSM70_COOLING_POWERSAVE); + } else if (*buffer == '1') { + retval = backend_byte_write(io_op, + TSM70_COOLING_OFFSET + TSM70_COOLING_PERF); + } else { + return -EINVAL; + } + + return retval; +} + +static int __init omnibook_cooling_init(struct omnibook_operation *io_op) +{ + mutex_lock(&io_op->backend->mutex); + /* XXX: Assumed default cooling method: performance */ + io_op->backend->cooling_state = TSM70_COOLING_PERF; + mutex_unlock(&io_op->backend->mutex); + return 0; +} + +static void __exit omnibook_cooling_exit(struct omnibook_operation *io_op) +{ + /* Set back cooling method to performance */ + backend_byte_write(io_op, TSM70_COOLING_OFFSET + TSM70_COOLING_PERF); +} + +static struct omnibook_tbl cooling_table[] __initdata = { + {TSM70, {CDI, 0, TSM70_FN_INDEX, 0, 0, 0 }}, + {0,} +}; + +struct omnibook_feature __declared_feature cooling_driver = { + .name = "cooling", + .enabled = 1, + .read = omnibook_cooling_read, + .write = omnibook_cooling_write, + .init = omnibook_cooling_init, + .exit = omnibook_cooling_exit, + .ectypes = TSM70, + .tbl = cooling_table, +}; + +module_param_named(cooling, cooling_driver.enabled, int, S_IRUGO); +MODULE_PARM_DESC(cooling, "Use 0 to disable, 1 to enable CPU cooling method control"); + +/* End of file */ diff --git a/doc/ChangeLog b/doc/ChangeLog index d9f6887..ea3840f 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -27,6 +27,14 @@ Changelog file for omnibook package: The state of the Toshiba M35X is unknown and is assigned to TSM70, one should send a bug report if that fail. Fix bugs 1617818 and 1605278 +* New features for TSM70 class laptops: + -Cooling method control (can tune fan behaviour to 'Save power' or + to 'Maximize performance') provided in /proc/omnibook/cooling + -CPU Throttling status&control (also known as ACPI T-States) should + be supported out of the box via /proc/acpi/processor/CPU0/throttling + but at least Toshiba Satellite M70 as a deficient ACPI FADT table + which prevent than, thus a custom access to ACPI Throttling is + provided in /proc/omnibook/throttling 2.20060921 Mathieu Bérard * The minimal required kernel version is now 2.6.9 (kref API) diff --git a/dump.c b/dump.c index ae55281..ff959e9 100644 --- a/dump.c +++ b/dump.c @@ -34,11 +34,15 @@ static int ecdump_read(char *buffer, struct omnibook_operation *io_op) sprintf(buffer + len, "EC " " +00 +01 +02 +03 +04 +05 +06 +07" " +08 +09 +0a +0b +0c +0d +0e +0f\n"); + + if(mutex_lock_interruptible(&io_op->backend->mutex)) + return -ERESTARTSYS; + for (i = 0; i < 255; i += 16) { len += sprintf(buffer + len, "EC 0x%02x:", i); for (j = 0; j < 16; j++) { io_op->read_addr = i +j; - if (backend_byte_read(io_op, &v)) + if (__backend_byte_read(io_op, &v)) break; if (v != ecdump_regs[i + j]) len += sprintf(buffer + len, " *%02x", v); @@ -51,6 +55,8 @@ static int ecdump_read(char *buffer, struct omnibook_operation *io_op) break; } + mutex_unlock(&io_op->backend->mutex); + /* These are way too dangerous to advertise openly... */ #if 0 len += diff --git a/hardware.h b/hardware.h index 7a046cc..16f8e8a 100644 --- a/hardware.h +++ b/hardware.h @@ -12,7 +12,7 @@ * General Public License for more details. * * Written by Soós Péter , 2002-2004 - * Modified by Mathieu Bérard , 2006 + * Modified by Mathieu Bérard , 2006-2007 */ #include @@ -55,7 +55,9 @@ struct omnibook_backend { /* Public data fields, access with mutex held */ unsigned int hotkeys_state; /* saved hotkeys state */ - unsigned int misc_state; /* various status bit: touchpad and muteled */ + unsigned int touchpad_state; /* saved touchpad state */ + unsigned int muteled_state; /* saved muteled state */ + unsigned int cooling_state; /* saved cooling method state */ /* Public function pointers */ int (*init) (const struct omnibook_operation *); @@ -68,6 +70,8 @@ struct omnibook_backend { int (*hotkeys_set) (const struct omnibook_operation *, unsigned int); int (*display_get) (const struct omnibook_operation *, unsigned int *); int (*display_set) (const struct omnibook_operation *, unsigned int); + int (*throttle_get) (const struct omnibook_operation *, unsigned int *); + int (*throttle_set) (const struct omnibook_operation *, unsigned int); /* Private fields, never to be accessed outside backend code */ struct kref kref; /* Reference counter of this backend */ @@ -133,6 +137,7 @@ static inline int __backend_##func##_set(const struct omnibook_operation *io_op, helper_func(aerial) helper_func(hotkeys) helper_func(display) +helper_func(throttle) static inline int backend_byte_read(const struct omnibook_operation *io_op, u8 *data) { @@ -502,6 +507,9 @@ static inline int omnibook_toggle(const struct omnibook_operation *io_op, int to #define TSM100_BLANK_INDEX 0x59 #define TSM100_LCD_ON 0xe1 #define TSM100_LCD_OFF 0xe2 +#define TSM70_COOLING_OFFSET 0xb0 +#define TSM70_COOLING_POWERSAVE 0x0 +#define TSM70_COOLING_PERF 0x2 /* Toshiba SMI funtions and constants*/ #define SMI_FN_PRESSED 0x8f diff --git a/muteled.c b/muteled.c index 751b8ef..a21793a 100644 --- a/muteled.c +++ b/muteled.c @@ -30,8 +30,7 @@ static int omnibook_muteled_set(struct omnibook_operation *io_op, int status) goto out; } - io_op->backend->misc_state = - (io_op->backend->misc_state & ~MUTELED) | (MUTELED * !!status); + io_op->backend->muteled_state = !!status; out: mutex_unlock(&io_op->backend->mutex); @@ -49,7 +48,7 @@ static int omnibook_muteled_read(char *buffer, struct omnibook_operation *io_op) return -ERESTARTSYS; len += sprintf(buffer + len, "Last mute LED action was an %s command.\n", - (io_op->backend->misc_state & MUTELED) ? "on" : "off"); + io_op->backend->touchpad_state ? "on" : "off"); mutex_unlock(&io_op->backend->mutex); return len; @@ -77,7 +76,7 @@ static int omnibook_muteled_resume(struct omnibook_operation *io_op) { int retval; mutex_lock(&io_op->backend->mutex); - retval = __omnibook_toggle(io_op, !!(io_op->backend->misc_state & MUTELED)); + retval = __omnibook_toggle(io_op, !!io_op->backend->touchpad_state); mutex_unlock(&io_op->backend->mutex); return retval; } diff --git a/omnibook.h b/omnibook.h index d9348e8..31a727f 100644 --- a/omnibook.h +++ b/omnibook.h @@ -100,15 +100,6 @@ enum { #define HKEY_LAST_SHIFT 6 -/* - * Various status bits - */ -enum { - MUTELED = (1<<0), /* Mute LED status */ - TOUCHPAD = (1<<1), /* Touchpad status */ -}; - - /* * Display state backend neutral masks * _ON masks = port is powered up and running diff --git a/pio.c b/pio.c index 4e197e9..312811e 100644 --- a/pio.c +++ b/pio.c @@ -138,7 +138,6 @@ static void omnibook_pio_exit(const struct omnibook_operation *io_op) if (match) kref_put(&match->refcount, omnibook_free_port); - match = NULL; match = omnibook_match_port(io_op->backend->data, io_op->write_addr); if (match) kref_put(&match->refcount, omnibook_free_port); diff --git a/throttling.c b/throttling.c new file mode 100644 index 0000000..e2f6900 --- /dev/null +++ b/throttling.c @@ -0,0 +1,83 @@ +/* + * throttling.c --CPU throttling control feature + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * Written by Mathieu Bérard , 2007 + */ + +#include "omnibook.h" +#include "hardware.h" + +/* + * Throttling level/rate mapping found in ICH6M datasheets + * the output is set to mimic the one of /proc/acpi/cpu/CPU0/throttling + * XXX: We always assume that there are 8 T-States and one processor. + */ +static const int trate[8] = { 0, 12, 25, 37, 50, 62, 75, 87 }; + +static int omnibook_throttle_read(char *buffer, struct omnibook_operation *io_op) +{ + int len = 0; + int tstate = 0; + int retval, i; + + retval = backend_throttle_get(io_op, &tstate); + if (retval < 0) + return retval; + + len += sprintf(buffer + len, "state count: 8\n"); + len += sprintf(buffer + len, "active state: T%d\n", tstate); + for (i = 0; i < 8; i += 1) + { + len += sprintf(buffer + len, " %cT%d: %02d%%\n", + (i == tstate ? '*' : ' '), + i, + trate[i]); + } + + return len; +} + +static int omnibook_throttle_write(char *buffer, struct omnibook_operation *io_op) +{ + int retval = 0; + int data; + char *endp; + + data = simple_strtoul(buffer, &endp, 10); + if ((endp == buffer) || (data > 7)) /* There are 8 throttling levels */ + return -EINVAL; + else + retval = backend_throttle_set(io_op, data); + + return retval; +} + + +static struct omnibook_tbl throttle_table[] __initdata = { + {TSM70, {ACPI,}}, + {0,} +}; + +struct omnibook_feature __declared_feature throttle_driver = { + .name = "throttling", + .enabled = 1, + .read = omnibook_throttle_read, + .write = omnibook_throttle_write, + .ectypes = TSM70, + .tbl = throttle_table, +}; + +module_param_named(throttle, throttle_driver.enabled, int, S_IRUGO); +MODULE_PARM_DESC(throttle, "Use 0 to disable, 1 to enable CPU throttling control"); + +/* End of file */ diff --git a/touchpad.c b/touchpad.c index f3a7f5b..b95e2ec 100644 --- a/touchpad.c +++ b/touchpad.c @@ -30,8 +30,7 @@ static int omnibook_touchpad_set(struct omnibook_operation *io_op, int status) goto out; } - io_op->backend->misc_state = - (io_op->backend->misc_state & ~TOUCHPAD) | (TOUCHPAD * !!status); + io_op->backend->touchpad_state = !!status; out: mutex_unlock(&io_op->backend->mutex); @@ -45,7 +44,7 @@ static int omnibook_touchpad_resume(struct omnibook_operation *io_op) { int retval; mutex_lock(&io_op->backend->mutex); - retval = __omnibook_toggle(io_op, !!(io_op->backend->misc_state & TOUCHPAD)); + retval = __omnibook_toggle(io_op, !!io_op->backend->touchpad_state); mutex_unlock(&io_op->backend->mutex); return retval; } @@ -62,7 +61,7 @@ static int omnibook_touchpad_read(char *buffer, struct omnibook_operation *io_op len += sprintf(buffer + len, "Last touchpad action was an %s command.\n", - (io_op->backend->misc_state & TOUCHPAD) ? "enable" : "disable"); + io_op->backend->touchpad_state ? "enable" : "disable"); mutex_unlock(&io_op->backend->mutex); return len; @@ -88,7 +87,7 @@ static int __init omnibook_touchpad_init(struct omnibook_operation *io_op) { mutex_lock(&io_op->backend->mutex); /* Touchpad is assumed to be enabled by default */ - io_op->backend->misc_state |= TOUCHPAD; + io_op->backend->touchpad_state = 1; mutex_unlock(&io_op->backend->mutex); return 0; } -- 2.43.5