Permalink
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
305 lines (300 sloc) 8.81 KB
From 553a274cb702e550b5ebae8aa483c16d595a2cf2 Mon Sep 17 00:00:00 2001
From: Carlos Roque <Carlos.Roque@bayphoto.com>
Date: Wed, 6 Apr 2016 17:26:14 -0500
Subject: [PATCH] patched camera and surface pro3 buttons
---
drivers/media/usb/uvc/uvc_driver.c | 17 ++-
drivers/platform/x86/Kconfig | 6 +
drivers/platform/x86/Makefile | 1 +
drivers/platform/x86/surface_button.c | 224 ++++++++++++++++++++++++++++++++++
4 files changed, 247 insertions(+), 1 deletion(-)
create mode 100644 drivers/platform/x86/surface_button.c
diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c
index fae81ef..b5fc470 100644
--- a/drivers/media/usb/uvc/uvc_driver.c
+++ b/drivers/media/usb/uvc/uvc_driver.c
@@ -2097,6 +2097,22 @@ MODULE_PARM_DESC(timeout, "Streaming control requests timeout");
* though they are compliant.
*/
static struct usb_device_id uvc_ids[] = {
+ /* Microsoft Surface Pro 3 Front */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x045e,
+ .idProduct = 0x07be,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 1 },
+ /* Microsoft Surface Pro 3 Rear */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x045e,
+ .idProduct = 0x07bf,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 1 },
/* LogiLink Wireless Webcam */
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
| USB_DEVICE_ID_MATCH_INT_INFO,
@@ -2594,4 +2610,3 @@ MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
MODULE_VERSION(DRIVER_VERSION);
-
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 6dc13e4..001091f 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -911,6 +911,12 @@ config PVPANIC
This driver provides support for the pvpanic device. pvpanic is
a paravirtualized device provided by QEMU; it lets a virtual machine
(guest) communicate panic events to the host.
+config SURFACE_BUTTON
+ tristate "Surface Pro Button Driver"
+ depends on ACPI
+ ---help---
+ This driver provides button support for the surface pro tablet, including
+ Power Button, Home Button, Volume Button.
config INTEL_PMC_IPC
tristate "Intel PMC IPC Driver"
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index dda95a9..4b6698a 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -60,3 +60,4 @@ obj-$(CONFIG_INTEL_SMARTCONNECT) += intel-smartconnect.o
obj-$(CONFIG_PVPANIC) += pvpanic.o
obj-$(CONFIG_ALIENWARE_WMI) += alienware-wmi.o
obj-$(CONFIG_INTEL_PMC_IPC) += intel_pmc_ipc.o
+obj-$(CONFIG_SURFACE_BUTTON) += surface_button.o
diff --git a/drivers/platform/x86/surface_button.c b/drivers/platform/x86/surface_button.c
new file mode 100644
index 0000000..0288b2b
--- /dev/null
+++ b/drivers/platform/x86/surface_button.c
@@ -0,0 +1,224 @@
+/*
+* Button support for surface.
+*
+* (C) Copyright 2015 Intel Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; version 2
+* of the License.
+*/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/input.h>
+#include <linux/acpi.h>
+#include <acpi/button.h>
+
+#define SURFACE_BUTTON_HID "MSHW0028"
+#define SURFACE_BUTTON_CLASS "button"
+#define SURFACE_BUTTON_SUB_CLASS "ec"
+#define SURFACE_BUTTON_DEVICE_NAME "EC"
+
+#define SURFACE_BUTTON_NOTIFY_PRESS_POWER 0xc6
+#define SURFACE_BUTTON_NOTIFY_RELEASE_POWER 0xc7
+
+#define SURFACE_BUTTON_NOTIFY_PRESS_HOME 0xc4
+#define SURFACE_BUTTON_NOTIFY_RELEASE_HOME 0xc5
+
+#define SURFACE_BUTTON_NOTIFY_PRESS_VOLUME_UP 0xc0
+#define SURFACE_BUTTON_NOTIFY_RELEASE_VOLUME_UP 0xc1
+
+#define SURFACE_BUTTON_NOTIFY_PRESS_VOLUME_DOWN 0xc2
+#define SURFACE_BUTTON_NOTIFY_RELEASE_VOLUME_DOWN 0xc3
+
+ACPI_MODULE_NAME("surface button");
+
+#define _COMPONENT ACPI_BUTTON_COMPONENT
+
+MODULE_AUTHOR("Chen Yu");
+MODULE_DESCRIPTION("Surface Button Driver");
+MODULE_LICENSE("GPL");
+
+/*
+* Power button, Home button, Volume button are handled by EC
+*/
+static const struct acpi_device_id surface_button_device_ids[] = {
+{SURFACE_BUTTON_HID, 0},
+ {"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, surface_button_device_ids);
+
+static int surface_button_add(struct acpi_device *device);
+static int surface_button_remove(struct acpi_device *device);
+static void surface_button_notify(struct acpi_device *device, u32 event);
+
+#ifdef CONFIG_PM_SLEEP
+static int surface_button_suspend(struct device *dev);
+static int surface_button_resume(struct device *dev);
+#else
+#define surface_button_suspend NULL
+#define surface_button_resume NULL
+#endif
+
+static SIMPLE_DEV_PM_OPS(surface_button_pm,
+ surface_button_suspend, surface_button_resume);
+
+static struct acpi_driver surface_button_driver = {
+ .name = "surface button",
+ .class = SURFACE_BUTTON_CLASS,
+ .ids = surface_button_device_ids,
+ .ops = {
+ .add = surface_button_add,
+ .remove = surface_button_remove,
+ .notify = surface_button_notify,
+ },
+ .drv.pm = &surface_button_pm,
+};
+
+struct surface_button {
+ unsigned int type;
+ struct input_dev *input;
+ char phys[32]; /* for input device */
+ unsigned long pushed;
+ bool suspended;
+};
+
+static void surface_button_notify(struct acpi_device *device, u32 event)
+{
+ struct surface_button *button = acpi_driver_data(device);
+ struct input_dev *input;
+ int key_code = KEY_RESERVED, pressed = 0;
+
+ switch (event) {
+ case SURFACE_BUTTON_NOTIFY_PRESS_POWER:
+ pressed = 1;
+ /*go through*/
+ case SURFACE_BUTTON_NOTIFY_RELEASE_POWER:
+ key_code = KEY_POWER;
+ break;
+ case SURFACE_BUTTON_NOTIFY_PRESS_HOME:
+ pressed = 1;
+ case SURFACE_BUTTON_NOTIFY_RELEASE_HOME:
+ key_code = KEY_LEFTMETA;
+ break;
+ case SURFACE_BUTTON_NOTIFY_PRESS_VOLUME_UP:
+ pressed = 1;
+ case SURFACE_BUTTON_NOTIFY_RELEASE_VOLUME_UP:
+ key_code = KEY_VOLUMEUP;
+ break;
+ case SURFACE_BUTTON_NOTIFY_PRESS_VOLUME_DOWN:
+ pressed = 1;
+ case SURFACE_BUTTON_NOTIFY_RELEASE_VOLUME_DOWN:
+ key_code = KEY_VOLUMEDOWN;
+ break;
+
+ default:
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Unsupported event [0x%x]\n", event));
+ break;
+ }
+
+ input = button->input;
+
+ if (KEY_RESERVED == key_code)
+ return;
+
+ if (pressed)
+ pm_wakeup_event(&device->dev, 0);
+
+ if (button->suspended)
+ return;
+
+ input_report_key(input, key_code, pressed);
+ input_sync(input);
+
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int surface_button_suspend(struct device *dev)
+{
+ struct acpi_device *device = to_acpi_device(dev);
+ struct surface_button *button = acpi_driver_data(device);
+
+ button->suspended = true;
+ return 0;
+}
+
+static int surface_button_resume(struct device *dev)
+{
+ struct acpi_device *device = to_acpi_device(dev);
+ struct surface_button *button = acpi_driver_data(device);
+
+ button->suspended = false;
+ return 0;
+}
+#endif
+
+static int surface_button_add(struct acpi_device *device)
+{
+ struct surface_button *button;
+ struct input_dev *input;
+ const char *hid = acpi_device_hid(device);
+ char *name, *class;
+ int error;
+
+ button = kzalloc(sizeof(struct surface_button), GFP_KERNEL);
+ if (!button)
+ return -ENOMEM;
+
+ device->driver_data = button;
+
+ button->input = input = input_allocate_device();
+ if (!input) {
+ error = -ENOMEM;
+ goto err_free_button;
+ }
+
+ name = acpi_device_name(device);
+ class = acpi_device_class(device);
+
+ strcpy(name, SURFACE_BUTTON_DEVICE_NAME);
+ sprintf(class, "%s/%s",
+ SURFACE_BUTTON_CLASS, SURFACE_BUTTON_SUB_CLASS);
+
+ snprintf(button->phys, sizeof(button->phys), "%s/button/input0", hid);
+
+ input->name = name;
+ input->phys = button->phys;
+ input->id.bustype = BUS_HOST;
+ input->dev.parent = &device->dev;
+
+ input_set_capability(input, EV_KEY, KEY_POWER);
+ input_set_capability(input, EV_KEY, KEY_LEFTMETA);
+ input_set_capability(input, EV_KEY, KEY_VOLUMEUP);
+ input_set_capability(input, EV_KEY, KEY_VOLUMEDOWN);
+
+
+ error = input_register_device(input);
+ if (error)
+ goto err_free_input;
+
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "%s [%s]\n", name, acpi_device_bid(device)));
+ return 0;
+
+err_free_input:
+ input_free_device(input);
+err_free_button:
+ kfree(button);
+ return error;
+}
+
+static int surface_button_remove(struct acpi_device *device)
+{
+ struct surface_button *button = acpi_driver_data(device);
+
+ input_unregister_device(button->input);
+ kfree(button);
+ return 0;
+}
+
+module_acpi_driver(surface_button_driver);
--
2.5.0