HID: hid-asus: reset the backlight brightness level on resume
[linux-2.6-microblaze.git] / drivers / hid / hid-lenovo.c
index 44763c0..7c1b33b 100644 (file)
@@ -51,7 +51,12 @@ struct lenovo_drvdata {
        int select_right;
        int sensitivity;
        int press_speed;
-       u8 middlebutton_state; /* 0:Up, 1:Down (undecided), 2:Scrolling */
+       /* 0: Up
+        * 1: Down (undecided)
+        * 2: Scrolling
+        * 3: Patched firmware, disable workaround
+        */
+       u8 middlebutton_state;
        bool fn_lock;
 };
 
@@ -521,6 +526,19 @@ static void lenovo_features_set_cptkbd(struct hid_device *hdev)
        int ret;
        struct lenovo_drvdata *cptkbd_data = hid_get_drvdata(hdev);
 
+       /*
+        * Tell the keyboard a driver understands it, and turn F7, F9, F11 into
+        * regular keys
+        */
+       ret = lenovo_send_cmd_cptkbd(hdev, 0x01, 0x03);
+       if (ret)
+               hid_warn(hdev, "Failed to switch F7/9/11 mode: %d\n", ret);
+
+       /* Switch middle button to native mode */
+       ret = lenovo_send_cmd_cptkbd(hdev, 0x09, 0x01);
+       if (ret)
+               hid_warn(hdev, "Failed to switch middle button: %d\n", ret);
+
        ret = lenovo_send_cmd_cptkbd(hdev, 0x05, cptkbd_data->fn_lock);
        if (ret)
                hid_err(hdev, "Fn-lock setting failed: %d\n", ret);
@@ -668,31 +686,48 @@ static int lenovo_event_cptkbd(struct hid_device *hdev,
 {
        struct lenovo_drvdata *cptkbd_data = hid_get_drvdata(hdev);
 
-       /* "wheel" scroll events */
-       if (usage->type == EV_REL && (usage->code == REL_WHEEL ||
-                       usage->code == REL_HWHEEL)) {
-               /* Scroll events disable middle-click event */
-               cptkbd_data->middlebutton_state = 2;
-               return 0;
-       }
+       if (cptkbd_data->middlebutton_state != 3) {
+               /* REL_X and REL_Y events during middle button pressed
+                * are only possible on patched, bug-free firmware
+                * so set middlebutton_state to 3
+                * to never apply workaround anymore
+                */
+               if (cptkbd_data->middlebutton_state == 1 &&
+                               usage->type == EV_REL &&
+                               (usage->code == REL_X || usage->code == REL_Y)) {
+                       cptkbd_data->middlebutton_state = 3;
+                       /* send middle button press which was hold before */
+                       input_event(field->hidinput->input,
+                               EV_KEY, BTN_MIDDLE, 1);
+                       input_sync(field->hidinput->input);
+               }
+
+               /* "wheel" scroll events */
+               if (usage->type == EV_REL && (usage->code == REL_WHEEL ||
+                               usage->code == REL_HWHEEL)) {
+                       /* Scroll events disable middle-click event */
+                       cptkbd_data->middlebutton_state = 2;
+                       return 0;
+               }
 
-       /* Middle click events */
-       if (usage->type == EV_KEY && usage->code == BTN_MIDDLE) {
-               if (value == 1) {
-                       cptkbd_data->middlebutton_state = 1;
-               } else if (value == 0) {
-                       if (cptkbd_data->middlebutton_state == 1) {
-                               /* No scrolling inbetween, send middle-click */
-                               input_event(field->hidinput->input,
-                                       EV_KEY, BTN_MIDDLE, 1);
-                               input_sync(field->hidinput->input);
-                               input_event(field->hidinput->input,
-                                       EV_KEY, BTN_MIDDLE, 0);
-                               input_sync(field->hidinput->input);
+               /* Middle click events */
+               if (usage->type == EV_KEY && usage->code == BTN_MIDDLE) {
+                       if (value == 1) {
+                               cptkbd_data->middlebutton_state = 1;
+                       } else if (value == 0) {
+                               if (cptkbd_data->middlebutton_state == 1) {
+                                       /* No scrolling inbetween, send middle-click */
+                                       input_event(field->hidinput->input,
+                                               EV_KEY, BTN_MIDDLE, 1);
+                                       input_sync(field->hidinput->input);
+                                       input_event(field->hidinput->input,
+                                               EV_KEY, BTN_MIDDLE, 0);
+                                       input_sync(field->hidinput->input);
+                               }
+                               cptkbd_data->middlebutton_state = 0;
                        }
-                       cptkbd_data->middlebutton_state = 0;
+                       return 1;
                }
-               return 1;
        }
 
        if (usage->type == EV_KEY && usage->code == KEY_FN_ESC && value == 1) {
@@ -1126,22 +1161,6 @@ static int lenovo_probe_cptkbd(struct hid_device *hdev)
        }
        hid_set_drvdata(hdev, cptkbd_data);
 
-       /*
-        * Tell the keyboard a driver understands it, and turn F7, F9, F11 into
-        * regular keys (Compact only)
-        */
-       if (hdev->product == USB_DEVICE_ID_LENOVO_CUSBKBD ||
-           hdev->product == USB_DEVICE_ID_LENOVO_CBTKBD) {
-               ret = lenovo_send_cmd_cptkbd(hdev, 0x01, 0x03);
-               if (ret)
-                       hid_warn(hdev, "Failed to switch F7/9/11 mode: %d\n", ret);
-       }
-
-       /* Switch middle button to native mode */
-       ret = lenovo_send_cmd_cptkbd(hdev, 0x09, 0x01);
-       if (ret)
-               hid_warn(hdev, "Failed to switch middle button: %d\n", ret);
-
        /* Set keyboard settings to known state */
        cptkbd_data->middlebutton_state = 0;
        cptkbd_data->fn_lock = true;
@@ -1264,6 +1283,24 @@ err:
        return ret;
 }
 
+#ifdef CONFIG_PM
+static int lenovo_reset_resume(struct hid_device *hdev)
+{
+       switch (hdev->product) {
+       case USB_DEVICE_ID_LENOVO_CUSBKBD:
+       case USB_DEVICE_ID_LENOVO_TPIIUSBKBD:
+               if (hdev->type == HID_TYPE_USBMOUSE)
+                       lenovo_features_set_cptkbd(hdev);
+
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+#endif
+
 static void lenovo_remove_tpkbd(struct hid_device *hdev)
 {
        struct lenovo_drvdata *data_pointer = hid_get_drvdata(hdev);
@@ -1380,6 +1417,9 @@ static struct hid_driver lenovo_driver = {
        .raw_event = lenovo_raw_event,
        .event = lenovo_event,
        .report_fixup = lenovo_report_fixup,
+#ifdef CONFIG_PM
+       .reset_resume = lenovo_reset_resume,
+#endif
 };
 module_hid_driver(lenovo_driver);