|
@@ -22,7 +22,7 @@
|
|
*/
|
|
*/
|
|
|
|
|
|
#define TPACPI_VERSION "0.23"
|
|
#define TPACPI_VERSION "0.23"
|
|
-#define TPACPI_SYSFS_VERSION 0x020300
|
|
|
|
|
|
+#define TPACPI_SYSFS_VERSION 0x020400
|
|
|
|
|
|
/*
|
|
/*
|
|
* Changelog:
|
|
* Changelog:
|
|
@@ -4815,7 +4815,7 @@ TPACPI_HANDLE(led, ec, "SLED", /* 570 */
|
|
"LED", /* all others */
|
|
"LED", /* all others */
|
|
); /* R30, R31 */
|
|
); /* R30, R31 */
|
|
|
|
|
|
-#define TPACPI_LED_NUMLEDS 8
|
|
|
|
|
|
+#define TPACPI_LED_NUMLEDS 16
|
|
static struct tpacpi_led_classdev *tpacpi_leds;
|
|
static struct tpacpi_led_classdev *tpacpi_leds;
|
|
static enum led_status_t tpacpi_led_state_cache[TPACPI_LED_NUMLEDS];
|
|
static enum led_status_t tpacpi_led_state_cache[TPACPI_LED_NUMLEDS];
|
|
static const char * const tpacpi_led_names[TPACPI_LED_NUMLEDS] = {
|
|
static const char * const tpacpi_led_names[TPACPI_LED_NUMLEDS] = {
|
|
@@ -4828,15 +4828,20 @@ static const char * const tpacpi_led_names[TPACPI_LED_NUMLEDS] = {
|
|
"tpacpi::dock_batt",
|
|
"tpacpi::dock_batt",
|
|
"tpacpi::unknown_led",
|
|
"tpacpi::unknown_led",
|
|
"tpacpi::standby",
|
|
"tpacpi::standby",
|
|
|
|
+ "tpacpi::dock_status1",
|
|
|
|
+ "tpacpi::dock_status2",
|
|
|
|
+ "tpacpi::unknown_led2",
|
|
|
|
+ "tpacpi::unknown_led3",
|
|
|
|
+ "tpacpi::thinkvantage",
|
|
};
|
|
};
|
|
-#define TPACPI_SAFE_LEDS 0x0081U
|
|
|
|
|
|
+#define TPACPI_SAFE_LEDS 0x1081U
|
|
|
|
|
|
static inline bool tpacpi_is_led_restricted(const unsigned int led)
|
|
static inline bool tpacpi_is_led_restricted(const unsigned int led)
|
|
{
|
|
{
|
|
#ifdef CONFIG_THINKPAD_ACPI_UNSAFE_LEDS
|
|
#ifdef CONFIG_THINKPAD_ACPI_UNSAFE_LEDS
|
|
return false;
|
|
return false;
|
|
#else
|
|
#else
|
|
- return (TPACPI_SAFE_LEDS & (1 << led)) == 0;
|
|
|
|
|
|
+ return (1U & (TPACPI_SAFE_LEDS >> led)) == 0;
|
|
#endif
|
|
#endif
|
|
}
|
|
}
|
|
|
|
|
|
@@ -4998,6 +5003,10 @@ static int __init tpacpi_init_led(unsigned int led)
|
|
|
|
|
|
tpacpi_leds[led].led = led;
|
|
tpacpi_leds[led].led = led;
|
|
|
|
|
|
|
|
+ /* LEDs with no name don't get registered */
|
|
|
|
+ if (!tpacpi_led_names[led])
|
|
|
|
+ return 0;
|
|
|
|
+
|
|
tpacpi_leds[led].led_classdev.brightness_set = &led_sysfs_set;
|
|
tpacpi_leds[led].led_classdev.brightness_set = &led_sysfs_set;
|
|
tpacpi_leds[led].led_classdev.blink_set = &led_sysfs_blink_set;
|
|
tpacpi_leds[led].led_classdev.blink_set = &led_sysfs_blink_set;
|
|
if (led_supported == TPACPI_LED_570)
|
|
if (led_supported == TPACPI_LED_570)
|
|
@@ -5016,10 +5025,59 @@ static int __init tpacpi_init_led(unsigned int led)
|
|
return rc;
|
|
return rc;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static const struct tpacpi_quirk led_useful_qtable[] __initconst = {
|
|
|
|
+ TPACPI_Q_IBM('1', 'E', 0x009f), /* A30 */
|
|
|
|
+ TPACPI_Q_IBM('1', 'N', 0x009f), /* A31 */
|
|
|
|
+ TPACPI_Q_IBM('1', 'G', 0x009f), /* A31 */
|
|
|
|
+
|
|
|
|
+ TPACPI_Q_IBM('1', 'I', 0x0097), /* T30 */
|
|
|
|
+ TPACPI_Q_IBM('1', 'R', 0x0097), /* T40, T41, T42, R50, R51 */
|
|
|
|
+ TPACPI_Q_IBM('7', '0', 0x0097), /* T43, R52 */
|
|
|
|
+ TPACPI_Q_IBM('1', 'Y', 0x0097), /* T43 */
|
|
|
|
+ TPACPI_Q_IBM('1', 'W', 0x0097), /* R50e */
|
|
|
|
+ TPACPI_Q_IBM('1', 'V', 0x0097), /* R51 */
|
|
|
|
+ TPACPI_Q_IBM('7', '8', 0x0097), /* R51e */
|
|
|
|
+ TPACPI_Q_IBM('7', '6', 0x0097), /* R52 */
|
|
|
|
+
|
|
|
|
+ TPACPI_Q_IBM('1', 'K', 0x00bf), /* X30 */
|
|
|
|
+ TPACPI_Q_IBM('1', 'Q', 0x00bf), /* X31, X32 */
|
|
|
|
+ TPACPI_Q_IBM('1', 'U', 0x00bf), /* X40 */
|
|
|
|
+ TPACPI_Q_IBM('7', '4', 0x00bf), /* X41 */
|
|
|
|
+ TPACPI_Q_IBM('7', '5', 0x00bf), /* X41t */
|
|
|
|
+
|
|
|
|
+ TPACPI_Q_IBM('7', '9', 0x1f97), /* T60 (1) */
|
|
|
|
+ TPACPI_Q_IBM('7', '7', 0x1f97), /* Z60* (1) */
|
|
|
|
+ TPACPI_Q_IBM('7', 'F', 0x1f97), /* Z61* (1) */
|
|
|
|
+ TPACPI_Q_IBM('7', 'B', 0x1fb7), /* X60 (1) */
|
|
|
|
+
|
|
|
|
+ /* (1) - may have excess leds enabled on MSB */
|
|
|
|
+
|
|
|
|
+ /* Defaults (order matters, keep last, don't reorder!) */
|
|
|
|
+ { /* Lenovo */
|
|
|
|
+ .vendor = PCI_VENDOR_ID_LENOVO,
|
|
|
|
+ .bios = TPACPI_MATCH_ANY, .ec = TPACPI_MATCH_ANY,
|
|
|
|
+ .quirks = 0x1fffU,
|
|
|
|
+ },
|
|
|
|
+ { /* IBM ThinkPads with no EC version string */
|
|
|
|
+ .vendor = PCI_VENDOR_ID_IBM,
|
|
|
|
+ .bios = TPACPI_MATCH_ANY, .ec = TPACPI_MATCH_UNKNOWN,
|
|
|
|
+ .quirks = 0x00ffU,
|
|
|
|
+ },
|
|
|
|
+ { /* IBM ThinkPads with EC version string */
|
|
|
|
+ .vendor = PCI_VENDOR_ID_IBM,
|
|
|
|
+ .bios = TPACPI_MATCH_ANY, .ec = TPACPI_MATCH_ANY,
|
|
|
|
+ .quirks = 0x00bfU,
|
|
|
|
+ },
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+#undef TPACPI_LEDQ_IBM
|
|
|
|
+#undef TPACPI_LEDQ_LNV
|
|
|
|
+
|
|
static int __init led_init(struct ibm_init_struct *iibm)
|
|
static int __init led_init(struct ibm_init_struct *iibm)
|
|
{
|
|
{
|
|
unsigned int i;
|
|
unsigned int i;
|
|
int rc;
|
|
int rc;
|
|
|
|
+ unsigned long useful_leds;
|
|
|
|
|
|
vdbg_printk(TPACPI_DBG_INIT, "initializing LED subdriver\n");
|
|
vdbg_printk(TPACPI_DBG_INIT, "initializing LED subdriver\n");
|
|
|
|
|
|
@@ -5041,6 +5099,9 @@ static int __init led_init(struct ibm_init_struct *iibm)
|
|
vdbg_printk(TPACPI_DBG_INIT, "LED commands are %s, mode %d\n",
|
|
vdbg_printk(TPACPI_DBG_INIT, "LED commands are %s, mode %d\n",
|
|
str_supported(led_supported), led_supported);
|
|
str_supported(led_supported), led_supported);
|
|
|
|
|
|
|
|
+ if (led_supported == TPACPI_LED_NONE)
|
|
|
|
+ return 1;
|
|
|
|
+
|
|
tpacpi_leds = kzalloc(sizeof(*tpacpi_leds) * TPACPI_LED_NUMLEDS,
|
|
tpacpi_leds = kzalloc(sizeof(*tpacpi_leds) * TPACPI_LED_NUMLEDS,
|
|
GFP_KERNEL);
|
|
GFP_KERNEL);
|
|
if (!tpacpi_leds) {
|
|
if (!tpacpi_leds) {
|
|
@@ -5048,8 +5109,12 @@ static int __init led_init(struct ibm_init_struct *iibm)
|
|
return -ENOMEM;
|
|
return -ENOMEM;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ useful_leds = tpacpi_check_quirks(led_useful_qtable,
|
|
|
|
+ ARRAY_SIZE(led_useful_qtable));
|
|
|
|
+
|
|
for (i = 0; i < TPACPI_LED_NUMLEDS; i++) {
|
|
for (i = 0; i < TPACPI_LED_NUMLEDS; i++) {
|
|
- if (!tpacpi_is_led_restricted(i)) {
|
|
|
|
|
|
+ if (!tpacpi_is_led_restricted(i) &&
|
|
|
|
+ test_bit(i, &useful_leds)) {
|
|
rc = tpacpi_init_led(i);
|
|
rc = tpacpi_init_led(i);
|
|
if (rc < 0) {
|
|
if (rc < 0) {
|
|
led_exit();
|
|
led_exit();
|
|
@@ -5059,12 +5124,11 @@ static int __init led_init(struct ibm_init_struct *iibm)
|
|
}
|
|
}
|
|
|
|
|
|
#ifdef CONFIG_THINKPAD_ACPI_UNSAFE_LEDS
|
|
#ifdef CONFIG_THINKPAD_ACPI_UNSAFE_LEDS
|
|
- if (led_supported != TPACPI_LED_NONE)
|
|
|
|
- printk(TPACPI_NOTICE
|
|
|
|
- "warning: userspace override of important "
|
|
|
|
- "firmware LEDs is enabled\n");
|
|
|
|
|
|
+ printk(TPACPI_NOTICE
|
|
|
|
+ "warning: userspace override of important "
|
|
|
|
+ "firmware LEDs is enabled\n");
|
|
#endif
|
|
#endif
|
|
- return (led_supported != TPACPI_LED_NONE)? 0 : 1;
|
|
|
|
|
|
+ return 0;
|
|
}
|
|
}
|
|
|
|
|
|
#define str_led_status(s) \
|
|
#define str_led_status(s) \
|
|
@@ -5094,7 +5158,7 @@ static int led_read(char *p)
|
|
}
|
|
}
|
|
|
|
|
|
len += sprintf(p + len, "commands:\t"
|
|
len += sprintf(p + len, "commands:\t"
|
|
- "<led> on, <led> off, <led> blink (<led> is 0-7)\n");
|
|
|
|
|
|
+ "<led> on, <led> off, <led> blink (<led> is 0-15)\n");
|
|
|
|
|
|
return len;
|
|
return len;
|
|
}
|
|
}
|
|
@@ -5109,7 +5173,7 @@ static int led_write(char *buf)
|
|
return -ENODEV;
|
|
return -ENODEV;
|
|
|
|
|
|
while ((cmd = next_cmd(&buf))) {
|
|
while ((cmd = next_cmd(&buf))) {
|
|
- if (sscanf(cmd, "%d", &led) != 1 || led < 0 || led > 7)
|
|
|
|
|
|
+ if (sscanf(cmd, "%d", &led) != 1 || led < 0 || led > 15)
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
|
|
|
|
if (strstr(cmd, "off")) {
|
|
if (strstr(cmd, "off")) {
|