0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/kernel.h>
0011 #include <linux/module.h>
0012 #include <linux/init.h>
0013 #include <linux/types.h>
0014 #include <linux/input.h>
0015 #include <linux/acpi.h>
0016 #include <acpi/button.h>
0017
0018 #define SURFACE_PRO3_BUTTON_HID "MSHW0028"
0019 #define SURFACE_PRO4_BUTTON_HID "MSHW0040"
0020 #define SURFACE_BUTTON_OBJ_NAME "VGBI"
0021 #define SURFACE_BUTTON_DEVICE_NAME "Surface Pro 3/4 Buttons"
0022
0023 #define MSHW0040_DSM_REVISION 0x01
0024 #define MSHW0040_DSM_GET_OMPR 0x02
0025 static const guid_t MSHW0040_DSM_UUID =
0026 GUID_INIT(0x6fd05c69, 0xcde3, 0x49f4, 0x95, 0xed, 0xab, 0x16, 0x65,
0027 0x49, 0x80, 0x35);
0028
0029 #define SURFACE_BUTTON_NOTIFY_TABLET_MODE 0xc8
0030
0031 #define SURFACE_BUTTON_NOTIFY_PRESS_POWER 0xc6
0032 #define SURFACE_BUTTON_NOTIFY_RELEASE_POWER 0xc7
0033
0034 #define SURFACE_BUTTON_NOTIFY_PRESS_HOME 0xc4
0035 #define SURFACE_BUTTON_NOTIFY_RELEASE_HOME 0xc5
0036
0037 #define SURFACE_BUTTON_NOTIFY_PRESS_VOLUME_UP 0xc0
0038 #define SURFACE_BUTTON_NOTIFY_RELEASE_VOLUME_UP 0xc1
0039
0040 #define SURFACE_BUTTON_NOTIFY_PRESS_VOLUME_DOWN 0xc2
0041 #define SURFACE_BUTTON_NOTIFY_RELEASE_VOLUME_DOWN 0xc3
0042
0043 MODULE_AUTHOR("Chen Yu");
0044 MODULE_DESCRIPTION("Surface Pro3 Button Driver");
0045 MODULE_LICENSE("GPL v2");
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059 static const struct acpi_device_id surface_button_device_ids[] = {
0060 {SURFACE_PRO3_BUTTON_HID, 0},
0061 {SURFACE_PRO4_BUTTON_HID, 0},
0062 {"", 0},
0063 };
0064 MODULE_DEVICE_TABLE(acpi, surface_button_device_ids);
0065
0066 struct surface_button {
0067 unsigned int type;
0068 struct input_dev *input;
0069 char phys[32];
0070 unsigned long pushed;
0071 bool suspended;
0072 };
0073
0074 static void surface_button_notify(struct acpi_device *device, u32 event)
0075 {
0076 struct surface_button *button = acpi_driver_data(device);
0077 struct input_dev *input;
0078 int key_code = KEY_RESERVED;
0079 bool pressed = false;
0080
0081 switch (event) {
0082
0083 case SURFACE_BUTTON_NOTIFY_PRESS_POWER:
0084 pressed = true;
0085 fallthrough;
0086 case SURFACE_BUTTON_NOTIFY_RELEASE_POWER:
0087 key_code = KEY_POWER;
0088 break;
0089
0090 case SURFACE_BUTTON_NOTIFY_PRESS_HOME:
0091 pressed = true;
0092 fallthrough;
0093 case SURFACE_BUTTON_NOTIFY_RELEASE_HOME:
0094 key_code = KEY_LEFTMETA;
0095 break;
0096
0097 case SURFACE_BUTTON_NOTIFY_PRESS_VOLUME_UP:
0098 pressed = true;
0099 fallthrough;
0100 case SURFACE_BUTTON_NOTIFY_RELEASE_VOLUME_UP:
0101 key_code = KEY_VOLUMEUP;
0102 break;
0103
0104 case SURFACE_BUTTON_NOTIFY_PRESS_VOLUME_DOWN:
0105 pressed = true;
0106 fallthrough;
0107 case SURFACE_BUTTON_NOTIFY_RELEASE_VOLUME_DOWN:
0108 key_code = KEY_VOLUMEDOWN;
0109 break;
0110 case SURFACE_BUTTON_NOTIFY_TABLET_MODE:
0111 dev_warn_once(&device->dev, "Tablet mode is not supported\n");
0112 break;
0113 default:
0114 dev_info_ratelimited(&device->dev,
0115 "Unsupported event [0x%x]\n", event);
0116 break;
0117 }
0118 input = button->input;
0119 if (key_code == KEY_RESERVED)
0120 return;
0121 if (pressed)
0122 pm_wakeup_dev_event(&device->dev, 0, button->suspended);
0123 if (button->suspended)
0124 return;
0125 input_report_key(input, key_code, pressed?1:0);
0126 input_sync(input);
0127 }
0128
0129 #ifdef CONFIG_PM_SLEEP
0130 static int surface_button_suspend(struct device *dev)
0131 {
0132 struct acpi_device *device = to_acpi_device(dev);
0133 struct surface_button *button = acpi_driver_data(device);
0134
0135 button->suspended = true;
0136 return 0;
0137 }
0138
0139 static int surface_button_resume(struct device *dev)
0140 {
0141 struct acpi_device *device = to_acpi_device(dev);
0142 struct surface_button *button = acpi_driver_data(device);
0143
0144 button->suspended = false;
0145 return 0;
0146 }
0147 #endif
0148
0149
0150
0151
0152
0153
0154
0155
0156
0157 static bool surface_button_check_MSHW0040(struct acpi_device *dev)
0158 {
0159 acpi_handle handle = dev->handle;
0160 union acpi_object *result;
0161 u64 oem_platform_rev = 0;
0162
0163
0164 result = acpi_evaluate_dsm_typed(handle, &MSHW0040_DSM_UUID,
0165 MSHW0040_DSM_REVISION,
0166 MSHW0040_DSM_GET_OMPR,
0167 NULL, ACPI_TYPE_INTEGER);
0168
0169
0170
0171
0172
0173
0174
0175
0176 if (result) {
0177 oem_platform_rev = result->integer.value;
0178 ACPI_FREE(result);
0179 }
0180
0181 dev_dbg(&dev->dev, "OEM Platform Revision %llu\n", oem_platform_rev);
0182
0183 return oem_platform_rev == 0;
0184 }
0185
0186
0187 static int surface_button_add(struct acpi_device *device)
0188 {
0189 struct surface_button *button;
0190 struct input_dev *input;
0191 const char *hid = acpi_device_hid(device);
0192 char *name;
0193 int error;
0194
0195 if (strncmp(acpi_device_bid(device), SURFACE_BUTTON_OBJ_NAME,
0196 strlen(SURFACE_BUTTON_OBJ_NAME)))
0197 return -ENODEV;
0198
0199 if (!surface_button_check_MSHW0040(device))
0200 return -ENODEV;
0201
0202 button = kzalloc(sizeof(struct surface_button), GFP_KERNEL);
0203 if (!button)
0204 return -ENOMEM;
0205
0206 device->driver_data = button;
0207 button->input = input = input_allocate_device();
0208 if (!input) {
0209 error = -ENOMEM;
0210 goto err_free_button;
0211 }
0212
0213 name = acpi_device_name(device);
0214 strcpy(name, SURFACE_BUTTON_DEVICE_NAME);
0215 snprintf(button->phys, sizeof(button->phys), "%s/buttons", hid);
0216
0217 input->name = name;
0218 input->phys = button->phys;
0219 input->id.bustype = BUS_HOST;
0220 input->dev.parent = &device->dev;
0221 input_set_capability(input, EV_KEY, KEY_POWER);
0222 input_set_capability(input, EV_KEY, KEY_LEFTMETA);
0223 input_set_capability(input, EV_KEY, KEY_VOLUMEUP);
0224 input_set_capability(input, EV_KEY, KEY_VOLUMEDOWN);
0225
0226 error = input_register_device(input);
0227 if (error)
0228 goto err_free_input;
0229
0230 device_init_wakeup(&device->dev, true);
0231 dev_info(&device->dev,
0232 "%s [%s]\n", name, acpi_device_bid(device));
0233 return 0;
0234
0235 err_free_input:
0236 input_free_device(input);
0237 err_free_button:
0238 kfree(button);
0239 return error;
0240 }
0241
0242 static int surface_button_remove(struct acpi_device *device)
0243 {
0244 struct surface_button *button = acpi_driver_data(device);
0245
0246 input_unregister_device(button->input);
0247 kfree(button);
0248 return 0;
0249 }
0250
0251 static SIMPLE_DEV_PM_OPS(surface_button_pm,
0252 surface_button_suspend, surface_button_resume);
0253
0254 static struct acpi_driver surface_button_driver = {
0255 .name = "surface_pro3_button",
0256 .class = "SurfacePro3",
0257 .ids = surface_button_device_ids,
0258 .ops = {
0259 .add = surface_button_add,
0260 .remove = surface_button_remove,
0261 .notify = surface_button_notify,
0262 },
0263 .drv.pm = &surface_button_pm,
0264 };
0265
0266 module_acpi_driver(surface_button_driver);