mirror of
https://github.com/FEX-Emu/linux.git
synced 2024-12-16 14:02:10 +00:00
ACPI: thinkpad-acpi: prepare light and LED for sysfs support
Do some preparatory work to add sysfs support to the thinklight and thinkpad leds driver. Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br> Signed-off-by: Len Brown <len.brown@intel.com>
This commit is contained in:
parent
95e57ab2cb
commit
4fa6811b8a
@ -245,6 +245,8 @@ config THINKPAD_ACPI
|
|||||||
select HWMON
|
select HWMON
|
||||||
select NVRAM
|
select NVRAM
|
||||||
depends on INPUT
|
depends on INPUT
|
||||||
|
select NEW_LEDS
|
||||||
|
select LEDS_CLASS
|
||||||
---help---
|
---help---
|
||||||
This is a driver for the IBM and Lenovo ThinkPad laptops. It adds
|
This is a driver for the IBM and Lenovo ThinkPad laptops. It adds
|
||||||
support for Fn-Fx key combinations, Bluetooth control, video
|
support for Fn-Fx key combinations, Bluetooth control, video
|
||||||
|
@ -67,6 +67,7 @@
|
|||||||
#include <linux/hwmon.h>
|
#include <linux/hwmon.h>
|
||||||
#include <linux/hwmon-sysfs.h>
|
#include <linux/hwmon-sysfs.h>
|
||||||
#include <linux/input.h>
|
#include <linux/input.h>
|
||||||
|
#include <linux/leds.h>
|
||||||
#include <asm/uaccess.h>
|
#include <asm/uaccess.h>
|
||||||
|
|
||||||
#include <linux/dmi.h>
|
#include <linux/dmi.h>
|
||||||
@ -85,6 +86,8 @@
|
|||||||
#define TP_CMOS_VOLUME_MUTE 2
|
#define TP_CMOS_VOLUME_MUTE 2
|
||||||
#define TP_CMOS_BRIGHTNESS_UP 4
|
#define TP_CMOS_BRIGHTNESS_UP 4
|
||||||
#define TP_CMOS_BRIGHTNESS_DOWN 5
|
#define TP_CMOS_BRIGHTNESS_DOWN 5
|
||||||
|
#define TP_CMOS_THINKLIGHT_ON 12
|
||||||
|
#define TP_CMOS_THINKLIGHT_OFF 13
|
||||||
|
|
||||||
/* NVRAM Addresses */
|
/* NVRAM Addresses */
|
||||||
enum tp_nvram_addr {
|
enum tp_nvram_addr {
|
||||||
@ -269,6 +272,13 @@ static enum {
|
|||||||
static int experimental;
|
static int experimental;
|
||||||
static u32 dbg_level;
|
static u32 dbg_level;
|
||||||
|
|
||||||
|
/* Special LED class that can defer work */
|
||||||
|
struct tpacpi_led_classdev {
|
||||||
|
struct led_classdev led_classdev;
|
||||||
|
struct work_struct work;
|
||||||
|
enum led_brightness new_brightness;
|
||||||
|
};
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
****************************************************************************
|
****************************************************************************
|
||||||
*
|
*
|
||||||
@ -3237,6 +3247,39 @@ static struct ibm_struct video_driver_data = {
|
|||||||
TPACPI_HANDLE(lght, root, "\\LGHT"); /* A21e, A2xm/p, T20-22, X20-21 */
|
TPACPI_HANDLE(lght, root, "\\LGHT"); /* A21e, A2xm/p, T20-22, X20-21 */
|
||||||
TPACPI_HANDLE(ledb, ec, "LEDB"); /* G4x */
|
TPACPI_HANDLE(ledb, ec, "LEDB"); /* G4x */
|
||||||
|
|
||||||
|
static int light_get_status(void)
|
||||||
|
{
|
||||||
|
int status = 0;
|
||||||
|
|
||||||
|
if (tp_features.light_status) {
|
||||||
|
if (!acpi_evalf(ec_handle, &status, "KBLT", "d"))
|
||||||
|
return -EIO;
|
||||||
|
return (!!status);
|
||||||
|
}
|
||||||
|
|
||||||
|
return -ENXIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int light_set_status(int status)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if (tp_features.light) {
|
||||||
|
if (cmos_handle) {
|
||||||
|
rc = acpi_evalf(cmos_handle, NULL, NULL, "vd",
|
||||||
|
(status)?
|
||||||
|
TP_CMOS_THINKLIGHT_ON :
|
||||||
|
TP_CMOS_THINKLIGHT_OFF);
|
||||||
|
} else {
|
||||||
|
rc = acpi_evalf(lght_handle, NULL, NULL, "vd",
|
||||||
|
(status)? 1 : 0);
|
||||||
|
}
|
||||||
|
return (rc)? 0 : -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -ENXIO;
|
||||||
|
}
|
||||||
|
|
||||||
static int __init light_init(struct ibm_init_struct *iibm)
|
static int __init light_init(struct ibm_init_struct *iibm)
|
||||||
{
|
{
|
||||||
vdbg_printk(TPACPI_DBG_INIT, "initializing light subdriver\n");
|
vdbg_printk(TPACPI_DBG_INIT, "initializing light subdriver\n");
|
||||||
@ -3263,7 +3306,7 @@ static int __init light_init(struct ibm_init_struct *iibm)
|
|||||||
static int light_read(char *p)
|
static int light_read(char *p)
|
||||||
{
|
{
|
||||||
int len = 0;
|
int len = 0;
|
||||||
int status = 0;
|
int status;
|
||||||
|
|
||||||
if (!tp_features.light) {
|
if (!tp_features.light) {
|
||||||
len += sprintf(p + len, "status:\t\tnot supported\n");
|
len += sprintf(p + len, "status:\t\tnot supported\n");
|
||||||
@ -3271,8 +3314,9 @@ static int light_read(char *p)
|
|||||||
len += sprintf(p + len, "status:\t\tunknown\n");
|
len += sprintf(p + len, "status:\t\tunknown\n");
|
||||||
len += sprintf(p + len, "commands:\ton, off\n");
|
len += sprintf(p + len, "commands:\ton, off\n");
|
||||||
} else {
|
} else {
|
||||||
if (!acpi_evalf(ec_handle, &status, "KBLT", "d"))
|
status = light_get_status();
|
||||||
return -EIO;
|
if (status < 0)
|
||||||
|
return status;
|
||||||
len += sprintf(p + len, "status:\t\t%s\n", onoff(status, 0));
|
len += sprintf(p + len, "status:\t\t%s\n", onoff(status, 0));
|
||||||
len += sprintf(p + len, "commands:\ton, off\n");
|
len += sprintf(p + len, "commands:\ton, off\n");
|
||||||
}
|
}
|
||||||
@ -3282,31 +3326,22 @@ static int light_read(char *p)
|
|||||||
|
|
||||||
static int light_write(char *buf)
|
static int light_write(char *buf)
|
||||||
{
|
{
|
||||||
int cmos_cmd, lght_cmd;
|
|
||||||
char *cmd;
|
char *cmd;
|
||||||
int success;
|
int newstatus = 0;
|
||||||
|
|
||||||
if (!tp_features.light)
|
if (!tp_features.light)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
while ((cmd = next_cmd(&buf))) {
|
while ((cmd = next_cmd(&buf))) {
|
||||||
if (strlencmp(cmd, "on") == 0) {
|
if (strlencmp(cmd, "on") == 0) {
|
||||||
cmos_cmd = 0x0c;
|
newstatus = 1;
|
||||||
lght_cmd = 1;
|
|
||||||
} else if (strlencmp(cmd, "off") == 0) {
|
} else if (strlencmp(cmd, "off") == 0) {
|
||||||
cmos_cmd = 0x0d;
|
newstatus = 0;
|
||||||
lght_cmd = 0;
|
|
||||||
} else
|
} else
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
success = cmos_handle ?
|
|
||||||
acpi_evalf(cmos_handle, NULL, NULL, "vd", cmos_cmd) :
|
|
||||||
acpi_evalf(lght_handle, NULL, NULL, "vd", lght_cmd);
|
|
||||||
if (!success)
|
|
||||||
return -EIO;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return light_set_status(newstatus);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct ibm_struct light_driver_data = {
|
static struct ibm_struct light_driver_data = {
|
||||||
@ -3710,6 +3745,12 @@ enum { /* For TPACPI_LED_OLD */
|
|||||||
TPACPI_LED_EC_HLMS = 0x0e, /* EC reg to select led to command */
|
TPACPI_LED_EC_HLMS = 0x0e, /* EC reg to select led to command */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum led_status_t {
|
||||||
|
TPACPI_LED_OFF = 0,
|
||||||
|
TPACPI_LED_ON,
|
||||||
|
TPACPI_LED_BLINK,
|
||||||
|
};
|
||||||
|
|
||||||
static enum led_access_mode led_supported;
|
static enum led_access_mode led_supported;
|
||||||
|
|
||||||
TPACPI_HANDLE(led, ec, "SLED", /* 570 */
|
TPACPI_HANDLE(led, ec, "SLED", /* 570 */
|
||||||
@ -3718,6 +3759,69 @@ TPACPI_HANDLE(led, ec, "SLED", /* 570 */
|
|||||||
"LED", /* all others */
|
"LED", /* all others */
|
||||||
); /* R30, R31 */
|
); /* R30, R31 */
|
||||||
|
|
||||||
|
static int led_get_status(unsigned int led)
|
||||||
|
{
|
||||||
|
int status;
|
||||||
|
|
||||||
|
switch (led_supported) {
|
||||||
|
case TPACPI_LED_570:
|
||||||
|
if (!acpi_evalf(ec_handle,
|
||||||
|
&status, "GLED", "dd", 1 << led))
|
||||||
|
return -EIO;
|
||||||
|
return (status == 0)?
|
||||||
|
TPACPI_LED_OFF :
|
||||||
|
((status == 1)?
|
||||||
|
TPACPI_LED_ON :
|
||||||
|
TPACPI_LED_BLINK);
|
||||||
|
default:
|
||||||
|
return -ENXIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* not reached */
|
||||||
|
}
|
||||||
|
|
||||||
|
static int led_set_status(unsigned int led, enum led_status_t ledstatus)
|
||||||
|
{
|
||||||
|
/* off, on, blink. Index is led_status_t */
|
||||||
|
static const int const led_sled_arg1[] = { 0, 1, 3 };
|
||||||
|
static const int const led_exp_hlbl[] = { 0, 0, 1 }; /* led# * */
|
||||||
|
static const int const led_exp_hlcl[] = { 0, 1, 1 }; /* led# * */
|
||||||
|
static const int const led_led_arg1[] = { 0, 0x80, 0xc0 };
|
||||||
|
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
switch (led_supported) {
|
||||||
|
case TPACPI_LED_570:
|
||||||
|
/* 570 */
|
||||||
|
led = 1 << led;
|
||||||
|
if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
|
||||||
|
led, led_sled_arg1[ledstatus]))
|
||||||
|
rc = -EIO;
|
||||||
|
break;
|
||||||
|
case TPACPI_LED_OLD:
|
||||||
|
/* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20 */
|
||||||
|
led = 1 << led;
|
||||||
|
rc = ec_write(TPACPI_LED_EC_HLMS, led);
|
||||||
|
if (rc >= 0)
|
||||||
|
rc = ec_write(TPACPI_LED_EC_HLBL,
|
||||||
|
led * led_exp_hlbl[ledstatus]);
|
||||||
|
if (rc >= 0)
|
||||||
|
rc = ec_write(TPACPI_LED_EC_HLCL,
|
||||||
|
led * led_exp_hlcl[ledstatus]);
|
||||||
|
break;
|
||||||
|
case TPACPI_LED_NEW:
|
||||||
|
/* all others */
|
||||||
|
if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
|
||||||
|
led, led_led_arg1[ledstatus]))
|
||||||
|
rc = -EIO;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
rc = -ENXIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
static int __init led_init(struct ibm_init_struct *iibm)
|
static int __init led_init(struct ibm_init_struct *iibm)
|
||||||
{
|
{
|
||||||
vdbg_printk(TPACPI_DBG_INIT, "initializing LED subdriver\n");
|
vdbg_printk(TPACPI_DBG_INIT, "initializing LED subdriver\n");
|
||||||
@ -3743,7 +3847,9 @@ static int __init led_init(struct ibm_init_struct *iibm)
|
|||||||
return (led_supported != TPACPI_LED_NONE)? 0 : 1;
|
return (led_supported != TPACPI_LED_NONE)? 0 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define led_status(s) ((s) == 0 ? "off" : ((s) == 1 ? "on" : "blinking"))
|
#define str_led_status(s) \
|
||||||
|
((s) == TPACPI_LED_OFF ? "off" : \
|
||||||
|
((s) == TPACPI_LED_ON ? "on" : "blinking"))
|
||||||
|
|
||||||
static int led_read(char *p)
|
static int led_read(char *p)
|
||||||
{
|
{
|
||||||
@ -3759,11 +3865,11 @@ static int led_read(char *p)
|
|||||||
/* 570 */
|
/* 570 */
|
||||||
int i, status;
|
int i, status;
|
||||||
for (i = 0; i < 8; i++) {
|
for (i = 0; i < 8; i++) {
|
||||||
if (!acpi_evalf(ec_handle,
|
status = led_get_status(i);
|
||||||
&status, "GLED", "dd", 1 << i))
|
if (status < 0)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
len += sprintf(p + len, "%d:\t\t%s\n",
|
len += sprintf(p + len, "%d:\t\t%s\n",
|
||||||
i, led_status(status));
|
i, str_led_status(status));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3773,16 +3879,11 @@ static int led_read(char *p)
|
|||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* off, on, blink */
|
|
||||||
static const int led_sled_arg1[] = { 0, 1, 3 };
|
|
||||||
static const int led_exp_hlbl[] = { 0, 0, 1 }; /* led# * */
|
|
||||||
static const int led_exp_hlcl[] = { 0, 1, 1 }; /* led# * */
|
|
||||||
static const int led_led_arg1[] = { 0, 0x80, 0xc0 };
|
|
||||||
|
|
||||||
static int led_write(char *buf)
|
static int led_write(char *buf)
|
||||||
{
|
{
|
||||||
char *cmd;
|
char *cmd;
|
||||||
int led, ind, ret;
|
int led, rc;
|
||||||
|
enum led_status_t s;
|
||||||
|
|
||||||
if (!led_supported)
|
if (!led_supported)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
@ -3792,38 +3893,18 @@ static int led_write(char *buf)
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (strstr(cmd, "off")) {
|
if (strstr(cmd, "off")) {
|
||||||
ind = 0;
|
s = TPACPI_LED_OFF;
|
||||||
} else if (strstr(cmd, "on")) {
|
} else if (strstr(cmd, "on")) {
|
||||||
ind = 1;
|
s = TPACPI_LED_ON;
|
||||||
} else if (strstr(cmd, "blink")) {
|
} else if (strstr(cmd, "blink")) {
|
||||||
ind = 2;
|
s = TPACPI_LED_BLINK;
|
||||||
} else
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if (led_supported == TPACPI_LED_570) {
|
|
||||||
/* 570 */
|
|
||||||
led = 1 << led;
|
|
||||||
if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
|
|
||||||
led, led_sled_arg1[ind]))
|
|
||||||
return -EIO;
|
|
||||||
} else if (led_supported == TPACPI_LED_OLD) {
|
|
||||||
/* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20 */
|
|
||||||
led = 1 << led;
|
|
||||||
ret = ec_write(TPACPI_LED_EC_HLMS, led);
|
|
||||||
if (ret >= 0)
|
|
||||||
ret = ec_write(TPACPI_LED_EC_HLBL,
|
|
||||||
led * led_exp_hlbl[ind]);
|
|
||||||
if (ret >= 0)
|
|
||||||
ret = ec_write(TPACPI_LED_EC_HLCL,
|
|
||||||
led * led_exp_hlcl[ind]);
|
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
} else {
|
} else {
|
||||||
/* all others */
|
return -EINVAL;
|
||||||
if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
|
|
||||||
led, led_led_arg1[ind]))
|
|
||||||
return -EIO;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rc = led_set_status(led, s);
|
||||||
|
if (rc < 0)
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
Loading…
Reference in New Issue
Block a user