On 06/20/2012 03:23 AM, Maxim Mikityanskiy wrote: > From: Maxim Mikityanskiy <maxtram95@xxxxxxxxx> > > The patch adds support for Lenovo IdeaPad Z570 laptop. It makes all special > keys working, adds possibility to control fan like Windows does, controls > Touchpad Disabled LED, toggles touchpad state via psmouse with previous > patch and corrects touchpad behavior on resume from suspend. It is new, > modified version of patch. > > Signed-off-by: Maxim Mikityanskiy <maxtram95@xxxxxxxxx> > --- linux/drivers/platform/x86/ideapad-laptop.c.orig > +++ linux/drivers/platform/x86/ideapad-laptop.c > @@ -36,6 +36,7 @@ > #include <linux/fb.h> > #include <linux/debugfs.h> > #include <linux/seq_file.h> > +#include <linux/input/psmouse.h> let IDEAPAD_LAPTOP depends on MOUSE_PS2 in Kconfig. Other build will fail without MOUSE_PS2 selected. Of course I know the chance is rare. > > #define IDEAPAD_RFKILL_DEV_NUM (3) > > @@ -62,9 +63,12 @@ enum { > VPCCMD_W_CAMERA, > VPCCMD_R_3G, > VPCCMD_W_3G, > - VPCCMD_R_ODD, /* 0x21 */ > - VPCCMD_R_RF = 0x23, > - VPCCMD_W_RF, > + VPCCMD_R_ODD, > + VPCCMD_W_FAN, > + VPCCMD_R_RF, > + VPCCMD_W_RF, /* 0x24 */ > + VPCCMD_R_FAN = 0x2B, > + VPCCMD_R_SPECIAL_BUTTONS = 0x31, > VPCCMD_W_BL_POWER = 0x33, > }; > > @@ -363,8 +367,47 @@ static ssize_t store_ideapad_cam(struct > > static DEVICE_ATTR(camera_power, 0644, show_ideapad_cam, store_ideapad_cam); > > +static ssize_t show_ideapad_fan(struct device *dev, > + struct device_attribute *attr, > + char *buf) > +{ > + unsigned long result; > + > + if (read_ec_data(ideapad_handle, VPCCMD_R_FAN, &result)) > + return sprintf(buf, "-1\n"); > + return sprintf(buf, "%lu\n", result); > +} > + > +static ssize_t store_ideapad_fan(struct device *dev, > + struct device_attribute *attr, > + const char *buf, size_t count) > +{ > + int ret, state; > + > + if (!count) > + return 0; > + if (sscanf(buf, "%i", &state) != 1) > + return -EINVAL; > + /* WARNING: these fan states are not speed > + * so it isn't cooling_device interface > + * 0 = super silent mode > + * 1 = standard mode > + * 2 = dust cleaning > + * 4 = efficient thermal dissipation mode > + */ I think the file in Documentation is doing good, no need to comment here. > + if (state < 0 || state > 4 || state == 3) > + return -EINVAL; > + ret = write_ec_cmd(ideapad_handle, VPCCMD_W_FAN, state); > + if (ret < 0) > + return ret; return -EIO is better, write_ec_cmd only return -1. > + return count; > +} > + > +static DEVICE_ATTR(fan_mode, 0644, show_ideapad_fan, store_ideapad_fan); > + > static struct attribute *ideapad_attributes[] = { > &dev_attr_camera_power.attr, > + &dev_attr_fan_mode.attr, > NULL > }; > > @@ -379,6 +422,10 @@ static umode_t ideapad_is_visible(struct > if (attr == &dev_attr_camera_power.attr) > supported = test_bit(CFG_CAMERA_BIT, &(priv->cfg)); > else > + if (attr == &dev_attr_fan_mode.attr) { > + unsigned long value; > + supported = !read_ec_data(ideapad_handle, VPCCMD_R_FAN, &value); I will test this with my ideapads. > + } else > supported = true; > > return supported ? attr->mode : 0; > @@ -519,9 +566,15 @@ static void ideapad_platform_exit(struct > */ > static const struct key_entry ideapad_keymap[] = { > { KE_KEY, 6, { KEY_SWITCHVIDEOMODE } }, > + { KE_KEY, 7, { KEY_CAMERA } }, > + { KE_KEY, 11, { KEY_F16 } }, > { KE_KEY, 13, { KEY_WLAN } }, > { KE_KEY, 16, { KEY_PROG1 } }, > { KE_KEY, 17, { KEY_PROG2 } }, > + { KE_KEY, 64, { KEY_PROG3 } }, > + { KE_KEY, 65, { KEY_PROG4 } }, > + { KE_KEY, 66, { KEY_TOUCHPAD_OFF } }, > + { KE_KEY, 67, { KEY_TOUCHPAD_ON } }, > { KE_END, 0 }, > }; > > @@ -692,6 +745,25 @@ static const struct acpi_device_id ideap > }; > MODULE_DEVICE_TABLE(acpi, ideapad_device_ids); > > +static void ideapad_sync_touchpad_state(struct acpi_device *adevice) > +{ > + struct ideapad_private *priv = dev_get_drvdata(&adevice->dev); > + unsigned long value; > + > + /* Without reading from EC touchpad LED doesn't switch state */ > + if (!read_ec_data(adevice->handle, VPCCMD_R_TOUCHPAD, &value)) { > + /* Some IdeaPads don't really turn off touchpad - they only > + * switch the LED state. We (de)activate psmouse to turn > + * touchpad off and on. We send KEY_TOUCHPAD_OFF and > + * KEY_TOUCHPAD_ON to not to get out of sync with LED */ > + if (value) > + psmouse_enable(); > + else > + psmouse_disable(); > + ideapad_input_report(priv, value ? 67 : 66); > + } > +} > + > static int __devinit ideapad_acpi_add(struct acpi_device *adevice) > { > int ret, i; > @@ -728,6 +800,7 @@ static int __devinit ideapad_acpi_add(st > priv->rfk[i] = NULL; > } > ideapad_sync_rfk_state(priv); > + ideapad_sync_touchpad_state(adevice); > > if (!acpi_video_backlight_support()) { > ret = ideapad_backlight_init(priv); > @@ -767,6 +840,26 @@ static int __devexit ideapad_acpi_remove > return 0; > } > > +static void ideapad_check_special_buttons(struct ideapad_private *priv, > + unsigned long state) > +{ > + unsigned long bit; > + for (bit = 0; bit < 16; bit++) { > + if (test_bit(bit, &state)) { > + switch (bit) { > + case 6: > + /* Thermal Management button */ > + ideapad_input_report(priv, 65); > + break; > + case 1: > + /* OneKey Theater button */ > + ideapad_input_report(priv, 64); > + break; > + } > + } > + } > +} > + > static void ideapad_acpi_notify(struct acpi_device *adevice, u32 event) > { > struct ideapad_private *priv = dev_get_drvdata(&adevice->dev); > @@ -785,6 +878,9 @@ static void ideapad_acpi_notify(struct a > case 9: > ideapad_sync_rfk_state(priv); > break; > + case 5: > + ideapad_sync_touchpad_state(adevice); > + break; > case 4: > ideapad_backlight_notify_brightness(priv); > break; > @@ -794,6 +890,14 @@ static void ideapad_acpi_notify(struct a > case 2: > ideapad_backlight_notify_power(priv); > break; > + case 0: > + { > + unsigned long value; > + read_ec_data(handle, VPCCMD_R_SPECIAL_BUTTONS, > + &value); > + ideapad_check_special_buttons(priv, value); > + } > + break; > default: > ideapad_input_report(priv, vpc_bit); > } > @@ -801,6 +905,12 @@ static void ideapad_acpi_notify(struct a > } > } > > +static int ideapad_acpi_resume(struct acpi_device *adevice) > +{ > + ideapad_sync_touchpad_state(adevice); Good idea, I will see if we need ideapad_sync_rfk_state() also. > + return 0; > +} > + > static struct acpi_driver ideapad_acpi_driver = { > .name = "ideapad_acpi", > .class = "IdeaPad", > @@ -808,6 +918,7 @@ static struct acpi_driver ideapad_acpi_d > .ops.add = ideapad_acpi_add, > .ops.remove = ideapad_acpi_remove, > .ops.notify = ideapad_acpi_notify, > + .ops.resume = ideapad_acpi_resume, > .owner = THIS_MODULE, > }; > > --- linux/Documentation/ABI/testing/sysfs-platform-ideapad-laptop.orig > +++ linux/Documentation/ABI/testing/sysfs-platform-ideapad-laptop > @@ -5,4 +5,14 @@ Contact: "Ike Panhc <ike.pan@canonical.c > Description: > Control the power of camera module. 1 means on, 0 means off. > > - > +What: /sys/devices/platform/ideapad/fan_mode > +Date: June 2012 > +KernelVersion: 3.5 Shall be 3.6 > +Contact: "Maxim Mikityanskiy <maxtram95@xxxxxxxxx>" > +Description: > + Change fan mode > + There are four available modes: > + * 0 -> Super Silent Mode > + * 1 -> Standard Mode > + * 2 -> Dust Cleaning > + * 4 -> Efficient Thermal Dissipation Mode > > > -- > To unsubscribe from this list: send the line "unsubscribe platform-driver-x86" in > the body of a message to majordomo@xxxxxxxxxxxxxxx > More majordomo info at http://vger.kernel.org/majordomo-info.html > -- To unsubscribe from this list: send the line "unsubscribe linux-input" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html