From 6bbdaf3679e2c1be7eb1fcf8362c5e53741c468c Mon Sep 17 00:00:00 2001 From: qzed Date: Sun, 28 Oct 2018 13:52:45 +0100 Subject: [PATCH] add surface-acpi module Add surface-acpi module, restructure patches, fix whitespace errors. --- patches/4.18/0001-surface-acpi.patch | 2996 +++++++++++++++++ patches/4.18/0002-resume-delay.patch | 63 + .../{buttons.patch => 0003-buttons.patch} | 30 +- .../{cameras.patch => 0004-cameras.patch} | 35 +- patches/4.18/{ipts.patch => 0005-ipts.patch} | 173 +- patches/4.18/0006-hid.patch | 144 + ..._reader.patch => 0007-sdcard_reader.patch} | 12 + patches/4.18/0008-wifi.patch | 16 + patches/4.18/acpi.patch | 1374 -------- patches/4.18/keyboards_and_covers.patch | 555 --- patches/4.18/wifi.patch | 3 - 11 files changed, 3398 insertions(+), 2003 deletions(-) create mode 100644 patches/4.18/0001-surface-acpi.patch create mode 100644 patches/4.18/0002-resume-delay.patch rename patches/4.18/{buttons.patch => 0003-buttons.patch} (96%) rename patches/4.18/{cameras.patch => 0004-cameras.patch} (98%) rename patches/4.18/{ipts.patch => 0005-ipts.patch} (97%) create mode 100644 patches/4.18/0006-hid.patch rename patches/4.18/{sdcard_reader.patch => 0007-sdcard_reader.patch} (62%) create mode 100644 patches/4.18/0008-wifi.patch delete mode 100644 patches/4.18/acpi.patch delete mode 100644 patches/4.18/keyboards_and_covers.patch delete mode 100644 patches/4.18/wifi.patch diff --git a/patches/4.18/0001-surface-acpi.patch b/patches/4.18/0001-surface-acpi.patch new file mode 100644 index 000000000..08e744d32 --- /dev/null +++ b/patches/4.18/0001-surface-acpi.patch @@ -0,0 +1,2996 @@ +From f742e9a20013dbf17f0d7bacb69047f8b7f77894 Mon Sep 17 00:00:00 2001 +From: qzed +Date: Mon, 24 Dec 2018 13:31:00 +0100 +Subject: [PATCH 1/8] surface-acpi + +--- + drivers/acpi/acpica/dsopcode.c | 2 +- + drivers/acpi/acpica/exfield.c | 26 +- + drivers/platform/x86/Kconfig | 56 + + drivers/platform/x86/Makefile | 1 + + drivers/platform/x86/surface_acpi.c | 2705 +++++++++++++++++++++++++++ + drivers/tty/serdev/core.c | 90 +- + 6 files changed, 2861 insertions(+), 19 deletions(-) + create mode 100644 drivers/platform/x86/surface_acpi.c + +diff --git a/drivers/acpi/acpica/dsopcode.c b/drivers/acpi/acpica/dsopcode.c +index e9fb0bf3c8d2..cad7d94fa8d8 100644 +--- a/drivers/acpi/acpica/dsopcode.c ++++ b/drivers/acpi/acpica/dsopcode.c +@@ -123,7 +123,7 @@ acpi_ds_init_buffer_field(u16 aml_opcode, + + /* Offset is in bits, count is in bits */ + +- field_flags = AML_FIELD_ACCESS_BYTE; ++ field_flags = AML_FIELD_ACCESS_BUFFER; + bit_offset = offset; + bit_count = (u32) length_desc->integer.value; + +diff --git a/drivers/acpi/acpica/exfield.c b/drivers/acpi/acpica/exfield.c +index b272c329d45d..cf547883a993 100644 +--- a/drivers/acpi/acpica/exfield.c ++++ b/drivers/acpi/acpica/exfield.c +@@ -102,6 +102,7 @@ acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state, + void *buffer; + u32 function; + u16 accessor_type; ++ u8 field_flags; + + ACPI_FUNCTION_TRACE_PTR(ex_read_data_from_field, obj_desc); + +@@ -199,11 +200,16 @@ acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state, + * Note: Field.length is in bits. + */ + length = +- (acpi_size)ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->field.bit_length); ++ (acpi_size)ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->common_field.bit_length); ++ field_flags = obj_desc->common_field.field_flags; + +- if (length > acpi_gbl_integer_byte_width) { ++ if (length > acpi_gbl_integer_byte_width || ++ (field_flags & AML_FIELD_ACCESS_TYPE_MASK) == AML_FIELD_ACCESS_BUFFER) { + +- /* Field is too large for an Integer, create a Buffer instead */ ++ /* ++ * Field is either too large for an Integer, or a actually of type ++ * buffer, so create a Buffer. ++ */ + + buffer_desc = acpi_ut_create_buffer_object(length); + if (!buffer_desc) { +@@ -366,19 +372,7 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc, + } else if (obj_desc->field.region_obj->region.space_id == + ACPI_ADR_SPACE_GSBUS) { + accessor_type = obj_desc->field.attribute; +- length = +- acpi_ex_get_serial_access_length(accessor_type, +- obj_desc->field. +- access_length); +- +- /* +- * Add additional 2 bytes for the generic_serial_bus data buffer: +- * +- * Status; (Byte 0 of the data buffer) +- * Length; (Byte 1 of the data buffer) +- * Data[x-1]: (Bytes 2-x of the arbitrary length data buffer) +- */ +- length += 2; ++ length = source_desc->buffer.length; + function = ACPI_WRITE | (accessor_type << 16); + } else { /* IPMI */ + +diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig +index ac4d48830415..d36316429293 100644 +--- a/drivers/platform/x86/Kconfig ++++ b/drivers/platform/x86/Kconfig +@@ -573,6 +573,62 @@ config THINKPAD_ACPI_HOTKEY_POLL + If you are not sure, say Y here. The driver enables polling only if + it is strictly necessary to do so. + ++config SURFACE_ACPI ++ depends on ACPI ++ tristate "Microsoft Surface ACPI/Platform Drivers" ++ ---help--- ++ ACPI and platform drivers for Microsoft Surface devices. ++ ++config SURFACE_ACPI_SSH ++ bool "Surface Serial Hub Driver" ++ depends on SURFACE_ACPI ++ depends on X86_INTEL_LPSS ++ depends on SERIAL_8250_DW ++ depends on SERIAL_8250_DMA ++ depends on SERIAL_DEV_CTRL_TTYPORT ++ select CRC_CCITT ++ default y ++ ---help--- ++ Surface Serial Hub driver for 5th generation (or later) Microsoft ++ Surface devices. ++ ++ This is the base driver for the embedded serial controller found on ++ 5th generation (and later) Microsoft Surface devices (e.g. Book 2, ++ Laptop, Laptop 2, Pro 2017, Pro 6, ...). This driver itself only ++ provides access to the embedded controller and subsequent drivers are ++ required for the respective functionalities. ++ ++ If you have a 5th generation (or later) Microsoft Surface device, say ++ Y or M here. ++ ++config SURFACE_ACPI_SAN ++ bool "Surface ACPI Notify Driver" ++ depends on SURFACE_ACPI_SSH ++ default y ++ ---help--- ++ Surface ACPI Notify driver for 5th generation (or later) Microsoft ++ Surface devices. ++ ++ This driver enables basic ACPI events and requests, such as battery ++ status requests/events, thermal events, lid status, and possibly more, ++ which would otherwise not work on these devices. ++ ++ If you are not sure, say Y here. ++ ++config SURFACE_ACPI_VHF ++ bool "Surface Virtual HID Framework Driver" ++ depends on SURFACE_ACPI_SSH ++ depends on HID ++ default y ++ ---help--- ++ Surface Virtual HID Framework driver for 5th generation (or later) ++ Microsoft Surface devices. ++ ++ This driver provides support for the Microsoft Virtual HID framework, ++ which is required for the Surface Laptop (1 and newer) keyboard. ++ ++ If you are not sure, say Y here. ++ + config SENSORS_HDAPS + tristate "Thinkpad Hard Drive Active Protection System (hdaps)" + depends on INPUT +diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile +index 2ba6cb795338..4a76e3fca5d5 100644 +--- a/drivers/platform/x86/Makefile ++++ b/drivers/platform/x86/Makefile +@@ -35,6 +35,7 @@ obj-$(CONFIG_TC1100_WMI) += tc1100-wmi.o + obj-$(CONFIG_SONY_LAPTOP) += sony-laptop.o + obj-$(CONFIG_IDEAPAD_LAPTOP) += ideapad-laptop.o + obj-$(CONFIG_THINKPAD_ACPI) += thinkpad_acpi.o ++obj-$(CONFIG_SURFACE_ACPI) += surface_acpi.o + obj-$(CONFIG_SENSORS_HDAPS) += hdaps.o + obj-$(CONFIG_FUJITSU_LAPTOP) += fujitsu-laptop.o + obj-$(CONFIG_FUJITSU_TABLET) += fujitsu-tablet.o +diff --git a/drivers/platform/x86/surface_acpi.c b/drivers/platform/x86/surface_acpi.c +new file mode 100644 +index 000000000000..e7d3c21e6f42 +--- /dev/null ++++ b/drivers/platform/x86/surface_acpi.c +@@ -0,0 +1,2705 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++/************************************************************************* ++ * Surface Serial Hub driver (cross-driver interface) ++ */ ++ ++#ifdef CONFIG_SURFACE_ACPI_SSH ++ ++/* ++ * Maximum request payload size in bytes. ++ * Value based on ACPI (255 bytes minus header/status bytes). ++ */ ++#define SURFACEGEN5_MAX_RQST_PAYLOAD (255 - 10) ++ ++/* ++ * Maximum response payload size in bytes. ++ * Value based on ACPI (255 bytes minus header/status bytes). ++ */ ++#define SURFACEGEN5_MAX_RQST_RESPONSE (255 - 4) ++ ++#define SURFACEGEN5_RQID_EVENT_BITS 5 ++ ++#define SURFACEGEN5_EVENT_IMMEDIATE ((unsigned long) -1) ++ ++ ++struct surfacegen5_buf { ++ u8 cap; ++ u8 len; ++ u8 *data; ++}; ++ ++struct surfacegen5_rqst { ++ u8 tc; ++ u8 iid; ++ u8 cid; ++ u8 snc; ++ u8 cdl; ++ u8 *pld; ++}; ++ ++struct surfacegen5_event { ++ u16 rqid; ++ u8 tc; ++ u8 iid; ++ u8 cid; ++ u8 len; ++ u8 *pld; ++}; ++ ++ ++typedef int (*surfacegen5_ec_event_handler_fn)(struct surfacegen5_event *event, void *data); ++typedef unsigned long (*surfacegen5_ec_event_handler_delay)(struct surfacegen5_event *event, void *data); ++ ++struct device_link *surfacegen5_ec_consumer_add(struct device *consumer, u32 flags); ++int surfacegen5_ec_consumer_remove(struct device_link *link); ++ ++int surfacegen5_ec_rqst(struct surfacegen5_rqst *rqst, struct surfacegen5_buf *result); ++ ++int surfacegen5_ec_enable_event_source(u8 tc, u8 unknown, u16 rqid); ++int surfacegen5_ec_disable_event_source(u8 tc, u8 unknown, u16 rqid); ++int surfacegen5_ec_remove_event_handler(u16 rqid); ++int surfacegen5_ec_set_event_handler(u16 rqid, surfacegen5_ec_event_handler_fn fn, void *data); ++int surfacegen5_ec_set_delayed_event_handler(u16 rqid, ++ surfacegen5_ec_event_handler_fn fn, ++ surfacegen5_ec_event_handler_delay delay, ++ void *data); ++ ++#endif /* CONFIG_SURFACE_ACPI_SSH */ ++ ++ ++/************************************************************************* ++ * Surface Serial Hub driver (private implementation) ++ */ ++ ++#ifdef CONFIG_SURFACE_ACPI_SSH ++ ++#define SG5_RQST_TAG_FULL "surfacegen5_ec_rqst: " ++#define SG5_RQST_TAG "rqst: " ++#define SG5_EVENT_TAG "event: " ++#define SG5_RECV_TAG "recv: " ++ ++#define SG5_SUPPORTED_FLOW_CONTROL_MASK (~((u8) ACPI_UART_FLOW_CONTROL_HW)) ++ ++#define SG5_BYTELEN_SYNC 2 ++#define SG5_BYTELEN_TERM 2 ++#define SG5_BYTELEN_CRC 2 ++#define SG5_BYTELEN_CTRL 4 // command-header, ACK, or RETRY ++#define SG5_BYTELEN_CMDFRAME 8 // without payload ++ ++#define SG5_MAX_WRITE ( \ ++ SG5_BYTELEN_SYNC \ ++ + SG5_BYTELEN_CTRL \ ++ + SG5_BYTELEN_CRC \ ++ + SG5_BYTELEN_CMDFRAME \ ++ + SURFACEGEN5_MAX_RQST_PAYLOAD \ ++ + SG5_BYTELEN_CRC \ ++) ++ ++#define SG5_MSG_LEN_CTRL ( \ ++ SG5_BYTELEN_SYNC \ ++ + SG5_BYTELEN_CTRL \ ++ + SG5_BYTELEN_CRC \ ++ + SG5_BYTELEN_TERM \ ++) ++ ++#define SG5_MSG_LEN_CMD_BASE ( \ ++ SG5_BYTELEN_SYNC \ ++ + SG5_BYTELEN_CTRL \ ++ + SG5_BYTELEN_CRC \ ++ + SG5_BYTELEN_CRC \ ++) // without payload and command-frame ++ ++#define SG5_WRITE_TIMEOUT msecs_to_jiffies(1000) ++#define SG5_READ_TIMEOUT msecs_to_jiffies(1000) ++#define SG5_NUM_RETRY 3 ++ ++#define SG5_WRITE_BUF_LEN SG5_MAX_WRITE ++#define SG5_READ_BUF_LEN 512 // must be power of 2 ++#define SG5_EVAL_BUF_LEN SG5_MAX_WRITE // also works for reading ++ ++#define SG5_FRAME_TYPE_CMD 0x80 ++#define SG5_FRAME_TYPE_ACK 0x40 ++#define SG5_FRAME_TYPE_RETRY 0x04 ++ ++#define SG5_FRAME_OFFS_CTRL SG5_BYTELEN_SYNC ++#define SG5_FRAME_OFFS_CTRL_CRC (SG5_FRAME_OFFS_CTRL + SG5_BYTELEN_CTRL) ++#define SG5_FRAME_OFFS_TERM (SG5_FRAME_OFFS_CTRL_CRC + SG5_BYTELEN_CRC) ++#define SG5_FRAME_OFFS_CMD SG5_FRAME_OFFS_TERM // either TERM or CMD ++#define SG5_FRAME_OFFS_CMD_PLD (SG5_FRAME_OFFS_CMD + SG5_BYTELEN_CMDFRAME) ++ ++/* ++ * A note on Request IDs (RQIDs): ++ * 0x0000 is not a valid RQID ++ * 0x0001 is valid, but reserved for Surface Laptop keyboard events ++ */ ++#define SG5_NUM_EVENT_TYPES ((1 << SURFACEGEN5_RQID_EVENT_BITS) - 1) ++ ++/* ++ * Sync: aa 55 ++ * Terminate: ff ff ++ * ++ * Request Message: sync cmd-hdr crc(cmd-hdr) cmd-rqst-frame crc(cmd-rqst-frame) ++ * Ack Message: sync ack crc(ack) terminate ++ * Retry Message: sync retry crc(retry) terminate ++ * Response Message: sync cmd-hdr crc(cmd-hdr) cmd-resp-frame crc(cmd-resp-frame) ++ * ++ * Command Header: 80 LEN 00 SEQ ++ * Ack: 40 00 00 SEQ ++ * Retry: 04 00 00 00 ++ * Command Request Frame: 80 RTC 01 00 RIID RQID RCID PLD ++ * Command Response Frame: 80 RTC 00 01 RIID RQID RCID PLD ++ */ ++ ++struct surfacegen5_frame_ctrl { ++ u8 type; ++ u8 len; // without crc ++ u8 pad; ++ u8 seq; ++} __packed; ++ ++struct surfacegen5_frame_cmd { ++ u8 type; ++ u8 tc; ++ u8 unknown1; ++ u8 unknown2; ++ u8 iid; ++ u8 rqid_lo; // id for request/response matching (low byte) ++ u8 rqid_hi; // id for request/response matching (high byte) ++ u8 cid; ++} __packed; ++ ++ ++enum surfacegen5_ec_state { ++ SG5_EC_UNINITIALIZED, ++ SG5_EC_INITIALIZED, ++ SG5_EC_SUSPENDED, ++}; ++ ++struct surfacegen5_ec_counters { ++ u8 seq; // control sequence id ++ u16 rqid; // id for request/response matching ++}; ++ ++struct surfacegen5_ec_writer { ++ u8 *data; ++ u8 *ptr; ++} __packed; ++ ++enum surfacegen5_ec_receiver_state { ++ SG5_RCV_DISCARD, ++ SG5_RCV_CONTROL, ++ SG5_RCV_COMMAND, ++}; ++ ++struct surfacegen5_ec_receiver { ++ spinlock_t lock; ++ enum surfacegen5_ec_receiver_state state; ++ struct completion signal; ++ struct kfifo fifo; ++ struct { ++ bool pld; ++ u8 seq; ++ u16 rqid; ++ } expect; ++ struct { ++ u16 cap; ++ u16 len; ++ u8 *ptr; ++ } eval_buf; ++}; ++ ++struct surfacegen5_ec_event_handler { ++ surfacegen5_ec_event_handler_fn handler; ++ surfacegen5_ec_event_handler_delay delay; ++ void *data; ++}; ++ ++struct surfacegen5_ec_events { ++ spinlock_t lock; ++ struct workqueue_struct *queue_ack; ++ struct workqueue_struct *queue_evt; ++ struct surfacegen5_ec_event_handler handler[SG5_NUM_EVENT_TYPES]; ++}; ++ ++struct surfacegen5_ec { ++ struct mutex lock; ++ enum surfacegen5_ec_state state; ++ struct serdev_device *serdev; ++ struct surfacegen5_ec_counters counter; ++ struct surfacegen5_ec_writer writer; ++ struct surfacegen5_ec_receiver receiver; ++ struct surfacegen5_ec_events events; ++}; ++ ++struct surfacegen5_fifo_packet { ++ u8 type; // packet type (ACK/RETRY/CMD) ++ u8 seq; ++ u8 len; ++}; ++ ++struct surfacegen5_event_work { ++ refcount_t refcount; ++ struct surfacegen5_ec *ec; ++ struct work_struct work_ack; ++ struct delayed_work work_evt; ++ struct surfacegen5_event event; ++ u8 seq; ++}; ++ ++ ++static struct surfacegen5_ec surfacegen5_ec = { ++ .lock = __MUTEX_INITIALIZER(surfacegen5_ec.lock), ++ .state = SG5_EC_UNINITIALIZED, ++ .serdev = NULL, ++ .counter = { ++ .seq = 0, ++ .rqid = 0, ++ }, ++ .writer = { ++ .data = NULL, ++ .ptr = NULL, ++ }, ++ .receiver = { ++ .lock = __SPIN_LOCK_UNLOCKED(), ++ .state = SG5_RCV_DISCARD, ++ .expect = {}, ++ }, ++ .events = { ++ .lock = __SPIN_LOCK_UNLOCKED(), ++ .handler = {}, ++ } ++}; ++ ++ ++static int surfacegen5_ec_rqst_unlocked(struct surfacegen5_ec *ec, ++ struct surfacegen5_rqst *rqst, ++ struct surfacegen5_buf *result); ++ ++ ++inline static struct surfacegen5_ec *surfacegen5_ec_acquire(void) ++{ ++ struct surfacegen5_ec *ec = &surfacegen5_ec; ++ ++ mutex_lock(&ec->lock); ++ return ec; ++} ++ ++inline static void surfacegen5_ec_release(struct surfacegen5_ec *ec) ++{ ++ mutex_unlock(&ec->lock); ++} ++ ++inline static struct surfacegen5_ec *surfacegen5_ec_acquire_init(void) ++{ ++ struct surfacegen5_ec *ec = surfacegen5_ec_acquire(); ++ ++ if (ec->state == SG5_EC_UNINITIALIZED) { ++ surfacegen5_ec_release(ec); ++ return NULL; ++ } ++ ++ return ec; ++} ++ ++struct device_link *surfacegen5_ec_consumer_add(struct device *consumer, u32 flags) ++{ ++ struct surfacegen5_ec *ec; ++ struct device_link *link; ++ ++ ec = surfacegen5_ec_acquire_init(); ++ if (!ec) { ++ return ERR_PTR(-ENXIO); ++ } ++ ++ link = device_link_add(consumer, &ec->serdev->dev, flags); ++ ++ surfacegen5_ec_release(ec); ++ return link; ++} ++ ++int surfacegen5_ec_consumer_remove(struct device_link *link) ++{ ++ struct surfacegen5_ec *ec = surfacegen5_ec_acquire_init(); ++ if (!ec) { ++ return -ENXIO; ++ } ++ ++ device_link_del(link); ++ ++ surfacegen5_ec_release(ec); ++ return 0; ++} ++ ++ ++inline static u16 surfacegen5_rqid_to_rqst(u16 rqid) { ++ return rqid << SURFACEGEN5_RQID_EVENT_BITS; ++} ++ ++inline static bool surfacegen5_rqid_is_event(u16 rqid) { ++ const u16 mask = (1 << SURFACEGEN5_RQID_EVENT_BITS) - 1; ++ return rqid != 0 && (rqid | mask) == mask; ++} ++ ++int surfacegen5_ec_enable_event_source(u8 tc, u8 unknown, u16 rqid) ++{ ++ struct surfacegen5_ec *ec; ++ ++ u8 pld[4] = { tc, unknown, rqid & 0xff, rqid >> 8 }; ++ u8 buf[1] = { 0x00 }; ++ ++ struct surfacegen5_rqst rqst = { ++ .tc = 0x01, ++ .iid = 0x00, ++ .cid = 0x0b, ++ .snc = 0x01, ++ .cdl = 0x04, ++ .pld = pld, ++ }; ++ ++ struct surfacegen5_buf result = { ++ result.cap = ARRAY_SIZE(buf), ++ result.len = 0, ++ result.data = buf, ++ }; ++ ++ int status; ++ ++ // only allow RQIDs that lie within event spectrum ++ if (!surfacegen5_rqid_is_event(rqid)) { ++ return -EINVAL; ++ } ++ ++ ec = surfacegen5_ec_acquire_init(); ++ if (!ec) { ++ printk(KERN_WARNING SG5_RQST_TAG_FULL "embedded controller is uninitialized\n"); ++ return -ENXIO; ++ } ++ ++ if (ec->state == SG5_EC_SUSPENDED) { ++ dev_warn(&ec->serdev->dev, SG5_RQST_TAG "embedded controller is suspended\n"); ++ ++ surfacegen5_ec_release(ec); ++ return -EPERM; ++ } ++ ++ status = surfacegen5_ec_rqst_unlocked(ec, &rqst, &result); ++ ++ if (buf[0] != 0x00) { ++ dev_warn(&ec->serdev->dev, ++ "unexpected result while enabling event source: 0x%02x\n", ++ buf[0]); ++ } ++ ++ surfacegen5_ec_release(ec); ++ return status; ++ ++} ++ ++int surfacegen5_ec_disable_event_source(u8 tc, u8 unknown, u16 rqid) ++{ ++ struct surfacegen5_ec *ec; ++ ++ u8 pld[4] = { tc, unknown, rqid & 0xff, rqid >> 8 }; ++ u8 buf[1] = { 0x00 }; ++ ++ struct surfacegen5_rqst rqst = { ++ .tc = 0x01, ++ .iid = 0x00, ++ .cid = 0x0c, ++ .snc = 0x01, ++ .cdl = 0x04, ++ .pld = pld, ++ }; ++ ++ struct surfacegen5_buf result = { ++ result.cap = ARRAY_SIZE(buf), ++ result.len = 0, ++ result.data = buf, ++ }; ++ ++ int status; ++ ++ // only allow RQIDs that lie within event spectrum ++ if (!surfacegen5_rqid_is_event(rqid)) { ++ return -EINVAL; ++ } ++ ++ ec = surfacegen5_ec_acquire_init(); ++ if (!ec) { ++ printk(KERN_WARNING SG5_RQST_TAG_FULL "embedded controller is uninitialized\n"); ++ return -ENXIO; ++ } ++ ++ if (ec->state == SG5_EC_SUSPENDED) { ++ dev_warn(&ec->serdev->dev, SG5_RQST_TAG "embedded controller is suspended\n"); ++ ++ surfacegen5_ec_release(ec); ++ return -EPERM; ++ } ++ ++ status = surfacegen5_ec_rqst_unlocked(ec, &rqst, &result); ++ ++ if (buf[0] != 0x00) { ++ dev_warn(&ec->serdev->dev, ++ "unexpected result while disabling event source: 0x%02x\n", ++ buf[0]); ++ } ++ ++ surfacegen5_ec_release(ec); ++ return status; ++} ++ ++int surfacegen5_ec_set_delayed_event_handler( ++ u16 rqid, surfacegen5_ec_event_handler_fn fn, ++ surfacegen5_ec_event_handler_delay delay, ++ void *data) ++{ ++ struct surfacegen5_ec *ec; ++ unsigned long flags; ++ ++ if (!surfacegen5_rqid_is_event(rqid)) { ++ return -EINVAL; ++ } ++ ++ ec = surfacegen5_ec_acquire_init(); ++ if (!ec) { ++ return -ENXIO; ++ } ++ ++ spin_lock_irqsave(&ec->events.lock, flags); ++ ++ // 0 is not a valid event RQID ++ ec->events.handler[rqid - 1].handler = fn; ++ ec->events.handler[rqid - 1].delay = delay; ++ ec->events.handler[rqid - 1].data = data; ++ ++ spin_unlock_irqrestore(&ec->events.lock, flags); ++ surfacegen5_ec_release(ec); ++ ++ return 0; ++} ++ ++int surfacegen5_ec_set_event_handler( ++ u16 rqid, surfacegen5_ec_event_handler_fn fn, void *data) ++{ ++ return surfacegen5_ec_set_delayed_event_handler(rqid, fn, NULL, data); ++} ++ ++int surfacegen5_ec_remove_event_handler(u16 rqid) ++{ ++ struct surfacegen5_ec *ec; ++ unsigned long flags; ++ ++ if (!surfacegen5_rqid_is_event(rqid)) { ++ return -EINVAL; ++ } ++ ++ ec = surfacegen5_ec_acquire_init(); ++ if (!ec) { ++ return -ENXIO; ++ } ++ ++ spin_lock_irqsave(&ec->events.lock, flags); ++ ++ // 0 is not a valid event RQID ++ ec->events.handler[rqid - 1].handler = NULL; ++ ec->events.handler[rqid - 1].delay = NULL; ++ ec->events.handler[rqid - 1].data = NULL; ++ ++ spin_unlock_irqrestore(&ec->events.lock, flags); ++ surfacegen5_ec_release(ec); ++ ++ /* ++ * Make sure that the handler is not in use any more after we've ++ * removed it. ++ */ ++ flush_workqueue(ec->events.queue_evt); ++ ++ return 0; ++} ++ ++ ++inline static u16 surfacegen5_ssh_crc(const u8 *buf, size_t size) ++{ ++ return crc_ccitt_false(0xffff, buf, size); ++} ++ ++inline static void surfacegen5_ssh_write_u16(struct surfacegen5_ec_writer *writer, u16 in) ++{ ++ put_unaligned_le16(in, writer->ptr); ++ writer->ptr += 2; ++} ++ ++inline static void surfacegen5_ssh_write_crc(struct surfacegen5_ec_writer *writer, ++ const u8 *buf, size_t size) ++{ ++ surfacegen5_ssh_write_u16(writer, surfacegen5_ssh_crc(buf, size)); ++} ++ ++inline static void surfacegen5_ssh_write_syn(struct surfacegen5_ec_writer *writer) ++{ ++ u8 *w = writer->ptr; ++ ++ *w++ = 0xaa; ++ *w++ = 0x55; ++ ++ writer->ptr = w; ++} ++ ++inline static void surfacegen5_ssh_write_ter(struct surfacegen5_ec_writer *writer) ++{ ++ u8 *w = writer->ptr; ++ ++ *w++ = 0xff; ++ *w++ = 0xff; ++ ++ writer->ptr = w; ++} ++ ++inline static void surfacegen5_ssh_write_buf(struct surfacegen5_ec_writer *writer, ++ u8 *in, size_t len) ++{ ++ writer->ptr = memcpy(writer->ptr, in, len) + len; ++} ++ ++inline static void surfacegen5_ssh_write_hdr(struct surfacegen5_ec_writer *writer, ++ struct surfacegen5_rqst *rqst, ++ struct surfacegen5_ec *ec) ++{ ++ struct surfacegen5_frame_ctrl *hdr = (struct surfacegen5_frame_ctrl *)writer->ptr; ++ u8 *begin = writer->ptr; ++ ++ hdr->type = SG5_FRAME_TYPE_CMD; ++ hdr->len = SG5_BYTELEN_CMDFRAME + rqst->cdl; // without CRC ++ hdr->pad = 0x00; ++ hdr->seq = ec->counter.seq; ++ ++ writer->ptr += sizeof(*hdr); ++ ++ surfacegen5_ssh_write_crc(writer, begin, writer->ptr - begin); ++} ++ ++inline static void surfacegen5_ssh_write_cmd(struct surfacegen5_ec_writer *writer, ++ struct surfacegen5_rqst *rqst, ++ struct surfacegen5_ec *ec) ++{ ++ struct surfacegen5_frame_cmd *cmd = (struct surfacegen5_frame_cmd *)writer->ptr; ++ u8 *begin = writer->ptr; ++ ++ u16 rqid = surfacegen5_rqid_to_rqst(ec->counter.rqid); ++ u8 rqid_lo = rqid & 0xFF; ++ u8 rqid_hi = rqid >> 8; ++ ++ cmd->type = SG5_FRAME_TYPE_CMD; ++ cmd->tc = rqst->tc; ++ cmd->unknown1 = 0x01; ++ cmd->unknown2 = 0x00; ++ cmd->iid = rqst->iid; ++ cmd->rqid_lo = rqid_lo; ++ cmd->rqid_hi = rqid_hi; ++ cmd->cid = rqst->cid; ++ ++ writer->ptr += sizeof(*cmd); ++ ++ surfacegen5_ssh_write_buf(writer, rqst->pld, rqst->cdl); ++ surfacegen5_ssh_write_crc(writer, begin, writer->ptr - begin); ++} ++ ++inline static void surfacegen5_ssh_write_ack(struct surfacegen5_ec_writer *writer, u8 seq) ++{ ++ struct surfacegen5_frame_ctrl *ack = (struct surfacegen5_frame_ctrl *)writer->ptr; ++ u8 *begin = writer->ptr; ++ ++ ack->type = SG5_FRAME_TYPE_ACK; ++ ack->len = 0x00; ++ ack->pad = 0x00; ++ ack->seq = seq; ++ ++ writer->ptr += sizeof(*ack); ++ ++ surfacegen5_ssh_write_crc(writer, begin, writer->ptr - begin); ++} ++ ++inline static void surfacegen5_ssh_writer_reset(struct surfacegen5_ec_writer *writer) ++{ ++ writer->ptr = writer->data; ++} ++ ++inline static int surfacegen5_ssh_writer_flush(struct surfacegen5_ec *ec) ++{ ++ struct surfacegen5_ec_writer *writer = &ec->writer; ++ struct serdev_device *serdev = ec->serdev; ++ ++ size_t len = writer->ptr - writer->data; ++ ++ dev_dbg(&ec->serdev->dev, "sending message\n"); ++ print_hex_dump_debug("send: ", DUMP_PREFIX_OFFSET, 16, 1, ++ writer->data, writer->ptr - writer->data, false); ++ ++ return serdev_device_write(serdev, writer->data, len, SG5_WRITE_TIMEOUT); ++} ++ ++inline static void surfacegen5_ssh_write_msg_cmd(struct surfacegen5_ec *ec, ++ struct surfacegen5_rqst *rqst) ++{ ++ surfacegen5_ssh_writer_reset(&ec->writer); ++ surfacegen5_ssh_write_syn(&ec->writer); ++ surfacegen5_ssh_write_hdr(&ec->writer, rqst, ec); ++ surfacegen5_ssh_write_cmd(&ec->writer, rqst, ec); ++} ++ ++inline static void surfacegen5_ssh_write_msg_ack(struct surfacegen5_ec *ec, u8 seq) ++{ ++ surfacegen5_ssh_writer_reset(&ec->writer); ++ surfacegen5_ssh_write_syn(&ec->writer); ++ surfacegen5_ssh_write_ack(&ec->writer, seq); ++ surfacegen5_ssh_write_ter(&ec->writer); ++} ++ ++inline static void surfacegen5_ssh_receiver_restart(struct surfacegen5_ec *ec, ++ struct surfacegen5_rqst *rqst) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&ec->receiver.lock, flags); ++ reinit_completion(&ec->receiver.signal); ++ ec->receiver.state = SG5_RCV_CONTROL; ++ ec->receiver.expect.pld = rqst->snc; ++ ec->receiver.expect.seq = ec->counter.seq; ++ ec->receiver.expect.rqid = surfacegen5_rqid_to_rqst(ec->counter.rqid); ++ ec->receiver.eval_buf.len = 0; ++ spin_unlock_irqrestore(&ec->receiver.lock, flags); ++} ++ ++inline static void surfacegen5_ssh_receiver_discard(struct surfacegen5_ec *ec) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&ec->receiver.lock, flags); ++ ec->receiver.state = SG5_RCV_DISCARD; ++ ec->receiver.eval_buf.len = 0; ++ kfifo_reset(&ec->receiver.fifo); ++ spin_unlock_irqrestore(&ec->receiver.lock, flags); ++} ++ ++static int surfacegen5_ec_rqst_unlocked(struct surfacegen5_ec *ec, ++ struct surfacegen5_rqst *rqst, ++ struct surfacegen5_buf *result) ++{ ++ struct device *dev = &ec->serdev->dev; ++ struct surfacegen5_fifo_packet packet = {}; ++ int status; ++ int try; ++ unsigned int rem; ++ ++ if (rqst->cdl > SURFACEGEN5_MAX_RQST_PAYLOAD) { ++ dev_err(dev, SG5_RQST_TAG "request payload too large\n"); ++ return -EINVAL; ++ } ++ ++ // write command in buffer, we may need it multiple times ++ surfacegen5_ssh_write_msg_cmd(ec, rqst); ++ surfacegen5_ssh_receiver_restart(ec, rqst); ++ ++ // send command, try to get an ack response ++ for (try = 0; try < SG5_NUM_RETRY; try++) { ++ status = surfacegen5_ssh_writer_flush(ec); ++ if (status) { ++ goto ec_rqst_out; ++ } ++ ++ rem = wait_for_completion_timeout(&ec->receiver.signal, SG5_READ_TIMEOUT); ++ if (rem) { ++ kfifo_out(&ec->receiver.fifo, &packet, sizeof(packet)); ++ ++ if (packet.type == SG5_FRAME_TYPE_ACK) { ++ break; ++ } ++ } ++ } ++ ++ // check if we ran out of tries? ++ if (try >= SG5_NUM_RETRY) { ++ dev_err(dev, SG5_RQST_TAG "communication failed %d times, giving up\n", try); ++ status = -EIO; ++ goto ec_rqst_out; ++ } ++ ++ ec->counter.seq += 1; ++ ec->counter.rqid += 1; ++ ++ // get command response/payload ++ if (rqst->snc && result) { ++ rem = wait_for_completion_timeout(&ec->receiver.signal, SG5_READ_TIMEOUT); ++ if (rem) { ++ kfifo_out(&ec->receiver.fifo, &packet, sizeof(packet)); ++ ++ if (result->cap < packet.len) { ++ status = -EINVAL; ++ goto ec_rqst_out; ++ } ++ ++ kfifo_out(&ec->receiver.fifo, result->data, packet.len); ++ result->len = packet.len; ++ } else { ++ dev_err(dev, SG5_RQST_TAG "communication timed out\n"); ++ status = -EIO; ++ goto ec_rqst_out; ++ } ++ ++ // send ACK ++ surfacegen5_ssh_write_msg_ack(ec, packet.seq); ++ status = surfacegen5_ssh_writer_flush(ec); ++ if (status) { ++ goto ec_rqst_out; ++ } ++ } ++ ++ec_rqst_out: ++ surfacegen5_ssh_receiver_discard(ec); ++ return status; ++} ++ ++int surfacegen5_ec_rqst(struct surfacegen5_rqst *rqst, struct surfacegen5_buf *result) ++{ ++ struct surfacegen5_ec *ec; ++ int status; ++ ++ ec = surfacegen5_ec_acquire_init(); ++ if (!ec) { ++ printk(KERN_WARNING SG5_RQST_TAG_FULL "embedded controller is uninitialized\n"); ++ return -ENXIO; ++ } ++ ++ if (ec->state == SG5_EC_SUSPENDED) { ++ dev_warn(&ec->serdev->dev, SG5_RQST_TAG "embedded controller is suspended\n"); ++ ++ surfacegen5_ec_release(ec); ++ return -EPERM; ++ } ++ ++ status = surfacegen5_ec_rqst_unlocked(ec, rqst, result); ++ ++ surfacegen5_ec_release(ec); ++ return status; ++} ++ ++ ++static int surfacegen5_ssh_ec_resume(struct surfacegen5_ec *ec) ++{ ++ u8 buf[1] = { 0x00 }; ++ ++ struct surfacegen5_rqst rqst = { ++ .tc = 0x01, ++ .iid = 0x00, ++ .cid = 0x16, ++ .snc = 0x01, ++ .cdl = 0x00, ++ .pld = NULL, ++ }; ++ ++ struct surfacegen5_buf result = { ++ result.cap = ARRAY_SIZE(buf), ++ result.len = 0, ++ result.data = buf, ++ }; ++ ++ int status = surfacegen5_ec_rqst_unlocked(ec, &rqst, &result); ++ if (status) { ++ return status; ++ } ++ ++ if (buf[0] != 0x00) { ++ dev_warn(&ec->serdev->dev, ++ "unexpected result while trying to resume EC: 0x%02x\n", ++ buf[0]); ++ } ++ ++ return 0; ++} ++ ++static int surfacegen5_ssh_ec_suspend(struct surfacegen5_ec *ec) ++{ ++ u8 buf[1] = { 0x00 }; ++ ++ struct surfacegen5_rqst rqst = { ++ .tc = 0x01, ++ .iid = 0x00, ++ .cid = 0x15, ++ .snc = 0x01, ++ .cdl = 0x00, ++ .pld = NULL, ++ }; ++ ++ struct surfacegen5_buf result = { ++ result.cap = ARRAY_SIZE(buf), ++ result.len = 0, ++ result.data = buf, ++ }; ++ ++ int status = surfacegen5_ec_rqst_unlocked(ec, &rqst, &result); ++ if (status) { ++ return status; ++ } ++ ++ if (buf[0] != 0x00) { ++ dev_warn(&ec->serdev->dev, ++ "unexpected result while trying to suspend EC: 0x%02x\n", ++ buf[0]); ++ } ++ ++ return 0; ++} ++ ++ ++inline static bool surfacegen5_ssh_is_valid_syn(const u8 *ptr) ++{ ++ return ptr[0] == 0xaa && ptr[1] == 0x55; ++} ++ ++inline static bool surfacegen5_ssh_is_valid_ter(const u8 *ptr) ++{ ++ return ptr[0] == 0xff && ptr[1] == 0xff; ++} ++ ++inline static bool surfacegen5_ssh_is_valid_crc(const u8 *begin, const u8 *end) ++{ ++ u16 crc = surfacegen5_ssh_crc(begin, end - begin); ++ return (end[0] == (crc & 0xff)) && (end[1] == (crc >> 8)); ++} ++ ++ ++static int surfacegen5_ssh_send_ack(struct surfacegen5_ec *ec, u8 seq) ++{ ++ u8 buf[SG5_MSG_LEN_CTRL]; ++ u16 crc; ++ ++ buf[0] = 0xaa; ++ buf[1] = 0x55; ++ buf[2] = 0x40; ++ buf[3] = 0x00; ++ buf[4] = 0x00; ++ buf[5] = seq; ++ ++ crc = surfacegen5_ssh_crc(buf + SG5_FRAME_OFFS_CTRL, SG5_BYTELEN_CTRL); ++ buf[6] = crc & 0xff; ++ buf[7] = crc >> 8; ++ ++ buf[8] = 0xff; ++ buf[9] = 0xff; ++ ++ dev_dbg(&ec->serdev->dev, "sending message\n"); ++ print_hex_dump_debug("send: ", DUMP_PREFIX_OFFSET, 16, 1, ++ buf, SG5_MSG_LEN_CTRL, false); ++ ++ return serdev_device_write(ec->serdev, buf, SG5_MSG_LEN_CTRL, SG5_WRITE_TIMEOUT); ++} ++ ++static void surfacegen5_event_work_ack_handler(struct work_struct *_work) ++{ ++ struct surfacegen5_event_work *work; ++ struct surfacegen5_event *event; ++ struct surfacegen5_ec *ec; ++ struct device *dev; ++ int status; ++ ++ work = container_of(_work, struct surfacegen5_event_work, work_ack); ++ event = &work->event; ++ ec = work->ec; ++ dev = &ec->serdev->dev; ++ ++ // make sure we load a fresh ec state ++ smp_mb(); ++ ++ if (ec->state == SG5_EC_INITIALIZED) { ++ status = surfacegen5_ssh_send_ack(ec, work->seq); ++ if (status) { ++ dev_err(dev, SG5_EVENT_TAG "failed to send ACK: %d\n", status); ++ } ++ } ++ ++ if (refcount_dec_and_test(&work->refcount)) { ++ kfree(work); ++ } ++} ++ ++static void surfacegen5_event_work_evt_handler(struct work_struct *_work) ++{ ++ struct delayed_work *dwork = (struct delayed_work *)_work; ++ struct surfacegen5_event_work *work; ++ struct surfacegen5_event *event; ++ struct surfacegen5_ec *ec; ++ struct device *dev; ++ unsigned long flags; ++ ++ surfacegen5_ec_event_handler_fn handler; ++ void *handler_data; ++ ++ int status = 0; ++ ++ work = container_of(dwork, struct surfacegen5_event_work, work_evt); ++ event = &work->event; ++ ec = work->ec; ++ dev = &ec->serdev->dev; ++ ++ spin_lock_irqsave(&ec->events.lock, flags); ++ handler = ec->events.handler[event->rqid - 1].handler; ++ handler_data = ec->events.handler[event->rqid - 1].data; ++ spin_unlock_irqrestore(&ec->events.lock, flags); ++ ++ /* ++ * During handler removal or driver release, we ensure every event gets ++ * handled before return of that function. Thus a handler obtained here is ++ * guaranteed to be valid at least until this function returns. ++ */ ++ ++ if (handler) { ++ status = handler(event, handler_data); ++ } else { ++ dev_warn(dev, SG5_EVENT_TAG "unhandled event (rqid: %04x)\n", event->rqid); ++ } ++ ++ if (status) { ++ dev_err(dev, SG5_EVENT_TAG "error handling event: %d\n", status); ++ } ++ ++ if (refcount_dec_and_test(&work->refcount)) { ++ kfree(work); ++ } ++} ++ ++static void surfacegen5_ssh_handle_event(struct surfacegen5_ec *ec, const u8 *buf) ++{ ++ struct device *dev = &ec->serdev->dev; ++ const struct surfacegen5_frame_ctrl *ctrl; ++ const struct surfacegen5_frame_cmd *cmd; ++ struct surfacegen5_event_work *work; ++ unsigned long flags; ++ u16 pld_len; ++ ++ surfacegen5_ec_event_handler_delay delay_fn; ++ void *handler_data; ++ unsigned long delay = 0; ++ ++ ctrl = (const struct surfacegen5_frame_ctrl *)(buf + SG5_FRAME_OFFS_CTRL); ++ cmd = (const struct surfacegen5_frame_cmd *)(buf + SG5_FRAME_OFFS_CMD); ++ ++ pld_len = ctrl->len - SG5_BYTELEN_CMDFRAME; ++ ++ work = kzalloc(sizeof(struct surfacegen5_event_work) + pld_len, GFP_ATOMIC); ++ if (!work) { ++ dev_warn(dev, SG5_EVENT_TAG "failed to allocate memory, dropping event\n"); ++ return; ++ } ++ ++ refcount_set(&work->refcount, 2); ++ work->ec = ec; ++ work->seq = ctrl->seq; ++ work->event.rqid = (cmd->rqid_hi << 8) | cmd->rqid_lo; ++ work->event.tc = cmd->tc; ++ work->event.iid = cmd->iid; ++ work->event.cid = cmd->cid; ++ work->event.len = pld_len; ++ work->event.pld = ((u8*) work) + sizeof(struct surfacegen5_event_work); ++ ++ memcpy(work->event.pld, buf + SG5_FRAME_OFFS_CMD_PLD, pld_len); ++ ++ INIT_WORK(&work->work_ack, surfacegen5_event_work_ack_handler); ++ queue_work(ec->events.queue_ack, &work->work_ack); ++ ++ spin_lock_irqsave(&ec->events.lock, flags); ++ handler_data = ec->events.handler[work->event.rqid - 1].data; ++ delay_fn = ec->events.handler[work->event.rqid - 1].delay; ++ if (delay_fn) { ++ delay = delay_fn(&work->event, handler_data); ++ } ++ spin_unlock_irqrestore(&ec->events.lock, flags); ++ ++ // immediate execution for high priority events (e.g. keyboard) ++ if (delay == SURFACEGEN5_EVENT_IMMEDIATE) { ++ surfacegen5_event_work_evt_handler(&work->work_evt.work); ++ } else { ++ INIT_DELAYED_WORK(&work->work_evt, surfacegen5_event_work_evt_handler); ++ queue_delayed_work(ec->events.queue_evt, &work->work_evt, delay); ++ } ++} ++ ++static int surfacegen5_ssh_receive_msg_ctrl(struct surfacegen5_ec *ec, ++ const u8 *buf, size_t size) ++{ ++ struct device *dev = &ec->serdev->dev; ++ struct surfacegen5_ec_receiver *rcv = &ec->receiver; ++ const struct surfacegen5_frame_ctrl *ctrl; ++ struct surfacegen5_fifo_packet packet; ++ ++ const u8 *ctrl_begin = buf + SG5_FRAME_OFFS_CTRL; ++ const u8 *ctrl_end = buf + SG5_FRAME_OFFS_CTRL_CRC; ++ ++ ctrl = (const struct surfacegen5_frame_ctrl *)(ctrl_begin); ++ ++ // actual length check ++ if (size < SG5_MSG_LEN_CTRL) { ++ return 0; // need more bytes ++ } ++ ++ // validate TERM ++ if (!surfacegen5_ssh_is_valid_ter(buf + SG5_FRAME_OFFS_TERM)) { ++ dev_err(dev, SG5_RECV_TAG "invalid end of message\n"); ++ return size; // discard everything ++ } ++ ++ // validate CRC ++ if (!surfacegen5_ssh_is_valid_crc(ctrl_begin, ctrl_end)) { ++ dev_err(dev, SG5_RECV_TAG "invalid checksum (ctrl)\n"); ++ return SG5_MSG_LEN_CTRL; // only discard message ++ } ++ ++ // check if we expect the message ++ if (rcv->state != SG5_RCV_CONTROL) { ++ dev_err(dev, SG5_RECV_TAG "discarding message: ctrl not expected\n"); ++ return SG5_MSG_LEN_CTRL; // discard message ++ } ++ ++ // check if it is for our request ++ if (ctrl->type == SG5_FRAME_TYPE_ACK && ctrl->seq != rcv->expect.seq) { ++ dev_err(dev, SG5_RECV_TAG "discarding message: ack does not match\n"); ++ return SG5_MSG_LEN_CTRL; // discard message ++ } ++ ++ // we now have a valid & expected ACK/RETRY message ++ dev_dbg(dev, SG5_RECV_TAG "valid control message received (type: 0x%02x)\n", ctrl->type); ++ ++ packet.type = ctrl->type; ++ packet.seq = ctrl->seq; ++ packet.len = 0; ++ ++ if (kfifo_avail(&rcv->fifo) >= sizeof(packet)) { ++ kfifo_in(&rcv->fifo, (u8 *) &packet, sizeof(packet)); ++ ++ } else { ++ dev_warn(dev, SG5_RECV_TAG ++ "dropping frame: not enough space in fifo (type = %d)\n", ++ SG5_FRAME_TYPE_CMD); ++ ++ return SG5_MSG_LEN_CTRL; // discard message ++ } ++ ++ // update decoder state ++ if (ctrl->type == SG5_FRAME_TYPE_ACK) { ++ rcv->state = rcv->expect.pld ++ ? SG5_RCV_COMMAND ++ : SG5_RCV_DISCARD; ++ } ++ ++ complete(&rcv->signal); ++ return SG5_MSG_LEN_CTRL; // handled message ++} ++ ++static int surfacegen5_ssh_receive_msg_cmd(struct surfacegen5_ec *ec, ++ const u8 *buf, size_t size) ++{ ++ struct device *dev = &ec->serdev->dev; ++ struct surfacegen5_ec_receiver *rcv = &ec->receiver; ++ const struct surfacegen5_frame_ctrl *ctrl; ++ const struct surfacegen5_frame_cmd *cmd; ++ struct surfacegen5_fifo_packet packet; ++ ++ const u8 *ctrl_begin = buf + SG5_FRAME_OFFS_CTRL; ++ const u8 *ctrl_end = buf + SG5_FRAME_OFFS_CTRL_CRC; ++ const u8 *cmd_begin = buf + SG5_FRAME_OFFS_CMD; ++ const u8 *cmd_begin_pld = buf + SG5_FRAME_OFFS_CMD_PLD; ++ const u8 *cmd_end; ++ ++ size_t msg_len; ++ ++ ctrl = (const struct surfacegen5_frame_ctrl *)(ctrl_begin); ++ cmd = (const struct surfacegen5_frame_cmd *)(cmd_begin); ++ ++ // we need at least a full control frame ++ if (size < (SG5_BYTELEN_SYNC + SG5_BYTELEN_CTRL + SG5_BYTELEN_CRC)) { ++ return 0; // need more bytes ++ } ++ ++ // validate control-frame CRC ++ if (!surfacegen5_ssh_is_valid_crc(ctrl_begin, ctrl_end)) { ++ dev_err(dev, SG5_RECV_TAG "invalid checksum (cmd-ctrl)\n"); ++ /* ++ * We can't be sure here if length is valid, thus ++ * discard everything. ++ */ ++ return size; ++ } ++ ++ // actual length check (ctrl->len contains command-frame but not crc) ++ msg_len = SG5_MSG_LEN_CMD_BASE + ctrl->len; ++ if (size < msg_len) { ++ return 0; // need more bytes ++ } ++ ++ cmd_end = cmd_begin + ctrl->len; ++ ++ // validate command-frame type ++ if (cmd->type != SG5_FRAME_TYPE_CMD) { ++ dev_err(dev, SG5_RECV_TAG "expected command frame type but got 0x%02x\n", cmd->type); ++ return size; // discard everything ++ } ++ ++ // validate command-frame CRC ++ if (!surfacegen5_ssh_is_valid_crc(cmd_begin, cmd_end)) { ++ dev_err(dev, SG5_RECV_TAG "invalid checksum (cmd-pld)\n"); ++ ++ /* ++ * The message length is provided in the control frame. As we ++ * already validated that, we can be sure here that it's ++ * correct, so we only need to discard the message. ++ */ ++ return msg_len; ++ } ++ ++ // check if we received an event notification ++ if (surfacegen5_rqid_is_event((cmd->rqid_hi << 8) | cmd->rqid_lo)) { ++ surfacegen5_ssh_handle_event(ec, buf); ++ return msg_len; // handled message ++ } ++ ++ // check if we expect the message ++ if (rcv->state != SG5_RCV_COMMAND) { ++ dev_dbg(dev, SG5_RECV_TAG "discarding message: command not expected\n"); ++ return msg_len; // discard message ++ } ++ ++ // check if response is for our request ++ if (rcv->expect.rqid != (cmd->rqid_lo | (cmd->rqid_hi << 8))) { ++ dev_dbg(dev, SG5_RECV_TAG "discarding message: command not a match\n"); ++ return msg_len; // discard message ++ } ++ ++ // we now have a valid & expected command message ++ dev_dbg(dev, SG5_RECV_TAG "valid command message received\n"); ++ ++ packet.type = ctrl->type; ++ packet.seq = ctrl->seq; ++ packet.len = cmd_end - cmd_begin_pld; ++ ++ if (kfifo_avail(&rcv->fifo) >= sizeof(packet) + packet.len) { ++ kfifo_in(&rcv->fifo, &packet, sizeof(packet)); ++ kfifo_in(&rcv->fifo, cmd_begin_pld, packet.len); ++ ++ } else { ++ dev_warn(dev, SG5_RECV_TAG ++ "dropping frame: not enough space in fifo (type = %d)\n", ++ SG5_FRAME_TYPE_CMD); ++ ++ return SG5_MSG_LEN_CTRL; // discard message ++ } ++ ++ rcv->state = SG5_RCV_DISCARD; ++ ++ complete(&rcv->signal); ++ return msg_len; // handled message ++} ++ ++static int surfacegen5_ssh_eval_buf(struct surfacegen5_ec *ec, ++ const u8 *buf, size_t size) ++{ ++ struct device *dev = &ec->serdev->dev; ++ struct surfacegen5_frame_ctrl *ctrl; ++ ++ // we need at least a control frame to check what to do ++ if (size < (SG5_BYTELEN_SYNC + SG5_BYTELEN_CTRL)) { ++ return 0; // need more bytes ++ } ++ ++ // make sure we're actually at the start of a new message ++ if (!surfacegen5_ssh_is_valid_syn(buf)) { ++ dev_err(dev, SG5_RECV_TAG "invalid start of message\n"); ++ return size; // discard everything ++ } ++ ++ // handle individual message types seperately ++ ctrl = (struct surfacegen5_frame_ctrl *)(buf + SG5_FRAME_OFFS_CTRL); ++ ++ switch (ctrl->type) { ++ case SG5_FRAME_TYPE_ACK: ++ case SG5_FRAME_TYPE_RETRY: ++ return surfacegen5_ssh_receive_msg_ctrl(ec, buf, size); ++ ++ case SG5_FRAME_TYPE_CMD: ++ return surfacegen5_ssh_receive_msg_cmd(ec, buf, size); ++ ++ default: ++ dev_err(dev, SG5_RECV_TAG "unknown frame type 0x%02x\n", ctrl->type); ++ return size; // discard everything ++ } ++} ++ ++static int surfacegen5_ssh_receive_buf(struct serdev_device *serdev, ++ const unsigned char *buf, size_t size) ++{ ++ struct surfacegen5_ec *ec = serdev_device_get_drvdata(serdev); ++ struct surfacegen5_ec_receiver *rcv = &ec->receiver; ++ unsigned long flags; ++ int offs = 0; ++ int used, n; ++ ++ dev_dbg(&serdev->dev, SG5_RECV_TAG "received buffer (size: %zu)\n", size); ++ print_hex_dump_debug(SG5_RECV_TAG, DUMP_PREFIX_OFFSET, 16, 1, buf, size, false); ++ ++ /* ++ * The battery _BIX message gets a bit long, thus we have to add some ++ * additional buffering here. ++ */ ++ ++ spin_lock_irqsave(&rcv->lock, flags); ++ ++ // copy to eval-buffer ++ used = min(size, (size_t)(rcv->eval_buf.cap - rcv->eval_buf.len)); ++ memcpy(rcv->eval_buf.ptr + rcv->eval_buf.len, buf, used); ++ rcv->eval_buf.len += used; ++ ++ // evaluate buffer until we need more bytes or eval-buf is empty ++ while (offs < rcv->eval_buf.len) { ++ n = rcv->eval_buf.len - offs; ++ n = surfacegen5_ssh_eval_buf(ec, rcv->eval_buf.ptr + offs, n); ++ if (n <= 0) break; // need more bytes ++ ++ offs += n; ++ } ++ ++ // throw away the evaluated parts ++ rcv->eval_buf.len -= offs; ++ memmove(rcv->eval_buf.ptr, rcv->eval_buf.ptr + offs, rcv->eval_buf.len); ++ ++ spin_unlock_irqrestore(&rcv->lock, flags); ++ ++ return used; ++} ++ ++ ++static acpi_status ++surfacegen5_ssh_setup_from_resource(struct acpi_resource *resource, void *context) ++{ ++ struct serdev_device *serdev = context; ++ struct acpi_resource_common_serialbus *serial; ++ struct acpi_resource_uart_serialbus *uart; ++ int status = 0; ++ ++ if (resource->type != ACPI_RESOURCE_TYPE_SERIAL_BUS) { ++ return AE_OK; ++ } ++ ++ serial = &resource->data.common_serial_bus; ++ if (serial->type != ACPI_RESOURCE_SERIAL_TYPE_UART) { ++ return AE_OK; ++ } ++ ++ uart = &resource->data.uart_serial_bus; ++ ++ // set up serdev device ++ serdev_device_set_baudrate(serdev, uart->default_baud_rate); ++ ++ // serdev currently only supports RTSCTS flow control ++ if (uart->flow_control & SG5_SUPPORTED_FLOW_CONTROL_MASK) { ++ dev_warn(&serdev->dev, "unsupported flow control (value: 0x%02x)\n", uart->flow_control); ++ } ++ ++ // set RTSCTS flow control ++ serdev_device_set_flow_control(serdev, uart->flow_control & ACPI_UART_FLOW_CONTROL_HW); ++ ++ // serdev currently only supports EVEN/ODD parity ++ switch (uart->parity) { ++ case ACPI_UART_PARITY_NONE: ++ status = serdev_device_set_parity(serdev, SERDEV_PARITY_NONE); ++ break; ++ case ACPI_UART_PARITY_EVEN: ++ status = serdev_device_set_parity(serdev, SERDEV_PARITY_EVEN); ++ break; ++ case ACPI_UART_PARITY_ODD: ++ status = serdev_device_set_parity(serdev, SERDEV_PARITY_ODD); ++ break; ++ default: ++ dev_warn(&serdev->dev, "unsupported parity (value: 0x%02x)\n", uart->parity); ++ break; ++ } ++ ++ if (status) { ++ dev_err(&serdev->dev, "failed to set parity (value: 0x%02x)\n", uart->parity); ++ return status; ++ } ++ ++ return AE_CTRL_TERMINATE; // we've found the resource and are done ++} ++ ++ ++static bool surfacegen5_idma_filter(struct dma_chan *chan, void *param) ++{ ++ // see dw8250_idma_filter ++ return param == chan->device->dev->parent; ++} ++ ++static int surfacegen5_ssh_check_dma(struct serdev_device *serdev) ++{ ++ struct device *dev = serdev->ctrl->dev.parent; ++ struct dma_chan *rx, *tx; ++ dma_cap_mask_t mask; ++ int status = 0; ++ ++ /* ++ * The EC UART requires DMA for proper communication. If we don't use DMA, ++ * we'll drop bytes when the system has high load, e.g. during boot. This ++ * causes some ugly behaviour, i.e. battery information (_BIX) messages ++ * failing frequently. We're making sure the required DMA channels are ++ * available here so serial8250_do_startup is able to grab them later ++ * instead of silently falling back to a non-DMA approach. ++ */ ++ ++ dma_cap_zero(mask); ++ dma_cap_set(DMA_SLAVE, mask); ++ ++ rx = dma_request_slave_channel_compat(mask, surfacegen5_idma_filter, dev->parent, dev, "rx"); ++ if (IS_ERR_OR_NULL(rx)) { ++ status = rx ? PTR_ERR(rx) : -EPROBE_DEFER; ++ if (status != -EPROBE_DEFER) { ++ dev_err(&serdev->dev, "sg5_dma: error requesting rx channel: %d\n", status); ++ } else { ++ dev_dbg(&serdev->dev, "sg5_dma: rx channel not found, deferring probe\n"); ++ } ++ goto check_dma_out; ++ } ++ ++ tx = dma_request_slave_channel_compat(mask, surfacegen5_idma_filter, dev->parent, dev, "tx"); ++ if (IS_ERR_OR_NULL(tx)) { ++ status = tx ? PTR_ERR(tx) : -EPROBE_DEFER; ++ if (status != -EPROBE_DEFER) { ++ dev_err(&serdev->dev, "sg5_dma: error requesting tx channel: %d\n", status); ++ } else { ++ dev_dbg(&serdev->dev, "sg5_dma: tx channel not found, deferring probe\n"); ++ } ++ goto check_dma_release_rx; ++ } ++ ++ dma_release_channel(tx); ++check_dma_release_rx: ++ dma_release_channel(rx); ++check_dma_out: ++ return status; ++} ++ ++ ++static int surfacegen5_ssh_suspend(struct device *dev) ++{ ++ struct surfacegen5_ec *ec; ++ int status = 0; ++ ++ dev_dbg(dev, "suspending\n"); ++ ++ ec = surfacegen5_ec_acquire_init(); ++ if (ec) { ++ status = surfacegen5_ssh_ec_suspend(ec); ++ if (status) { ++ dev_err(dev, "failed to suspend EC: %d\n", status); ++ } ++ ++ ec->state = SG5_EC_SUSPENDED; ++ surfacegen5_ec_release(ec); ++ } ++ ++ return status; ++} ++ ++static int surfacegen5_ssh_resume(struct device *dev) ++{ ++ struct surfacegen5_ec *ec; ++ int status = 0; ++ ++ dev_dbg(dev, "resuming\n"); ++ ++ ec = surfacegen5_ec_acquire_init(); ++ if (ec) { ++ ec->state = SG5_EC_INITIALIZED; ++ ++ status = surfacegen5_ssh_ec_resume(ec); ++ if (status) { ++ dev_err(dev, "failed to resume EC: %d\n", status); ++ } ++ ++ surfacegen5_ec_release(ec); ++ } ++ ++ return status; ++} ++ ++static SIMPLE_DEV_PM_OPS(surfacegen5_ssh_pm_ops, surfacegen5_ssh_suspend, surfacegen5_ssh_resume); ++ ++ ++static const struct serdev_device_ops surfacegen5_ssh_device_ops = { ++ .receive_buf = surfacegen5_ssh_receive_buf, ++ .write_wakeup = serdev_device_write_wakeup, ++}; ++ ++static int surfacegen5_acpi_ssh_probe(struct serdev_device *serdev) ++{ ++ struct surfacegen5_ec *ec; ++ struct workqueue_struct *event_queue_ack; ++ struct workqueue_struct *event_queue_evt; ++ u8 *write_buf; ++ u8 *read_buf; ++ u8 *eval_buf; ++ acpi_handle *ssh = ACPI_HANDLE(&serdev->dev); ++ acpi_status status; ++ ++ dev_dbg(&serdev->dev, "probing\n"); ++ ++ // ensure DMA is ready before we set up the device ++ status = surfacegen5_ssh_check_dma(serdev); ++ if (status) { ++ return status; ++ } ++ ++ // allocate buffers ++ write_buf = kzalloc(SG5_WRITE_BUF_LEN, GFP_KERNEL); ++ if (!write_buf) { ++ status = -ENOMEM; ++ goto err_ssh_probe_write_buf; ++ } ++ ++ read_buf = kzalloc(SG5_READ_BUF_LEN, GFP_KERNEL); ++ if (!read_buf) { ++ status = -ENOMEM; ++ goto err_ssh_probe_read_buf; ++ } ++ ++ eval_buf = kzalloc(SG5_EVAL_BUF_LEN, GFP_KERNEL); ++ if (!eval_buf) { ++ status = -ENOMEM; ++ goto err_ssh_probe_eval_buf; ++ } ++ ++ event_queue_ack = create_singlethread_workqueue("sg5_ackq"); ++ if (!event_queue_ack) { ++ status = -ENOMEM; ++ goto err_ssh_probe_ackq; ++ } ++ ++ event_queue_evt = create_workqueue("sg5_evtq"); ++ if (!event_queue_evt) { ++ status = -ENOMEM; ++ goto err_ssh_probe_evtq; ++ } ++ ++ // set up EC ++ ec = surfacegen5_ec_acquire(); ++ if (ec->state != SG5_EC_UNINITIALIZED) { ++ dev_err(&serdev->dev, "embedded controller already initialized\n"); ++ surfacegen5_ec_release(ec); ++ ++ status = -EBUSY; ++ goto err_ssh_probe_busy; ++ } ++ ++ ec->serdev = serdev; ++ ec->writer.data = write_buf; ++ ec->writer.ptr = write_buf; ++ ++ // initialize receiver ++ init_completion(&ec->receiver.signal); ++ kfifo_init(&ec->receiver.fifo, read_buf, SG5_READ_BUF_LEN); ++ ec->receiver.eval_buf.ptr = eval_buf; ++ ec->receiver.eval_buf.cap = SG5_EVAL_BUF_LEN; ++ ec->receiver.eval_buf.len = 0; ++ ++ // initialize event handling ++ ec->events.queue_ack = event_queue_ack; ++ ec->events.queue_evt = event_queue_evt; ++ ++ ec->state = SG5_EC_INITIALIZED; ++ ++ serdev_device_set_drvdata(serdev, ec); ++ ++ // ensure everything is properly set-up before we open the device ++ smp_mb(); ++ ++ serdev_device_set_client_ops(serdev, &surfacegen5_ssh_device_ops); ++ status = serdev_device_open(serdev); ++ if (status) { ++ goto err_ssh_probe_open; ++ } ++ ++ status = acpi_walk_resources(ssh, METHOD_NAME__CRS, ++ surfacegen5_ssh_setup_from_resource, serdev); ++ if (ACPI_FAILURE(status)) { ++ goto err_ssh_probe_devinit; ++ } ++ ++ status = surfacegen5_ssh_ec_resume(ec); ++ if (status) { ++ goto err_ssh_probe_devinit; ++ } ++ ++ surfacegen5_ec_release(ec); ++ acpi_walk_dep_device_list(ssh); ++ ++ return 0; ++ ++err_ssh_probe_devinit: ++ serdev_device_close(serdev); ++err_ssh_probe_open: ++ ec->state = SG5_EC_UNINITIALIZED; ++ serdev_device_set_drvdata(serdev, NULL); ++ surfacegen5_ec_release(ec); ++err_ssh_probe_busy: ++ destroy_workqueue(event_queue_evt); ++err_ssh_probe_evtq: ++ destroy_workqueue(event_queue_ack); ++err_ssh_probe_ackq: ++ kfree(eval_buf); ++err_ssh_probe_eval_buf: ++ kfree(read_buf); ++err_ssh_probe_read_buf: ++ kfree(write_buf); ++err_ssh_probe_write_buf: ++ return status; ++} ++ ++static void surfacegen5_acpi_ssh_remove(struct serdev_device *serdev) ++{ ++ struct surfacegen5_ec *ec; ++ unsigned long flags; ++ int status; ++ ++ ec = surfacegen5_ec_acquire_init(); ++ if (!ec) { ++ return; ++ } ++ ++ // suspend EC and disable events ++ status = surfacegen5_ssh_ec_suspend(ec); ++ if (status) { ++ dev_err(&serdev->dev, "failed to suspend EC: %d\n", status); ++ } ++ ++ // make sure all events (received up to now) have been properly handled ++ flush_workqueue(ec->events.queue_ack); ++ flush_workqueue(ec->events.queue_evt); ++ ++ // remove event handlers ++ spin_lock_irqsave(&ec->events.lock, flags); ++ memset(ec->events.handler, 0, ++ sizeof(struct surfacegen5_ec_event_handler) ++ * SG5_NUM_EVENT_TYPES); ++ spin_unlock_irqrestore(&ec->events.lock, flags); ++ ++ // set device to deinitialized state ++ ec->state = SG5_EC_UNINITIALIZED; ++ ec->serdev = NULL; ++ ++ // ensure state and serdev get set before continuing ++ smp_mb(); ++ ++ /* ++ * Flush any event that has not been processed yet to ensure we're not going to ++ * use the serial device any more (e.g. for ACKing). ++ */ ++ flush_workqueue(ec->events.queue_ack); ++ flush_workqueue(ec->events.queue_evt); ++ ++ serdev_device_close(serdev); ++ ++ /* ++ * Only at this point, no new events can be received. Destroying the ++ * workqueue here flushes all remaining events. Those events will be ++ * silently ignored and neither ACKed nor any handler gets called. ++ */ ++ destroy_workqueue(ec->events.queue_ack); ++ destroy_workqueue(ec->events.queue_evt); ++ ++ // free writer ++ kfree(ec->writer.data); ++ ec->writer.data = NULL; ++ ec->writer.ptr = NULL; ++ ++ // free receiver ++ spin_lock_irqsave(&ec->receiver.lock, flags); ++ ec->receiver.state = SG5_RCV_DISCARD; ++ kfifo_free(&ec->receiver.fifo); ++ ++ kfree(ec->receiver.eval_buf.ptr); ++ ec->receiver.eval_buf.ptr = NULL; ++ ec->receiver.eval_buf.cap = 0; ++ ec->receiver.eval_buf.len = 0; ++ spin_unlock_irqrestore(&ec->receiver.lock, flags); ++ ++ serdev_device_set_drvdata(serdev, NULL); ++ surfacegen5_ec_release(ec); ++} ++ ++ ++static const struct acpi_device_id surfacegen5_acpi_ssh_match[] = { ++ { "MSHW0084", 0 }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(acpi, surfacegen5_acpi_ssh_match); ++ ++static struct serdev_device_driver surfacegen5_acpi_ssh = { ++ .probe = surfacegen5_acpi_ssh_probe, ++ .remove = surfacegen5_acpi_ssh_remove, ++ .driver = { ++ .name = "surfacegen5_acpi_ssh", ++ .acpi_match_table = ACPI_PTR(surfacegen5_acpi_ssh_match), ++ .pm = &surfacegen5_ssh_pm_ops, ++ }, ++}; ++ ++#endif /* CONFIG_SURFACE_ACPI_SSH */ ++ ++ ++/************************************************************************* ++ * Surface ACPI Notify driver ++ */ ++ ++#ifdef CONFIG_SURFACE_ACPI_SAN ++ ++#define SG5_RQST_RETRY 5 ++ ++#define SG5_SAN_DSM_REVISION 0 ++#define SG5_SAN_DSM_FN_NOTIFY_SENSOR_TRIP_POINT 0x09 ++ ++static const guid_t SG5_SAN_DSM_UUID = ++ GUID_INIT(0x93b666c5, 0x70c6, 0x469f, 0xa2, 0x15, 0x3d, ++ 0x48, 0x7c, 0x91, 0xab, 0x3c); ++ ++#define SG5_EVENT_DELAY_POWER msecs_to_jiffies(5000) ++ ++#define SG5_EVENT_PWR_TC 0x02 ++#define SG5_EVENT_PWR_RQID 0x0002 ++#define SG5_EVENT_PWR_CID_HWCHANGE 0x15 ++#define SG5_EVENT_PWR_CID_CHARGING 0x16 ++#define SG5_EVENT_PWR_CID_ADAPTER 0x17 ++#define SG5_EVENT_PWR_CID_STATE 0x4f ++ ++#define SG5_EVENT_TEMP_TC 0x03 ++#define SG5_EVENT_TEMP_RQID 0x0003 ++#define SG5_EVENT_TEMP_CID_NOTIFY_SENSOR_TRIP_POINT 0x0b ++ ++#define SG5_SAN_RQST_TAG "san_rqst: " ++ ++ ++struct surfacegen5_san_acpi_consumer { ++ char *path; ++ bool required; ++ u32 flags; ++}; ++ ++struct surfacegen5_san_opreg_context { ++ struct acpi_connection_info connection; ++ struct device *dev; ++}; ++ ++struct surfacegen5_san_consumers { ++ u32 num; ++ struct device_link **links; ++}; ++ ++struct surfacegen5_san_drvdata { ++ struct surfacegen5_san_opreg_context opreg_ctx; ++ struct surfacegen5_san_consumers consumers; ++ struct device_link *ec_link; ++}; ++ ++struct gsb_data_in { ++ u8 cv; ++} __packed; ++ ++struct gsb_data_rqsx { ++ u8 cv; // command value (should be 0x01 or 0x03) ++ u8 tc; // target controller ++ u8 tid; // expected to be 0x01, could be revision ++ u8 iid; // target sub-controller (e.g. primary vs. secondary battery) ++ u8 snc; // expect-response-flag ++ u8 cid; // command ID ++ u8 cdl; // payload length ++ u8 _pad; // padding ++ u8 pld[0]; // payload ++} __packed; ++ ++struct gsb_data_etwl { ++ u8 cv; // command value (should be 0x02) ++ u8 etw3; // ? ++ u8 etw4; // ? ++ u8 msg[0]; // error message (ASCIIZ) ++} __packed; ++ ++struct gsb_data_out { ++ u8 status; // _SSH communication status ++ u8 len; // _SSH payload length ++ u8 pld[0]; // _SSH payload ++} __packed; ++ ++union gsb_buffer_data { ++ struct gsb_data_in in; // common input ++ struct gsb_data_rqsx rqsx; // RQSX input ++ struct gsb_data_etwl etwl; // ETWL input ++ struct gsb_data_out out; // output ++}; ++ ++struct gsb_buffer { ++ u8 status; // GSB AttribRawProcess status ++ u8 len; // GSB AttribRawProcess length ++ union gsb_buffer_data data; ++} __packed; ++ ++ ++enum surfacegen5_pwr_event { ++ SURFACEGEN5_PWR_EVENT_BAT1_STAT = 0x03, ++ SURFACEGEN5_PWR_EVENT_BAT1_INFO = 0x04, ++ SURFACEGEN5_PWR_EVENT_ADP1_STAT = 0x05, ++ SURFACEGEN5_PWR_EVENT_ADP1_INFO = 0x06, ++ SURFACEGEN5_PWR_EVENT_BAT2_STAT = 0x07, ++ SURFACEGEN5_PWR_EVENT_BAT2_INFO = 0x08, ++}; ++ ++ ++static int surfacegen5_acpi_notify_power_event(struct device *dev, enum surfacegen5_pwr_event event) ++{ ++ acpi_handle san = ACPI_HANDLE(dev); ++ union acpi_object *obj; ++ ++ obj = acpi_evaluate_dsm_typed(san, &SG5_SAN_DSM_UUID, SG5_SAN_DSM_REVISION, ++ (u8) event, NULL, ACPI_TYPE_BUFFER); ++ ++ if (IS_ERR_OR_NULL(obj)) { ++ return obj ? PTR_ERR(obj) : -ENXIO; ++ } ++ ++ if (obj->buffer.length != 1 || obj->buffer.pointer[0] != 0) { ++ dev_err(dev, "got unexpected result from _DSM\n"); ++ return -EFAULT; ++ } ++ ++ ACPI_FREE(obj); ++ return 0; ++} ++ ++static int surfacegen5_acpi_notify_sensor_trip_point(struct device *dev, u8 iid) ++{ ++ acpi_handle san = ACPI_HANDLE(dev); ++ union acpi_object *obj; ++ union acpi_object param; ++ ++ param.type = ACPI_TYPE_INTEGER; ++ param.integer.value = iid; ++ ++ obj = acpi_evaluate_dsm_typed(san, &SG5_SAN_DSM_UUID, SG5_SAN_DSM_REVISION, ++ SG5_SAN_DSM_FN_NOTIFY_SENSOR_TRIP_POINT, ++ ¶m, ACPI_TYPE_BUFFER); ++ ++ if (IS_ERR_OR_NULL(obj)) { ++ return obj ? PTR_ERR(obj) : -ENXIO; ++ } ++ ++ if (obj->buffer.length != 1 || obj->buffer.pointer[0] != 0) { ++ dev_err(dev, "got unexpected result from _DSM\n"); ++ return -EFAULT; ++ } ++ ++ ACPI_FREE(obj); ++ return 0; ++} ++ ++ ++inline static int surfacegen5_evt_power_adapter(struct device *dev, struct surfacegen5_event *event) ++{ ++ int status; ++ ++ status = surfacegen5_acpi_notify_power_event(dev, SURFACEGEN5_PWR_EVENT_ADP1_STAT); ++ if (status) { ++ dev_err(dev, "error handling power event (cid = %x)\n", event->cid); ++ return status; ++ } ++ ++ return 0; ++} ++ ++inline static int surfacegen5_evt_power_hwchange(struct device *dev, struct surfacegen5_event *event) ++{ ++ enum surfacegen5_pwr_event evcode; ++ int status; ++ ++ if (event->iid == 0x02) { ++ evcode = SURFACEGEN5_PWR_EVENT_BAT2_INFO; ++ } else { ++ evcode = SURFACEGEN5_PWR_EVENT_BAT1_INFO; ++ } ++ ++ status = surfacegen5_acpi_notify_power_event(dev, evcode); ++ if (status) { ++ dev_err(dev, "error handling power event (cid = %x)\n", event->cid); ++ return status; ++ } ++ ++ return 0; ++} ++ ++inline static int surfacegen5_evt_power_state(struct device *dev, struct surfacegen5_event *event) ++{ ++ int status; ++ ++ status = surfacegen5_acpi_notify_power_event(dev, SURFACEGEN5_PWR_EVENT_BAT1_STAT); ++ if (status) { ++ dev_err(dev, "error handling power event (cid = %x)\n", event->cid); ++ return status; ++ } ++ ++ status = surfacegen5_acpi_notify_power_event(dev, SURFACEGEN5_PWR_EVENT_BAT2_STAT); ++ if (status) { ++ dev_err(dev, "error handling power event (cid = %x)\n", event->cid); ++ return status; ++ } ++ ++ return 0; ++} ++ ++static unsigned long surfacegen5_evt_power_delay(struct surfacegen5_event *event, void *data) ++{ ++ switch (event->cid) { ++ case SG5_EVENT_PWR_CID_CHARGING: ++ case SG5_EVENT_PWR_CID_STATE: ++ return SG5_EVENT_DELAY_POWER; ++ ++ case SG5_EVENT_PWR_CID_ADAPTER: ++ case SG5_EVENT_PWR_CID_HWCHANGE: ++ default: ++ return 0; ++ } ++} ++ ++static int surfacegen5_evt_power(struct surfacegen5_event *event, void *data) ++{ ++ struct device *dev = (struct device *)data; ++ ++ switch (event->cid) { ++ case SG5_EVENT_PWR_CID_HWCHANGE: ++ return surfacegen5_evt_power_hwchange(dev, event); ++ ++ case SG5_EVENT_PWR_CID_ADAPTER: ++ return surfacegen5_evt_power_adapter(dev, event); ++ ++ case SG5_EVENT_PWR_CID_CHARGING: ++ case SG5_EVENT_PWR_CID_STATE: ++ return surfacegen5_evt_power_state(dev, event); ++ ++ default: ++ dev_warn(dev, "unhandled power event (cid = %x)\n", event->cid); ++ } ++ ++ return 0; ++} ++ ++ ++inline static int surfacegen5_evt_thermal_notify(struct device *dev, struct surfacegen5_event *event) ++{ ++ int status; ++ ++ status = surfacegen5_acpi_notify_sensor_trip_point(dev, event->iid); ++ if (status) { ++ dev_err(dev, "error handling thermal event (cid = %x)\n", event->cid); ++ return status; ++ } ++ ++ return 0; ++} ++ ++static int surfacegen5_evt_thermal(struct surfacegen5_event *event, void *data) ++{ ++ struct device *dev = (struct device *)data; ++ ++ switch (event->cid) { ++ case SG5_EVENT_TEMP_CID_NOTIFY_SENSOR_TRIP_POINT: ++ return surfacegen5_evt_thermal_notify(dev, event); ++ ++ default: ++ dev_warn(dev, "unhandled thermal event (cid = %x)\n", event->cid); ++ } ++ ++ return 0; ++} ++ ++ ++static struct gsb_data_rqsx *surfacegen5_san_validate_rqsx( ++ struct device *dev, const char *type, struct gsb_buffer *buffer) ++{ ++ struct gsb_data_rqsx *rqsx = &buffer->data.rqsx; ++ ++ if (buffer->len < 8) { ++ dev_err(dev, "invalid %s package (len = %d)\n", ++ type, buffer->len); ++ return NULL; ++ } ++ ++ if (rqsx->cdl != buffer->len - 8) { ++ dev_err(dev, "bogus %s package (len = %d, cdl = %d)\n", ++ type, buffer->len, rqsx->cdl); ++ return NULL; ++ } ++ ++ if (rqsx->tid != 0x01) { ++ dev_warn(dev, "unsupported %s package (tid = 0x%02x)\n", ++ type, rqsx->tid); ++ return NULL; ++ } ++ ++ return rqsx; ++} ++ ++static acpi_status ++surfacegen5_san_etwl(struct surfacegen5_san_opreg_context *ctx, struct gsb_buffer *buffer) ++{ ++ struct gsb_data_etwl *etwl = &buffer->data.etwl; ++ ++ if (buffer->len < 3) { ++ dev_err(ctx->dev, "invalid ETWL package (len = %d)\n", buffer->len); ++ return AE_OK; ++ } ++ ++ dev_err(ctx->dev, "ETWL(0x%02x, 0x%02x): %.*s\n", ++ etwl->etw3, etwl->etw4, ++ buffer->len - 3, (char *)etwl->msg); ++ ++ // indicate success ++ buffer->status = 0x00; ++ buffer->len = 0x00; ++ ++ return AE_OK; ++} ++ ++static acpi_status ++surfacegen5_san_rqst(struct surfacegen5_san_opreg_context *ctx, struct gsb_buffer *buffer) ++{ ++ struct gsb_data_rqsx *gsb_rqst = surfacegen5_san_validate_rqsx(ctx->dev, "RQST", buffer); ++ struct surfacegen5_rqst rqst = {}; ++ struct surfacegen5_buf result = {}; ++ int status = 0; ++ int try; ++ ++ if (!gsb_rqst) { ++ return AE_OK; ++ } ++ ++ rqst.tc = gsb_rqst->tc; ++ rqst.iid = gsb_rqst->iid; ++ rqst.cid = gsb_rqst->cid; ++ rqst.snc = gsb_rqst->snc; ++ rqst.cdl = gsb_rqst->cdl; ++ rqst.pld = &gsb_rqst->pld[0]; ++ ++ result.cap = SURFACEGEN5_MAX_RQST_RESPONSE; ++ result.len = 0; ++ result.data = kzalloc(result.cap, GFP_KERNEL); ++ ++ if (!result.data) { ++ return AE_NO_MEMORY; ++ } ++ ++ for (try = 0; try < SG5_RQST_RETRY; try++) { ++ if (try) { ++ dev_warn(ctx->dev, SG5_SAN_RQST_TAG "IO error occured, trying again\n"); ++ } ++ ++ status = surfacegen5_ec_rqst(&rqst, &result); ++ if (status != -EIO) break; ++ } ++ ++ if (!status) { ++ buffer->status = 0x00; ++ buffer->len = result.len + 2; ++ buffer->data.out.status = 0x00; ++ buffer->data.out.len = result.len; ++ memcpy(&buffer->data.out.pld[0], result.data, result.len); ++ ++ } else { ++ dev_err(ctx->dev, SG5_SAN_RQST_TAG "failed with error %d\n", status); ++ buffer->status = 0x00; ++ buffer->len = 0x02; ++ buffer->data.out.status = 0x01; // indicate _SSH error ++ buffer->data.out.len = 0x00; ++ } ++ ++ kfree(result.data); ++ ++ return AE_OK; ++} ++ ++static acpi_status ++surfacegen5_san_rqsg(struct surfacegen5_san_opreg_context *ctx, struct gsb_buffer *buffer) ++{ ++ struct gsb_data_rqsx *rqsg = surfacegen5_san_validate_rqsx(ctx->dev, "RQSG", buffer); ++ ++ if (!rqsg) { ++ return AE_OK; ++ } ++ ++ // TODO: RQSG handler ++ ++ dev_warn(ctx->dev, "unsupported request: RQSG(0x%02x, 0x%02x, 0x%02x)\n", ++ rqsg->tc, rqsg->cid, rqsg->iid); ++ ++ return AE_OK; ++} ++ ++ ++static acpi_status ++surfacegen5_san_opreg_handler(u32 function, acpi_physical_address command, ++ u32 bits, u64 *value64, ++ void *opreg_context, void *region_context) ++{ ++ struct surfacegen5_san_opreg_context *context = opreg_context; ++ struct gsb_buffer *buffer = (struct gsb_buffer *)value64; ++ int accessor_type = (0xFFFF0000 & function) >> 16; ++ ++ if (command != 0) { ++ dev_warn(context->dev, "unsupported command: 0x%02llx\n", command); ++ return AE_OK; ++ } ++ ++ if (accessor_type != ACPI_GSB_ACCESS_ATTRIB_RAW_PROCESS) { ++ dev_err(context->dev, "invalid access type: 0x%02x\n", accessor_type); ++ return AE_OK; ++ } ++ ++ // buffer must have at least contain the command-value ++ if (buffer->len == 0) { ++ dev_err(context->dev, "request-package too small\n"); ++ return AE_OK; ++ } ++ ++ switch (buffer->data.in.cv) { ++ case 0x01: return surfacegen5_san_rqst(context, buffer); ++ case 0x02: return surfacegen5_san_etwl(context, buffer); ++ case 0x03: return surfacegen5_san_rqsg(context, buffer); ++ } ++ ++ dev_warn(context->dev, "unsupported SAN0 request (cv: 0x%02x)\n", buffer->data.in.cv); ++ return AE_OK; ++} ++ ++static int surfacegen5_san_enable_events(struct device *dev) ++{ ++ int status; ++ ++ status = surfacegen5_ec_set_delayed_event_handler( ++ SG5_EVENT_PWR_RQID, surfacegen5_evt_power, ++ surfacegen5_evt_power_delay, dev); ++ if (status) { ++ goto err_san_event_handler_power; ++ } ++ ++ status = surfacegen5_ec_set_event_handler( ++ SG5_EVENT_TEMP_RQID, surfacegen5_evt_thermal, ++ dev); ++ if (status) { ++ goto err_san_event_handler_thermal; ++ } ++ ++ status = surfacegen5_ec_enable_event_source(SG5_EVENT_PWR_TC, 0x01, SG5_EVENT_PWR_RQID); ++ if (status) { ++ goto err_san_event_source_power; ++ } ++ ++ status = surfacegen5_ec_enable_event_source(SG5_EVENT_TEMP_TC, 0x01, SG5_EVENT_TEMP_RQID); ++ if (status) { ++ goto err_san_event_source_thermal; ++ } ++ ++ return 0; ++ ++err_san_event_source_thermal: ++ surfacegen5_ec_disable_event_source(SG5_EVENT_PWR_TC, 0x01, SG5_EVENT_PWR_RQID); ++err_san_event_source_power: ++ surfacegen5_ec_remove_event_handler(SG5_EVENT_TEMP_RQID); ++err_san_event_handler_thermal: ++ surfacegen5_ec_remove_event_handler(SG5_EVENT_PWR_RQID); ++err_san_event_handler_power: ++ return status; ++} ++ ++static void surfacegen5_san_disable_events(void) ++{ ++ surfacegen5_ec_disable_event_source(SG5_EVENT_TEMP_TC, 0x01, SG5_EVENT_TEMP_RQID); ++ surfacegen5_ec_disable_event_source(SG5_EVENT_PWR_TC, 0x01, SG5_EVENT_PWR_RQID); ++ surfacegen5_ec_remove_event_handler(SG5_EVENT_TEMP_RQID); ++ surfacegen5_ec_remove_event_handler(SG5_EVENT_PWR_RQID); ++} ++ ++ ++static int surfacegen5_san_consumers_link(struct platform_device *pdev, ++ const struct surfacegen5_san_acpi_consumer *cons, ++ struct surfacegen5_san_consumers *out) ++{ ++ const struct surfacegen5_san_acpi_consumer *con; ++ struct device_link **links, **link; ++ struct acpi_device *adev; ++ acpi_handle handle; ++ u32 max_links = 0; ++ int status; ++ ++ if (!cons) { ++ return 0; ++ } ++ ++ // count links ++ for (con = cons; con->path; ++con) { ++ max_links += 1; ++ } ++ ++ // allocate ++ links = kzalloc(max_links * sizeof(struct device_link *), GFP_KERNEL); ++ link = &links[0]; ++ ++ if (!links) { ++ return -ENOMEM; ++ } ++ ++ // create links ++ for (con = cons; con->path; ++con) { ++ status = acpi_get_handle(NULL, con->path, &handle); ++ if (status) { ++ if (con->required || status != AE_NOT_FOUND) { ++ status = -ENXIO; ++ goto san_consumers_link_cleanup; ++ } else { ++ continue; ++ } ++ } ++ ++ status = acpi_bus_get_device(handle, &adev); ++ if (status) { ++ goto san_consumers_link_cleanup; ++ } ++ ++ *link = device_link_add(&adev->dev, &pdev->dev, con->flags); ++ if (!(*link)) { ++ status = -EFAULT; ++ goto san_consumers_link_cleanup; ++ } ++ ++ link += 1; ++ } ++ ++ out->num = link - links; ++ out->links = links; ++ ++ return 0; ++ ++san_consumers_link_cleanup: ++ for (link = link - 1; link >= links; --link) { ++ device_link_del(*link); ++ } ++ ++ return status; ++} ++ ++static void surfacegen5_san_consumers_unlink(struct surfacegen5_san_consumers *consumers) { ++ u32 i; ++ ++ if (!consumers) { ++ return; ++ } ++ ++ for (i = 0; i < consumers->num; ++i) { ++ device_link_del(consumers->links[i]); ++ } ++ ++ kfree(consumers->links); ++ ++ consumers->num = 0; ++ consumers->links = NULL; ++} ++ ++static int surfacegen5_acpi_san_probe(struct platform_device *pdev) ++{ ++ const struct surfacegen5_san_acpi_consumer *cons; ++ struct surfacegen5_san_drvdata *drvdata; ++ struct device_link *ec_link; ++ acpi_handle san = ACPI_HANDLE(&pdev->dev); // _SAN device node ++ int status; ++ ++ drvdata = kzalloc(sizeof(struct surfacegen5_san_drvdata), GFP_KERNEL); ++ if (!drvdata) { ++ return -ENOMEM; ++ } ++ ++ /* ++ * Defer probe if the _SSH driver has not set up the controller yet. This ++ * makes sure we do not fail any initial requests (e.g. _STA request without ++ * which the battery does not get set up correctly). Otherwise register as ++ * consumer to set up a device_link. ++ */ ++ ec_link = surfacegen5_ec_consumer_add(&pdev->dev, DL_FLAG_PM_RUNTIME); ++ if (IS_ERR_OR_NULL(ec_link)) { ++ if (PTR_ERR(ec_link) == -ENXIO) { ++ status = -EPROBE_DEFER; ++ } else { ++ status = -EFAULT; ++ } ++ ++ goto err_san_probe_ec_link; ++ } ++ ++ drvdata->ec_link = ec_link; ++ drvdata->opreg_ctx.dev = &pdev->dev; ++ ++ cons = acpi_device_get_match_data(&pdev->dev); ++ status = surfacegen5_san_consumers_link(pdev, cons, &drvdata->consumers); ++ if (status) { ++ goto err_san_probe_consumers; ++ } ++ ++ platform_set_drvdata(pdev, drvdata); ++ ++ status = acpi_install_address_space_handler(san, ++ ACPI_ADR_SPACE_GSBUS, ++ &surfacegen5_san_opreg_handler, ++ NULL, &drvdata->opreg_ctx); ++ ++ if (ACPI_FAILURE(status)) { ++ status = -ENODEV; ++ goto err_san_probe_install_handler; ++ } ++ ++ status = surfacegen5_san_enable_events(&pdev->dev); ++ if (status) { ++ goto err_san_probe_enable_events; ++ } ++ ++ acpi_walk_dep_device_list(san); ++ return 0; ++ ++err_san_probe_enable_events: ++ acpi_remove_address_space_handler(san, ACPI_ADR_SPACE_GSBUS, &surfacegen5_san_opreg_handler); ++err_san_probe_install_handler: ++ platform_set_drvdata(san, NULL); ++ surfacegen5_san_consumers_unlink(&drvdata->consumers); ++err_san_probe_consumers: ++ surfacegen5_ec_consumer_remove(drvdata->ec_link); ++err_san_probe_ec_link: ++ kfree(drvdata); ++ return status; ++} ++ ++static int surfacegen5_acpi_san_remove(struct platform_device *pdev) ++{ ++ struct surfacegen5_san_drvdata *drvdata = platform_get_drvdata(pdev); ++ acpi_handle san = ACPI_HANDLE(&pdev->dev); // _SAN device node ++ acpi_status status = AE_OK; ++ ++ acpi_remove_address_space_handler(san, ACPI_ADR_SPACE_GSBUS, &surfacegen5_san_opreg_handler); ++ surfacegen5_san_disable_events(); ++ ++ surfacegen5_san_consumers_unlink(&drvdata->consumers); ++ surfacegen5_ec_consumer_remove(drvdata->ec_link); ++ kfree(drvdata); ++ ++ platform_set_drvdata(pdev, NULL); ++ return status; ++} ++ ++ ++static const struct surfacegen5_san_acpi_consumer surfacegen5_mshw0091_consumers[] = { ++ { "\\_SB.SRTC", true, DL_FLAG_PM_RUNTIME | DL_FLAG_STATELESS }, ++ { "\\ADP1", true, DL_FLAG_PM_RUNTIME | DL_FLAG_STATELESS }, ++ { "\\_SB.BAT1", true, DL_FLAG_PM_RUNTIME | DL_FLAG_STATELESS }, ++ { "\\_SB.BAT2", false, DL_FLAG_PM_RUNTIME | DL_FLAG_STATELESS }, ++ { }, ++}; ++ ++static const struct acpi_device_id surfacegen5_acpi_san_match[] = { ++ { "MSHW0091", (long unsigned int) surfacegen5_mshw0091_consumers }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(acpi, surfacegen5_acpi_san_match); ++ ++static struct platform_driver surfacegen5_acpi_san = { ++ .probe = surfacegen5_acpi_san_probe, ++ .remove = surfacegen5_acpi_san_remove, ++ .driver = { ++ .name = "surfacegen5_acpi_san", ++ .acpi_match_table = ACPI_PTR(surfacegen5_acpi_san_match), ++ }, ++}; ++ ++#endif /* CONFIG_SURFACE_ACPI_SAN */ ++ ++ ++/************************************************************************* ++ * Virtual HID Framework driver ++ */ ++ ++#ifdef CONFIG_SURFACE_ACPI_VHF ++ ++#define USB_VENDOR_ID_MICROSOFT 0x045e ++#define USB_DEVICE_ID_MS_VHF 0xf001 ++ ++/* ++ * Request ID for VHF events. This value is based on the output of the Surface ++ * EC and should not be changed. ++ */ ++#define SG5_VHF_RQID 0x0001 ++ ++ ++struct surfacegen5_vhf_evtctx { ++ struct device *dev; ++ struct hid_device *hid; ++}; ++ ++struct surfacegen5_vhf_drvdata { ++ struct device_link *ec_link; ++ struct surfacegen5_vhf_evtctx event_ctx; ++}; ++ ++ ++/* ++ * These report descriptors have been extracted from a Surface Book 2. ++ * They seems to be similar enough to be usable on the Surface Laptop. ++ */ ++static const u8 vhf_hid_desc[] = { ++ // keyboard descriptor (event command ID 0x03) ++ 0x05, 0x01, /* Usage Page (Desktop), */ ++ 0x09, 0x06, /* Usage (Keyboard), */ ++ 0xA1, 0x01, /* Collection (Application), */ ++ 0x85, 0x01, /* Report ID (1), */ ++ 0x15, 0x00, /* Logical Minimum (0), */ ++ 0x25, 0x01, /* Logical Maximum (1), */ ++ 0x75, 0x01, /* Report Size (1), */ ++ 0x95, 0x08, /* Report Count (8), */ ++ 0x05, 0x07, /* Usage Page (Keyboard), */ ++ 0x19, 0xE0, /* Usage Minimum (KB Leftcontrol), */ ++ 0x29, 0xE7, /* Usage Maximum (KB Right GUI), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0x75, 0x08, /* Report Size (8), */ ++ 0x95, 0x0A, /* Report Count (10), */ ++ 0x19, 0x00, /* Usage Minimum (None), */ ++ 0x29, 0x91, /* Usage Maximum (KB LANG2), */ ++ 0x26, 0xFF, 0x00, /* Logical Maximum (255), */ ++ 0x81, 0x00, /* Input, */ ++ 0x05, 0x0C, /* Usage Page (Consumer), */ ++ 0x0A, 0xC0, 0x02, /* Usage (02C0h), */ ++ 0xA1, 0x02, /* Collection (Logical), */ ++ 0x1A, 0xC1, 0x02, /* Usage Minimum (02C1h), */ ++ 0x2A, 0xC6, 0x02, /* Usage Maximum (02C6h), */ ++ 0x95, 0x06, /* Report Count (6), */ ++ 0xB1, 0x03, /* Feature (Constant, Variable), */ ++ 0xC0, /* End Collection, */ ++ 0x05, 0x08, /* Usage Page (LED), */ ++ 0x19, 0x01, /* Usage Minimum (01h), */ ++ 0x29, 0x03, /* Usage Maximum (03h), */ ++ 0x75, 0x01, /* Report Size (1), */ ++ 0x95, 0x03, /* Report Count (3), */ ++ 0x25, 0x01, /* Logical Maximum (1), */ ++ 0x91, 0x02, /* Output (Variable), */ ++ 0x95, 0x05, /* Report Count (5), */ ++ 0x91, 0x01, /* Output (Constant), */ ++ 0xC0, /* End Collection, */ ++ ++ // media key descriptor (event command ID 0x04) ++ 0x05, 0x0C, /* Usage Page (Consumer), */ ++ 0x09, 0x01, /* Usage (Consumer Control), */ ++ 0xA1, 0x01, /* Collection (Application), */ ++ 0x85, 0x03, /* Report ID (3), */ ++ 0x75, 0x10, /* Report Size (16), */ ++ 0x15, 0x00, /* Logical Minimum (0), */ ++ 0x26, 0xFF, 0x03, /* Logical Maximum (1023), */ ++ 0x19, 0x00, /* Usage Minimum (00h), */ ++ 0x2A, 0xFF, 0x03, /* Usage Maximum (03FFh), */ ++ 0x81, 0x00, /* Input, */ ++ 0xC0, /* End Collection, */ ++}; ++ ++ ++static int vhf_hid_start(struct hid_device *hid) ++{ ++ hid_dbg(hid, "%s\n", __func__); ++ return 0; ++} ++ ++static void vhf_hid_stop(struct hid_device *hid) ++{ ++ hid_dbg(hid, "%s\n", __func__); ++} ++ ++static int vhf_hid_open(struct hid_device *hid) ++{ ++ hid_dbg(hid, "%s\n", __func__); ++ return 0; ++} ++ ++static void vhf_hid_close(struct hid_device *hid) ++{ ++ hid_dbg(hid, "%s\n", __func__); ++} ++ ++static int vhf_hid_parse(struct hid_device *hid) ++{ ++ return hid_parse_report(hid, (u8 *)vhf_hid_desc, ARRAY_SIZE(vhf_hid_desc)); ++} ++ ++static int vhf_hid_raw_request(struct hid_device *hid, unsigned char reportnum, ++ u8 *buf, size_t len, unsigned char rtype, ++ int reqtype) ++{ ++ hid_dbg(hid, "%s\n", __func__); ++ return 0; ++} ++ ++static int vhf_hid_output_report(struct hid_device *hid, u8 *buf, size_t len) ++{ ++ hid_dbg(hid, "%s\n", __func__); ++ print_hex_dump_debug("report:", DUMP_PREFIX_OFFSET, 16, 1, buf, len, false); ++ ++ return len; ++} ++ ++static struct hid_ll_driver vhf_hid_ll_driver = { ++ .start = vhf_hid_start, ++ .stop = vhf_hid_stop, ++ .open = vhf_hid_open, ++ .close = vhf_hid_close, ++ .parse = vhf_hid_parse, ++ .raw_request = vhf_hid_raw_request, ++ .output_report = vhf_hid_output_report, ++}; ++ ++ ++static struct hid_device *surfacegen5_vhf_create_hid_device(struct platform_device *pdev) ++{ ++ struct hid_device *hid; ++ ++ hid = hid_allocate_device(); ++ if (IS_ERR(hid)) { ++ return hid; ++ } ++ ++ hid->dev.parent = &pdev->dev; ++ ++ hid->bus = BUS_VIRTUAL; ++ hid->vendor = USB_VENDOR_ID_MICROSOFT; ++ hid->product = USB_DEVICE_ID_MS_VHF; ++ ++ hid->ll_driver = &vhf_hid_ll_driver; ++ ++ sprintf(hid->name, "%s", "Microsoft Virtual HID Framework Device"); ++ ++ return hid; ++} ++ ++static int surfacegen5_vhf_event_handler(struct surfacegen5_event *event, void *data) ++{ ++ struct surfacegen5_vhf_evtctx *ctx = (struct surfacegen5_vhf_evtctx *)data; ++ ++ if (event->tc == 0x08 && (event->cid == 0x03 || event->cid == 0x04)) { ++ return hid_input_report(ctx->hid, HID_INPUT_REPORT, event->pld, event->len, 1); ++ } ++ ++ dev_warn(ctx->dev, "unsupported event (tc = %d, cid = %d)\n", event->tc, event->cid); ++ return 0; ++} ++ ++static unsigned long surfacegen5_vhf_event_delay(struct surfacegen5_event *event, void *data) ++{ ++ // high priority immediate execution for keyboard events ++ if (event->tc == 0x08 && (event->cid == 0x03 || event->cid == 0x04)) { ++ return SURFACEGEN5_EVENT_IMMEDIATE; ++ } ++ ++ return 0; ++} ++ ++static int surfacegen5_acpi_vhf_probe(struct platform_device *pdev) ++{ ++ struct surfacegen5_vhf_drvdata *drvdata; ++ struct device_link *ec_link; ++ struct hid_device *hid; ++ int status; ++ ++ drvdata = kzalloc(sizeof(struct surfacegen5_vhf_drvdata), GFP_KERNEL); ++ if (!drvdata) { ++ return -ENOMEM; ++ } ++ ++ // add device link to EC ++ ec_link = surfacegen5_ec_consumer_add(&pdev->dev, DL_FLAG_PM_RUNTIME); ++ if (IS_ERR_OR_NULL(ec_link)) { ++ if (PTR_ERR(ec_link) == -ENXIO) { ++ status = -EPROBE_DEFER; ++ } else { ++ status = -EFAULT; ++ } ++ ++ goto err_probe_ec_link; ++ } ++ ++ hid = surfacegen5_vhf_create_hid_device(pdev); ++ if (IS_ERR(hid)) { ++ status = PTR_ERR(hid); ++ goto err_probe_hid; ++ } ++ ++ status = hid_add_device(hid); ++ if (status) { ++ goto err_add_hid; ++ } ++ ++ drvdata->ec_link = ec_link; ++ drvdata->event_ctx.dev = &pdev->dev; ++ drvdata->event_ctx.hid = hid; ++ ++ platform_set_drvdata(pdev, drvdata); ++ ++ /* ++ * Set event hanlder for VHF events. They seem to be enabled by ++ * default, thus there should be no need to explicitly enable them. ++ */ ++ status = surfacegen5_ec_set_delayed_event_handler( ++ SG5_VHF_RQID, ++ surfacegen5_vhf_event_handler, ++ surfacegen5_vhf_event_delay, ++ &drvdata->event_ctx); ++ if (status) { ++ goto err_add_hid; ++ } ++ ++ return 0; ++ ++err_add_hid: ++ hid_destroy_device(hid); ++ platform_set_drvdata(pdev, NULL); ++err_probe_hid: ++ surfacegen5_ec_consumer_remove(drvdata->ec_link); ++err_probe_ec_link: ++ kfree(drvdata); ++ return status; ++} ++ ++static int surfacegen5_acpi_vhf_remove(struct platform_device *pdev) ++{ ++ struct surfacegen5_vhf_drvdata *drvdata = platform_get_drvdata(pdev); ++ ++ surfacegen5_ec_remove_event_handler(SG5_VHF_RQID); ++ ++ hid_destroy_device(drvdata->event_ctx.hid); ++ surfacegen5_ec_consumer_remove(drvdata->ec_link); ++ kfree(drvdata); ++ ++ platform_set_drvdata(pdev, NULL); ++ return 0; ++} ++ ++ ++static const struct acpi_device_id surfacegen5_acpi_vhf_match[] = { ++ { "MSHW0096" }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(acpi, surfacegen5_acpi_vhf_match); ++ ++static struct platform_driver surfacegen5_acpi_vhf = { ++ .probe = surfacegen5_acpi_vhf_probe, ++ .remove = surfacegen5_acpi_vhf_remove, ++ .driver = { ++ .name = "surfacegen5_acpi_vhf", ++ .acpi_match_table = ACPI_PTR(surfacegen5_acpi_vhf_match), ++ }, ++}; ++ ++#endif /* CONFIG_SURFACE_ACPI_VHF */ ++ ++ ++/************************************************************************* ++ * Module initialization ++ */ ++ ++int __init surface_acpi_init(void) ++{ ++ int status; ++ ++#ifdef CONFIG_SURFACE_ACPI_SSH ++ status = serdev_device_driver_register(&surfacegen5_acpi_ssh); ++ if (status) { ++ goto err_modinit_ssh; ++ } ++#endif /* CONFIG_SURFACE_ACPI_SSH */ ++ ++#ifdef CONFIG_SURFACE_ACPI_SAN ++ status = platform_driver_register(&surfacegen5_acpi_san); ++ if (status) { ++ goto err_modinit_san; ++ } ++#endif /* CONFIG_SURFACE_ACPI_SAN */ ++ ++#ifdef CONFIG_SURFACE_ACPI_VHF ++ status = platform_driver_register(&surfacegen5_acpi_vhf); ++ if (status) { ++ goto err_modinit_vhf; ++ } ++#endif /* CONFIG_SURFACE_ACPI_VHF */ ++ ++ return 0; ++ ++#ifdef CONFIG_SURFACE_ACPI_VHF ++ platform_driver_unregister(&surfacegen5_acpi_vhf); ++err_modinit_vhf: ++#endif /* CONFIG_SURFACE_ACPI_VHF */ ++ ++#ifdef CONFIG_SURFACE_ACPI_SAN ++ platform_driver_unregister(&surfacegen5_acpi_san); ++err_modinit_san: ++#endif /* CONFIG_SURFACE_ACPI_SAN */ ++ ++#ifdef CONFIG_SURFACE_ACPI_SSH ++ serdev_device_driver_unregister(&surfacegen5_acpi_ssh); ++err_modinit_ssh: ++#endif /* CONFIG_SURFACE_ACPI_SSH */ ++ ++ return status; ++} ++ ++void __exit surface_acpi_exit(void) ++{ ++#ifdef CONFIG_SURFACE_ACPI_VHF ++ platform_driver_unregister(&surfacegen5_acpi_vhf); ++#endif /* CONFIG_SURFACE_ACPI_VHF */ ++ ++#ifdef CONFIG_SURFACE_ACPI_SAN ++ platform_driver_unregister(&surfacegen5_acpi_san); ++#endif /* CONFIG_SURFACE_ACPI_SAN */ ++ ++#ifdef CONFIG_SURFACE_ACPI_SSH ++ serdev_device_driver_unregister(&surfacegen5_acpi_ssh); ++#endif /* CONFIG_SURFACE_ACPI_SSH */ ++} ++ ++ ++module_init(surface_acpi_init) ++module_exit(surface_acpi_exit) ++ ++MODULE_AUTHOR("Maximilian Luz "); ++MODULE_DESCRIPTION("ACPI/Platform Drivers for Microsoft Surface Devices"); ++MODULE_LICENSE("GPL v2"); +diff --git a/drivers/tty/serdev/core.c b/drivers/tty/serdev/core.c +index 9e59f4788589..d9f4700722b6 100644 +--- a/drivers/tty/serdev/core.c ++++ b/drivers/tty/serdev/core.c +@@ -466,8 +466,7 @@ static acpi_status acpi_serdev_register_device(struct serdev_controller *ctrl, + struct serdev_device *serdev = NULL; + int err; + +- if (acpi_bus_get_status(adev) || !adev->status.present || +- acpi_device_enumerated(adev)) ++ if (acpi_bus_get_status(adev) || !adev->status.present) + return AE_OK; + + serdev = serdev_device_alloc(ctrl); +@@ -490,6 +489,81 @@ static acpi_status acpi_serdev_register_device(struct serdev_controller *ctrl, + return AE_OK; + } + ++struct acpi_serdev_add_device_from_resource_ctx { ++ acpi_handle ctrl_handle; ++ acpi_handle device_handle; ++ struct serdev_controller *ctrl; ++ struct acpi_device *device; ++}; ++ ++static acpi_status ++acpi_serdev_add_device_from_resource(struct acpi_resource *resource, void *data) ++{ ++ struct acpi_serdev_add_device_from_resource_ctx* ctx = data; ++ struct acpi_resource_source *ctrl_name; ++ acpi_handle ctrl_handle; ++ acpi_status status; ++ ++ if (resource->type != ACPI_RESOURCE_TYPE_SERIAL_BUS) ++ return AE_OK; ++ ++ if (resource->data.common_serial_bus.type != ACPI_RESOURCE_SERIAL_TYPE_UART) ++ return AE_OK; ++ ++ ctrl_name = &resource->data.common_serial_bus.resource_source; ++ if (ctrl_name->string_length == 0 || !ctrl_name->string_ptr) { ++ return AE_OK; ++ } ++ ++ status = acpi_get_handle(ctx->device_handle, ctrl_name->string_ptr, ++ &ctrl_handle); ++ if (ACPI_FAILURE(status)) { ++ return AE_OK; ++ } ++ ++ if (ctrl_handle == ctx->ctrl_handle) { ++ return acpi_serdev_register_device(ctx->ctrl, ctx->device); ++ } ++ ++ return AE_OK; ++} ++ ++static acpi_status ++acpi_serdev_add_devices_from_resources(acpi_handle handle, u32 level, ++ void *data, void **return_value) ++{ ++ struct acpi_serdev_add_device_from_resource_ctx *ctx = data; ++ acpi_status status; ++ ++ ctx->device_handle = handle; ++ ++ status = acpi_bus_get_device(handle, &ctx->device); ++ if (status) return AE_OK; ++ ++ status = acpi_walk_resources(handle, METHOD_NAME__CRS, ++ acpi_serdev_add_device_from_resource, ++ ctx); ++ ++ if (status == AE_NOT_FOUND) ++ return AE_OK; // not finding _CRS is not an error ++ else ++ return status; ++} ++ ++static int ++acpi_serdev_register_devices_from_resources(acpi_handle handle, ++ struct serdev_controller *ctrl) ++{ ++ struct acpi_serdev_add_device_from_resource_ctx ctx = { ++ .ctrl = ctrl, ++ .ctrl_handle = handle, ++ }; ++ ++ return acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, 128, ++ acpi_serdev_add_devices_from_resources, ++ NULL, &ctx, NULL); ++} ++ + static acpi_status acpi_serdev_add_device(acpi_handle handle, u32 level, + void *data, void **return_value) + { +@@ -499,6 +573,9 @@ static acpi_status acpi_serdev_add_device(acpi_handle handle, u32 level, + if (acpi_bus_get_device(handle, &adev)) + return AE_OK; + ++ if (acpi_device_enumerated(adev)) ++ return AE_OK; ++ + return acpi_serdev_register_device(ctrl, adev); + } + +@@ -516,6 +593,15 @@ static int acpi_serdev_register_devices(struct serdev_controller *ctrl) + if (ACPI_FAILURE(status)) + dev_dbg(&ctrl->dev, "failed to enumerate serdev slaves\n"); + ++ if (!ctrl->serdev) { ++ status = acpi_serdev_register_devices_from_resources(handle, ctrl); ++ if (ACPI_FAILURE(status)) { ++ dev_dbg(&ctrl->dev, ++ "failed to register serdev slaves from resources: %x\n", ++ status); ++ } ++ } ++ + if (!ctrl->serdev) + return -ENODEV; + +-- +2.20.1 + diff --git a/patches/4.18/0002-resume-delay.patch b/patches/4.18/0002-resume-delay.patch new file mode 100644 index 000000000..0348025b9 --- /dev/null +++ b/patches/4.18/0002-resume-delay.patch @@ -0,0 +1,63 @@ +From 415511ab8182c8948ed31e38cb7d304c61d53277 Mon Sep 17 00:00:00 2001 +From: qzed +Date: Mon, 24 Dec 2018 14:03:51 +0100 +Subject: [PATCH 2/8] resume-delay + +--- + kernel/power/suspend.c | 11 +++++++++++ + kernel/sysctl.c | 9 +++++++++ + 2 files changed, 20 insertions(+) + +diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c +index 87331565e505..d55f949ee25a 100644 +--- a/kernel/power/suspend.c ++++ b/kernel/power/suspend.c +@@ -520,6 +520,8 @@ int suspend_devices_and_enter(suspend_state_t state) + goto Resume_devices; + } + ++unsigned int resume_delay = 3000; ++ + /** + * suspend_finish - Clean up before finishing the suspend sequence. + * +@@ -528,6 +530,15 @@ int suspend_devices_and_enter(suspend_state_t state) + */ + static void suspend_finish(void) + { ++ if (resume_delay) { ++ /* Give kernel threads a head start, such that usb-storage ++ * can detect devices before syslog attempts to write log ++ * messages from the suspend code. ++ */ ++ thaw_kernel_threads(); ++ pr_debug("PM: Sleeping for %d milliseconds.\n", resume_delay); ++ msleep(resume_delay); ++ } + suspend_thaw_processes(); + pm_notifier_call_chain(PM_POST_SUSPEND); + pm_restore_console(); +diff --git a/kernel/sysctl.c b/kernel/sysctl.c +index 2d9837c0aff4..ac704bf71f45 100644 +--- a/kernel/sysctl.c ++++ b/kernel/sysctl.c +@@ -308,7 +308,16 @@ static int min_extfrag_threshold; + static int max_extfrag_threshold = 1000; + #endif + ++extern unsigned int resume_delay; ++ + static struct ctl_table kern_table[] = { ++ { ++ .procname = "resume_delay", ++ .data = &resume_delay, ++ .maxlen = sizeof(unsigned int), ++ .mode = 0644, ++ .proc_handler = proc_dointvec, ++ }, + { + .procname = "sched_child_runs_first", + .data = &sysctl_sched_child_runs_first, +-- +2.20.1 + diff --git a/patches/4.18/buttons.patch b/patches/4.18/0003-buttons.patch similarity index 96% rename from patches/4.18/buttons.patch rename to patches/4.18/0003-buttons.patch index 4877d305b..fe3d836d5 100644 --- a/patches/4.18/buttons.patch +++ b/patches/4.18/0003-buttons.patch @@ -1,7 +1,7 @@ -From 9c4948b06b2e8d23bbb4d65c7453b6b847d3f237 Mon Sep 17 00:00:00 2001 +From ac9ac2a05180af9e356f2f4d6840b132b1fb45f7 Mon Sep 17 00:00:00 2001 From: qzed -Date: Wed, 19 Sep 2018 19:21:14 +0200 -Subject: [PATCH] Surface Book 2 / Surface Pro 2017 button support +Date: Mon, 24 Dec 2018 14:05:07 +0100 +Subject: [PATCH 3/8] buttons --- drivers/input/misc/soc_button_array.c | 67 +++++++++++++++++++++-- @@ -15,7 +15,7 @@ index 23520df7650f..d74f8c3dd54b 100644 @@ -29,12 +29,20 @@ struct soc_button_info { bool wakeup; }; - + +struct soc_device_data { + /* Button info, may be NULL. */ + struct soc_button_info *button_info; @@ -31,7 +31,7 @@ index 23520df7650f..d74f8c3dd54b 100644 -#define BUTTON_TYPES 2 +#define BUTTON_TYPES 2 +#define SURFACE_METHOD_DSM "_DSM" - + struct soc_button_data { struct platform_device *children[BUTTON_TYPES]; @@ -310,6 +318,7 @@ static int soc_button_probe(struct platform_device *pdev) @@ -45,7 +45,7 @@ index 23520df7650f..d74f8c3dd54b 100644 @@ -320,12 +329,20 @@ static int soc_button_probe(struct platform_device *pdev) if (!id) return -ENODEV; - + - if (!id->driver_data) { + device_data = (struct soc_device_data *)id->driver_data; + if (device_data && device_data->check) { @@ -64,21 +64,21 @@ index 23520df7650f..d74f8c3dd54b 100644 - } else { - button_info = (struct soc_button_info *)id->driver_data; } - + error = gpiod_count(dev, NULL); @@ -357,7 +374,7 @@ static int soc_button_probe(struct platform_device *pdev) if (!priv->children[0] && !priv->children[1]) return -ENODEV; - + - if (!id->driver_data) + if (!device_data || !device_data->button_info) devm_kfree(dev, button_info); - + return 0; @@ -377,9 +394,47 @@ static struct soc_button_info soc_button_PNP0C40[] = { { } }; - + +static struct soc_device_data soc_device_PNP0C40 = { + .button_info = soc_button_PNP0C40, + .check = NULL, @@ -123,7 +123,7 @@ index 23520df7650f..d74f8c3dd54b 100644 + { "MSHW0040", (unsigned long)&soc_device_MSHW0040 }, { } }; - + diff --git a/drivers/platform/x86/surfacepro3_button.c b/drivers/platform/x86/surfacepro3_button.c index 1b491690ce07..006c94eda7be 100644 --- a/drivers/platform/x86/surfacepro3_button.c @@ -134,12 +134,12 @@ index 1b491690ce07..006c94eda7be 100644 #define SURFACE_BUTTON_OBJ_NAME "VGBI" +#define SURFACE_METHOD_DSM "_DSM" #define SURFACE_BUTTON_DEVICE_NAME "Surface Pro 3/4 Buttons" - + #define SURFACE_BUTTON_NOTIFY_TABLET_MODE 0xc8 @@ -158,6 +159,14 @@ static int surface_button_add(struct acpi_device *device) strlen(SURFACE_BUTTON_OBJ_NAME))) return -ENODEV; - + + /* + * Surface Pro 4 and Surface Book 2 / Surface Pro 2017 use the same device + * ID (MSHW0040) for the power/volume buttons. Make sure this is the right @@ -151,6 +151,6 @@ index 1b491690ce07..006c94eda7be 100644 button = kzalloc(sizeof(struct surface_button), GFP_KERNEL); if (!button) return -ENOMEM; --- -2.19.0 +-- +2.20.1 diff --git a/patches/4.18/cameras.patch b/patches/4.18/0004-cameras.patch similarity index 98% rename from patches/4.18/cameras.patch rename to patches/4.18/0004-cameras.patch index 4dcce1e25..bd8df99ad 100644 --- a/patches/4.18/cameras.patch +++ b/patches/4.18/0004-cameras.patch @@ -1,3 +1,25 @@ +From ddc414a8b8bb0df0763eb793019f5bc616e142bf Mon Sep 17 00:00:00 2001 +From: qzed +Date: Mon, 24 Dec 2018 14:08:40 +0100 +Subject: [PATCH 4/8] cameras + +--- + drivers/media/usb/uvc/uvc_driver.c | 40 + + drivers/staging/Makefile | 1 + + drivers/staging/ov5693/Kconfig | 10 + + drivers/staging/ov5693/Makefile | 5 + + drivers/staging/ov5693/ad5823.c | 218 +++++ + drivers/staging/ov5693/ad5823.h | 90 ++ + drivers/staging/ov5693/ov5693.c | 1461 ++++++++++++++++++++++++++++ + drivers/staging/ov5693/ov5693.h | 848 ++++++++++++++++ + 8 files changed, 2673 insertions(+) + create mode 100644 drivers/staging/ov5693/Kconfig + create mode 100644 drivers/staging/ov5693/Makefile + create mode 100644 drivers/staging/ov5693/ad5823.c + create mode 100644 drivers/staging/ov5693/ad5823.h + create mode 100644 drivers/staging/ov5693/ov5693.c + create mode 100644 drivers/staging/ov5693/ov5693.h + diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c index 8e138201330f..db38a76af80b 100644 --- a/drivers/media/usb/uvc/uvc_driver.c @@ -60,10 +82,10 @@ index e84959a8a684..6a78734cfc5a 100644 +obj-$(CONFIG_VIDEO_OV5693) += ov5693/ diff --git a/drivers/staging/ov5693/Kconfig b/drivers/staging/ov5693/Kconfig new file mode 100644 -index 000000000000..9fb1bffbe9b3 +index 000000000000..96000f112c4d --- /dev/null +++ b/drivers/staging/ov5693/Kconfig -@@ -0,0 +1,11 @@ +@@ -0,0 +1,10 @@ +config VIDEO_OV5693 + tristate "Omnivision ov5693 sensor support" + depends on I2C && VIDEO_V4L2 @@ -74,7 +96,6 @@ index 000000000000..9fb1bffbe9b3 + ov5693 is video camera sensor. + + It currently only works with the atomisp driver. -+ diff --git a/drivers/staging/ov5693/Makefile b/drivers/staging/ov5693/Makefile new file mode 100644 index 000000000000..d8a63faa591f @@ -88,10 +109,10 @@ index 000000000000..d8a63faa591f +ccflags-y += -Werror diff --git a/drivers/staging/ov5693/ad5823.c b/drivers/staging/ov5693/ad5823.c new file mode 100644 -index 000000000000..fcb9f5b70f9f +index 000000000000..7c34c36e77e5 --- /dev/null +++ b/drivers/staging/ov5693/ad5823.c -@@ -0,0 +1,219 @@ +@@ -0,0 +1,218 @@ +#include +#include +#include @@ -310,7 +331,6 @@ index 000000000000..fcb9f5b70f9f + ad5823_dev.platform_data = camera_get_af_platform_data(); + return ad5823_dev.platform_data ? 0 : -ENODEV; +} -+ diff --git a/drivers/staging/ov5693/ad5823.h b/drivers/staging/ov5693/ad5823.h new file mode 100644 index 000000000000..8b046c31f3af @@ -2728,3 +2748,6 @@ index 000000000000..79aef69666e8 + .q_focus_abs = ad5823_q_focus_abs, +}; +#endif +-- +2.20.1 + diff --git a/patches/4.18/ipts.patch b/patches/4.18/0005-ipts.patch similarity index 97% rename from patches/4.18/ipts.patch rename to patches/4.18/0005-ipts.patch index f9d3808eb..98a199b55 100644 --- a/patches/4.18/ipts.patch +++ b/patches/4.18/0005-ipts.patch @@ -1,3 +1,74 @@ +From f2a58519921430701dc3fc4dca924e85e6c2d883 Mon Sep 17 00:00:00 2001 +From: qzed +Date: Mon, 24 Dec 2018 14:14:01 +0100 +Subject: [PATCH 5/8] ipts + +--- + drivers/gpu/drm/i915/Makefile | 3 + + drivers/gpu/drm/i915/i915_drv.c | 7 + + drivers/gpu/drm/i915/i915_drv.h | 3 + + drivers/gpu/drm/i915/i915_gem_context.c | 12 + + drivers/gpu/drm/i915/i915_irq.c | 7 +- + drivers/gpu/drm/i915/i915_params.c | 5 +- + drivers/gpu/drm/i915/i915_params.h | 5 +- + drivers/gpu/drm/i915/intel_dp.c | 4 +- + drivers/gpu/drm/i915/intel_guc.h | 1 + + drivers/gpu/drm/i915/intel_guc_submission.c | 79 +- + drivers/gpu/drm/i915/intel_guc_submission.h | 4 + + drivers/gpu/drm/i915/intel_ipts.c | 627 +++++++++++ + drivers/gpu/drm/i915/intel_ipts.h | 34 + + drivers/gpu/drm/i915/intel_lrc.c | 11 +- + drivers/gpu/drm/i915/intel_lrc.h | 8 + + drivers/gpu/drm/i915/intel_panel.c | 7 + + drivers/hid/hid-multitouch.c | 32 +- + drivers/misc/Kconfig | 1 + + drivers/misc/Makefile | 1 + + drivers/misc/ipts/Kconfig | 9 + + drivers/misc/ipts/Makefile | 13 + + drivers/misc/ipts/ipts-binary-spec.h | 118 +++ + drivers/misc/ipts/ipts-dbgfs.c | 152 +++ + drivers/misc/ipts/ipts-gfx.c | 184 ++++ + drivers/misc/ipts/ipts-gfx.h | 24 + + drivers/misc/ipts/ipts-hid.c | 456 ++++++++ + drivers/misc/ipts/ipts-hid.h | 34 + + drivers/misc/ipts/ipts-kernel.c | 1050 +++++++++++++++++++ + drivers/misc/ipts/ipts-kernel.h | 23 + + drivers/misc/ipts/ipts-mei-msgs.h | 585 +++++++++++ + drivers/misc/ipts/ipts-mei.c | 282 +++++ + drivers/misc/ipts/ipts-msg-handler.c | 431 ++++++++ + drivers/misc/ipts/ipts-msg-handler.h | 32 + + drivers/misc/ipts/ipts-resource.c | 277 +++++ + drivers/misc/ipts/ipts-resource.h | 30 + + drivers/misc/ipts/ipts-sensor-regs.h | 700 +++++++++++++ + drivers/misc/ipts/ipts-state.h | 29 + + drivers/misc/ipts/ipts.h | 200 ++++ + drivers/misc/mei/hw-me-regs.h | 1 + + drivers/misc/mei/pci-me.c | 1 + + include/linux/intel_ipts_if.h | 75 ++ + 41 files changed, 5532 insertions(+), 25 deletions(-) + create mode 100644 drivers/gpu/drm/i915/intel_ipts.c + create mode 100644 drivers/gpu/drm/i915/intel_ipts.h + create mode 100644 drivers/misc/ipts/Kconfig + create mode 100644 drivers/misc/ipts/Makefile + create mode 100644 drivers/misc/ipts/ipts-binary-spec.h + create mode 100644 drivers/misc/ipts/ipts-dbgfs.c + create mode 100644 drivers/misc/ipts/ipts-gfx.c + create mode 100644 drivers/misc/ipts/ipts-gfx.h + create mode 100644 drivers/misc/ipts/ipts-hid.c + create mode 100644 drivers/misc/ipts/ipts-hid.h + create mode 100644 drivers/misc/ipts/ipts-kernel.c + create mode 100644 drivers/misc/ipts/ipts-kernel.h + create mode 100644 drivers/misc/ipts/ipts-mei-msgs.h + create mode 100644 drivers/misc/ipts/ipts-mei.c + create mode 100644 drivers/misc/ipts/ipts-msg-handler.c + create mode 100644 drivers/misc/ipts/ipts-msg-handler.h + create mode 100644 drivers/misc/ipts/ipts-resource.c + create mode 100644 drivers/misc/ipts/ipts-resource.h + create mode 100644 drivers/misc/ipts/ipts-sensor-regs.h + create mode 100644 drivers/misc/ipts/ipts-state.h + create mode 100644 drivers/misc/ipts/ipts.h + create mode 100644 include/linux/intel_ipts_if.h + diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 4c6adae23e18..1171fbd3a823 100644 --- a/drivers/gpu/drm/i915/Makefile @@ -13,7 +84,7 @@ index 4c6adae23e18..1171fbd3a823 100644 i915-$(CONFIG_DRM_I915_CAPTURE_ERROR) += i915_gpu_error.o i915-$(CONFIG_DRM_I915_SELFTEST) += \ diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c -index 9c449b8d8eab..d5d91d196627 100644 +index 015f9e93419d..4ecb9b824fc1 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -53,6 +53,7 @@ @@ -34,7 +105,7 @@ index 9c449b8d8eab..d5d91d196627 100644 return 0; cleanup_gem: -@@ -1441,6 +1445,9 @@ void i915_driver_unload(struct drm_device *dev) +@@ -1440,6 +1444,9 @@ void i915_driver_unload(struct drm_device *dev) struct drm_i915_private *dev_priv = to_i915(dev); struct pci_dev *pdev = dev_priv->drm.pdev; @@ -45,10 +116,10 @@ index 9c449b8d8eab..d5d91d196627 100644 if (i915_gem_suspend(dev_priv)) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h -index 71e1aa54f774..62686739ff57 100644 +index 7c22fac3aa04..8cd24da0c6ea 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h -@@ -3230,6 +3230,9 @@ void i915_gem_object_do_bit_17_swizzle(struct drm_i915_gem_object *obj, +@@ -3222,6 +3222,9 @@ void i915_gem_object_do_bit_17_swizzle(struct drm_i915_gem_object *obj, void i915_gem_object_save_bit_17_swizzle(struct drm_i915_gem_object *obj, struct sg_table *pages); @@ -114,7 +185,7 @@ index c16cb025755e..8fb9160d013b 100644 GT_RENDER_USER_INTERRUPT << GEN8_BCS_IRQ_SHIFT | GT_CONTEXT_SWITCH_INTERRUPT << GEN8_BCS_IRQ_SHIFT, diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c -index 66ea3552c63e..4f54d74febc8 100644 +index 66ea3552c63e..b256e8a900af 100644 --- a/drivers/gpu/drm/i915/i915_params.c +++ b/drivers/gpu/drm/i915/i915_params.c @@ -152,7 +152,10 @@ i915_param_named_unsafe(edp_vswing, int, 0400, @@ -130,7 +201,7 @@ index 66ea3552c63e..4f54d74febc8 100644 i915_param_named(guc_log_level, int, 0400, "GuC firmware logging level. Requires GuC to be loaded. " diff --git a/drivers/gpu/drm/i915/i915_params.h b/drivers/gpu/drm/i915/i915_params.h -index 6684025b7af8..f7f0a63a87e5 100644 +index 6684025b7af8..ca1128dcebca 100644 --- a/drivers/gpu/drm/i915/i915_params.h +++ b/drivers/gpu/drm/i915/i915_params.h @@ -47,7 +47,7 @@ struct drm_printer; @@ -153,10 +224,10 @@ index 6684025b7af8..f7f0a63a87e5 100644 #define MEMBER(T, member, ...) T member; struct i915_params { diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c -index 16faea30114a..e5c1e24a6072 100644 +index 5d6517d37236..0119a4663071 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c -@@ -2601,8 +2601,8 @@ void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode) +@@ -2631,8 +2631,8 @@ void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode) return; if (mode != DRM_MODE_DPMS_ON) { @@ -180,7 +251,7 @@ index f1265e122d30..1303090a4bd8 100644 struct guc_preempt_work preempt_work[I915_NUM_ENGINES]; struct workqueue_struct *preempt_wq; diff --git a/drivers/gpu/drm/i915/intel_guc_submission.c b/drivers/gpu/drm/i915/intel_guc_submission.c -index 2feb65096966..1b7b8dc27a28 100644 +index 2feb65096966..4f8f3845bbe9 100644 --- a/drivers/gpu/drm/i915/intel_guc_submission.c +++ b/drivers/gpu/drm/i915/intel_guc_submission.c @@ -94,6 +94,7 @@ static inline bool is_high_priority(struct intel_guc_client *client) @@ -191,7 +262,7 @@ index 2feb65096966..1b7b8dc27a28 100644 unsigned long offset; unsigned long end; u16 id; -@@ -106,11 +107,16 @@ static int reserve_doorbell(struct intel_guc_client *client) +@@ -106,10 +107,15 @@ static int reserve_doorbell(struct intel_guc_client *client) * priority contexts, the second half for high-priority ones. */ offset = 0; @@ -201,17 +272,16 @@ index 2feb65096966..1b7b8dc27a28 100644 - end += offset; + if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) { + end = GUC_NUM_DOORBELLS; - } ++ } + else { + end = GUC_NUM_DOORBELLS/2; + if (is_high_priority(client)) { + offset = end; + end += offset; + } -+ } + } id = find_next_zero_bit(client->guc->doorbell_bitmap, end, offset); - if (id == end) @@ -355,8 +361,14 @@ static void guc_stage_desc_init(struct intel_guc *guc, desc = __get_stage_desc(client); memset(desc, 0, sizeof(*desc)); @@ -986,7 +1056,7 @@ index 000000000000..a6965d102417 + +#endif //_INTEL_IPTS_H_ diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c -index 7c4c8fb1dae4..88cab775a4d2 100644 +index 0328ee704ee5..5be61a9a7233 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -163,8 +163,6 @@ @@ -998,7 +1068,7 @@ index 7c4c8fb1dae4..88cab775a4d2 100644 static void execlists_init_reg_state(u32 *reg_state, struct i915_gem_context *ctx, struct intel_engine_cs *engine, -@@ -1345,7 +1343,7 @@ static int __context_pin(struct i915_gem_context *ctx, struct i915_vma *vma) +@@ -1357,7 +1355,7 @@ static int __context_pin(struct i915_gem_context *ctx, struct i915_vma *vma) return i915_vma_pin(vma, 0, GEN8_LR_CONTEXT_ALIGN, flags); } @@ -1007,7 +1077,7 @@ index 7c4c8fb1dae4..88cab775a4d2 100644 execlists_context_pin(struct intel_engine_cs *engine, struct i915_gem_context *ctx) { -@@ -1399,7 +1397,7 @@ execlists_context_pin(struct intel_engine_cs *engine, +@@ -1411,7 +1409,7 @@ execlists_context_pin(struct intel_engine_cs *engine, return ERR_PTR(ret); } @@ -1016,7 +1086,7 @@ index 7c4c8fb1dae4..88cab775a4d2 100644 struct i915_gem_context *ctx) { struct intel_context *ce = to_intel_context(ctx, engine); -@@ -2364,6 +2362,9 @@ int logical_render_ring_init(struct intel_engine_cs *engine) +@@ -2376,6 +2374,9 @@ int logical_render_ring_init(struct intel_engine_cs *engine) logical_ring_setup(engine); @@ -1026,7 +1096,7 @@ index 7c4c8fb1dae4..88cab775a4d2 100644 if (HAS_L3_DPF(dev_priv)) engine->irq_keep_mask |= GT_RENDER_L3_PARITY_ERROR_INTERRUPT; -@@ -2628,7 +2629,7 @@ populate_lr_context(struct i915_gem_context *ctx, +@@ -2640,7 +2641,7 @@ populate_lr_context(struct i915_gem_context *ctx, return ret; } @@ -1085,7 +1155,7 @@ index b443278e569c..4e44ae7c3387 100644 static void pch_enable_backlight(const struct intel_crtc_state *crtc_state, diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c -index 45968f7970f8..a0e053c4dc1c 100644 +index 15c934ef6b18..468710ac7693 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -151,6 +151,7 @@ struct mt_device { @@ -1153,7 +1223,7 @@ index 45968f7970f8..a0e053c4dc1c 100644 /* let hid-core decide for the others */ return 0; -@@ -1315,6 +1330,7 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) +@@ -1327,6 +1342,7 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) suffix = "Pen"; /* force BTN_STYLUS to allow tablet matching in udev */ __set_bit(BTN_STYLUS, hi->input->keybit); @@ -1161,7 +1231,7 @@ index 45968f7970f8..a0e053c4dc1c 100644 } } -@@ -1330,12 +1346,13 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) +@@ -1342,12 +1358,13 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) /* already handled by hid core */ break; case HID_DG_TOUCHSCREEN: @@ -1176,7 +1246,7 @@ index 45968f7970f8..a0e053c4dc1c 100644 break; case HID_VD_ASUS_CUSTOM_MEDIA_KEYS: suffix = "Custom Media Keys"; -@@ -1452,6 +1469,7 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) +@@ -1464,6 +1481,7 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) td->cc_index = -1; td->scantime_index = -1; td->mt_report_id = -1; @@ -1746,7 +1816,7 @@ index 000000000000..03a5f3551ddf +#endif // _IPTS_GFX_H_ diff --git a/drivers/misc/ipts/ipts-hid.c b/drivers/misc/ipts/ipts-hid.c new file mode 100644 -index 000000000000..3b3be6177648 +index 000000000000..e85844dc1158 --- /dev/null +++ b/drivers/misc/ipts/ipts-hid.c @@ -0,0 +1,456 @@ @@ -2158,7 +2228,7 @@ index 000000000000..3b3be6177648 + err_payload->code[2], + err_payload->code[3], + err_payload->string); -+ ++ + break; + } + default: @@ -2248,7 +2318,7 @@ index 000000000000..f1b22c912df7 +#endif /* _IPTS_HID_H_ */ diff --git a/drivers/misc/ipts/ipts-kernel.c b/drivers/misc/ipts/ipts-kernel.c new file mode 100644 -index 000000000000..ca5e24ce579e +index 000000000000..86fd359d2eed --- /dev/null +++ b/drivers/misc/ipts/ipts-kernel.c @@ -0,0 +1,1050 @@ @@ -2526,7 +2596,7 @@ index 000000000000..ca5e24ce579e + return -EINVAL; + + ipts_dbg(ipts, "cmd buf size = %d\n", cmd->size); -+ ++ + num_of_parallels = ipts_get_num_of_parallel_buffers(ipts); + /* command buffers are located after the other allocations */ + cmdbuf_idx = num_of_parallels * alloc_info->num_of_allocations; @@ -2598,7 +2668,7 @@ index 000000000000..ca5e24ce579e + int buf_idx, num_of_alloc; + u32 buf_size, flags, io_buf_type; + bool initialize; -+ ++ + parsed = parse_info->parsed; + size = parse_info->size; + bin_data = parse_info->data; @@ -2611,7 +2681,7 @@ index 000000000000..ca5e24ce579e + + ipts_dbg(ipts, "number of resources %u\n", res_list->num); + for (i = 0; i < res_list->num; i++) { -+ initialize = false; ++ initialize = false; + io_buf_type = 0; + flags = 0; + @@ -2792,7 +2862,7 @@ index 000000000000..ca5e24ce579e + if(alloc_info->buffs[buf_idx].buf != NULL) { + gtt_offset = (u32)(u64) + alloc_info->buffs[buf_idx].buf->gfx_addr; -+ } ++ } + gtt_offset += patch[i].alloc_offset; + + batch += patch[i].patch_offset; @@ -2816,7 +2886,7 @@ index 000000000000..ca5e24ce579e + u8 *wi_data; + int size, parsed, hdr_size, wi_size; + int i, batch_offset; -+ ++ + parsed = parse_info->parsed; + size = parse_info->size; + bin_guc_wq = (ipts_bin_guc_wq_info_t *)&parse_info->data[parsed]; @@ -2861,7 +2931,7 @@ index 000000000000..ca5e24ce579e + bin_buffer_t *bin_buf; + int wq_size, wi_size, parallel_idx, cmd_idx, k_idx, iter_size; + int i, num_of_parallels, batch_offset, k_num, total_workload; -+ ++ + wq_addr = (u8*)ipts->resource.wq_info.wq_addr; + wq_size = ipts->resource.wq_info.wq_size; + num_of_parallels = ipts_get_num_of_parallel_buffers(ipts); @@ -2885,7 +2955,7 @@ index 000000000000..ca5e24ce579e + batch_offset = kernel->guc_wq_item->batch_offset; + wi_size = kernel->guc_wq_item->size; + wi_data = &kernel->guc_wq_item->data[0]; -+ ++ + cmd_idx = wl[parallel_idx].cmdbuf_index; + bin_buf = &alloc_info->buffs[cmd_idx]; + @@ -3028,38 +3098,38 @@ index 000000000000..ca5e24ce579e + + ret = bin_read_allocation_list(ipts, parse_info, alloc_info); + if (ret) { -+ ipts_dbg(ipts, "error read_allocation_list\n"); ++ ipts_dbg(ipts, "error read_allocation_list\n"); + goto setup_error; + } + + ret = bin_read_cmd_buffer(ipts, parse_info, alloc_info, wl); + if (ret) { -+ ipts_dbg(ipts, "error read_cmd_buffer\n"); ++ ipts_dbg(ipts, "error read_cmd_buffer\n"); + goto setup_error; + } + + ret = bin_read_res_list(ipts, parse_info, alloc_info, wl); + if (ret) { -+ ipts_dbg(ipts, "error read_res_list\n"); ++ ipts_dbg(ipts, "error read_res_list\n"); + goto setup_error; + } + + ret = bin_read_patch_list(ipts, parse_info, alloc_info, wl); + if (ret) { -+ ipts_dbg(ipts, "error read_patch_list\n"); ++ ipts_dbg(ipts, "error read_patch_list\n"); + goto setup_error; + } + + ret = bin_read_guc_wq_item(ipts, parse_info, &guc_wq_item); + if (ret) { -+ ipts_dbg(ipts, "error read_guc_workqueue\n"); ++ ipts_dbg(ipts, "error read_guc_workqueue\n"); + goto setup_error; + } + + memset(&bufid_patch, 0, sizeof(bufid_patch)); + ret = bin_read_bufid_patch(ipts, parse_info, &bufid_patch); + if (ret) { -+ ipts_dbg(ipts, "error read_bufid_patch\n"); ++ ipts_dbg(ipts, "error read_bufid_patch\n"); + goto setup_error; + } + @@ -3069,7 +3139,7 @@ index 000000000000..ca5e24ce579e + kernel->guc_wq_item = guc_wq_item; + memcpy(&kernel->bufid_patch, &bufid_patch, sizeof(bufid_patch)); + -+ return 0; ++ return 0; + +setup_error: + vfree(guc_wq_item); @@ -3198,16 +3268,16 @@ index 000000000000..ca5e24ce579e + } + + ipts_set_wq_item_size(ipts, total_workload); -+ ++ + ret = bin_setup_guc_workqueue(ipts, kernel_list); + if (ret) { -+ ipts_dbg(ipts, "error setup_guc_workqueue\n"); ++ ipts_dbg(ipts, "error setup_guc_workqueue\n"); + goto error_exit; + } + + ret = bin_setup_bufid_buffer(ipts, kernel_list); + if (ret) { -+ ipts_dbg(ipts, "error setup_lastbubmit_buffer\n"); ++ ipts_dbg(ipts, "error setup_lastbubmit_buffer\n"); + goto error_exit; + } + @@ -3250,7 +3320,7 @@ index 000000000000..ca5e24ce579e + for (k_idx = 0; k_idx < k_num; k_idx++) { + unload_kernel(ipts, kernel); + kernel++; -+ } ++ } + + ipts_unmap_buffer(ipts, kernel_list->bufid_buf); + @@ -3924,7 +3994,7 @@ index 000000000000..8ca146800a47 +#endif // _IPTS_MEI_MSGS_H_ diff --git a/drivers/misc/ipts/ipts-mei.c b/drivers/misc/ipts/ipts-mei.c new file mode 100644 -index 000000000000..39667e75dafd +index 000000000000..199e49cb8d70 --- /dev/null +++ b/drivers/misc/ipts/ipts-mei.c @@ -0,0 +1,282 @@ @@ -4152,7 +4222,7 @@ index 000000000000..39667e75dafd + +disable_mei : + mei_cldev_disable(cldev); -+ ++ + return ret; +} + @@ -4212,7 +4282,7 @@ index 000000000000..39667e75dafd +MODULE_LICENSE("GPL"); diff --git a/drivers/misc/ipts/ipts-msg-handler.c b/drivers/misc/ipts/ipts-msg-handler.c new file mode 100644 -index 000000000000..1396ecc7197f +index 000000000000..8b214f975c03 --- /dev/null +++ b/drivers/misc/ipts/ipts-msg-handler.c @@ -0,0 +1,431 @@ @@ -4374,7 +4444,7 @@ index 000000000000..1396ecc7197f + + if (old_state == IPTS_STA_RAW_DATA_STARTED || + old_state == IPTS_STA_HID_STARTED) { -+ ipts_free_default_resource(ipts); ++ ipts_free_default_resource(ipts); + ipts_free_raw_data_resource(ipts); + + return; @@ -4390,7 +4460,7 @@ index 000000000000..1396ecc7197f + ipts_stop(ipts); + + ipts->retry++; -+ if (ipts->retry == IPTS_MAX_RETRY && ++ if (ipts->retry == IPTS_MAX_RETRY && + ipts->sensor_mode == TOUCH_SENSOR_MODE_RAW_DATA) { + /* try with HID mode */ + ipts->sensor_mode = TOUCH_SENSOR_MODE_HID; @@ -4649,7 +4719,7 @@ index 000000000000..1396ecc7197f +} diff --git a/drivers/misc/ipts/ipts-msg-handler.h b/drivers/misc/ipts/ipts-msg-handler.h new file mode 100644 -index 000000000000..b8e27d30c63e +index 000000000000..15038814dfec --- /dev/null +++ b/drivers/misc/ipts/ipts-msg-handler.h @@ -0,0 +1,32 @@ @@ -4677,7 +4747,7 @@ index 000000000000..b8e27d30c63e +void ipts_stop(ipts_info_t *ipts); +int ipts_switch_sensor_mode(ipts_info_t *ipts, int new_sensor_mode); +int ipts_handle_resp(ipts_info_t *ipts, touch_sensor_msg_m2h_t *m2h_msg, -+ u32 msg_len); ++ u32 msg_len); +int ipts_handle_processed_data(ipts_info_t *ipts); +int ipts_send_feedback(ipts_info_t *ipts, int buffer_idx, u32 transaction_id); +int ipts_send_sensor_quiesce_io_cmd(ipts_info_t *ipts); @@ -6056,3 +6126,6 @@ index 000000000000..f329bbfb8079 +void intel_ipts_disconnect(uint64_t gfx_handle); + +#endif // INTEL_IPTS_IF_H +-- +2.20.1 + diff --git a/patches/4.18/0006-hid.patch b/patches/4.18/0006-hid.patch new file mode 100644 index 000000000..068b21910 --- /dev/null +++ b/patches/4.18/0006-hid.patch @@ -0,0 +1,144 @@ +From 756ee28254567d058b3f671451cf2b9652cf88db Mon Sep 17 00:00:00 2001 +From: qzed +Date: Mon, 24 Dec 2018 14:19:55 +0100 +Subject: [PATCH 6/8] hid + +--- + drivers/hid/hid-ids.h | 20 ++++++++++---- + drivers/hid/hid-microsoft.c | 3 ++- + drivers/hid/hid-multitouch.c | 52 ++++++++++++++++++++++++++++++++++++ + drivers/hid/hid-quirks.c | 10 +++++++ + 4 files changed, 79 insertions(+), 6 deletions(-) + +diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h +index ae5b72269e27..c7ec848f630a 100644 +--- a/drivers/hid/hid-ids.h ++++ b/drivers/hid/hid-ids.h +@@ -792,11 +792,21 @@ + #define USB_DEVICE_ID_MS_DIGITAL_MEDIA_3KV1 0x0732 + #define USB_DEVICE_ID_MS_DIGITAL_MEDIA_600 0x0750 + #define USB_DEVICE_ID_MS_COMFORT_MOUSE_4500 0x076c +-#define USB_DEVICE_ID_MS_COMFORT_KEYBOARD 0x00e3 +-#define USB_DEVICE_ID_MS_SURFACE_PRO_2 0x0799 +-#define USB_DEVICE_ID_MS_TOUCH_COVER_2 0x07a7 +-#define USB_DEVICE_ID_MS_TYPE_COVER_2 0x07a9 +-#define USB_DEVICE_ID_MS_POWER_COVER 0x07da ++#define USB_DEVICE_ID_MS_COMFORT_KEYBOARD 0x00e3 ++#define USB_DEVICE_ID_MS_SURFACE_PRO_2 0x0799 ++#define USB_DEVICE_ID_MS_TOUCH_COVER_2 0x07a7 ++#define USB_DEVICE_ID_MS_TYPE_COVER_2 0x07a9 ++#define USB_DEVICE_ID_MS_TYPE_COVER_3 0x07de ++#define USB_DEVICE_ID_MS_TYPE_COVER_PRO_3 0x07dc ++#define USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_1 0x07de ++#define USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_2 0x07e2 ++#define USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP 0x07dd ++#define USB_DEVICE_ID_MS_TYPE_COVER_PRO_4 0x07e8 ++#define USB_DEVICE_ID_MS_TYPE_COVER_PRO_4_1 0x07e4 ++#define USB_DEVICE_ID_MS_SURFACE_BOOK 0x07cd ++#define USB_DEVICE_ID_MS_SURFACE_BOOK_2 0x0922 ++#define USB_DEVICE_ID_MS_SURFACE_VHF 0xf001 ++#define USB_DEVICE_ID_MS_POWER_COVER 0x07da + + #define USB_VENDOR_ID_MOJO 0x8282 + #define USB_DEVICE_ID_RETRO_ADAPTER 0x3201 +diff --git a/drivers/hid/hid-microsoft.c b/drivers/hid/hid-microsoft.c +index 96e7d3231d2f..36f13a867f0f 100644 +--- a/drivers/hid/hid-microsoft.c ++++ b/drivers/hid/hid-microsoft.c +@@ -278,7 +278,8 @@ static const struct hid_device_id ms_devices[] = { + .driver_data = MS_HIDINPUT }, + { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_COMFORT_KEYBOARD), + .driver_data = MS_ERGONOMY}, +- ++ { HID_DEVICE(BUS_VIRTUAL, 0, USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_SURFACE_VHF), ++ .driver_data = MS_HIDINPUT}, + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_BT), + .driver_data = MS_PRESENTER }, + { } +diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c +index 468710ac7693..130fc1432bc2 100644 +--- a/drivers/hid/hid-multitouch.c ++++ b/drivers/hid/hid-multitouch.c +@@ -1769,6 +1769,58 @@ static const struct hid_device_id mt_devices[] = { + HID_USB_DEVICE(USB_VENDOR_ID_LG, + USB_DEVICE_ID_LG_MELFAS_MT) }, + ++ /* Microsoft Touch Cover */ ++ { .driver_data = MT_CLS_EXPORT_ALL_INPUTS, ++ MT_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, ++ USB_DEVICE_ID_MS_TOUCH_COVER_2) }, ++ ++ /* Microsoft Type Cover */ ++ { .driver_data = MT_CLS_EXPORT_ALL_INPUTS, ++ MT_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, ++ USB_DEVICE_ID_MS_TYPE_COVER_2) }, ++ { .driver_data = MT_CLS_EXPORT_ALL_INPUTS, ++ MT_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, ++ USB_DEVICE_ID_MS_TYPE_COVER_3) }, ++ { .driver_data = MT_CLS_EXPORT_ALL_INPUTS, ++ MT_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, ++ USB_DEVICE_ID_MS_TYPE_COVER_PRO_3) }, ++ { .driver_data = MT_CLS_EXPORT_ALL_INPUTS, ++ MT_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, ++ USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_1) }, ++ { .driver_data = MT_CLS_EXPORT_ALL_INPUTS, ++ MT_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, ++ USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_2) }, ++ { .driver_data = MT_CLS_EXPORT_ALL_INPUTS, ++ MT_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, ++ USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP) }, ++ { .driver_data = MT_CLS_EXPORT_ALL_INPUTS, ++ MT_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, ++ USB_DEVICE_ID_MS_TYPE_COVER_PRO_4) }, ++ { .driver_data = MT_CLS_EXPORT_ALL_INPUTS, ++ MT_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, ++ USB_DEVICE_ID_MS_TYPE_COVER_PRO_4_1) }, ++ ++ /* Microsoft Surface Book */ ++ { .driver_data = MT_CLS_EXPORT_ALL_INPUTS, ++ MT_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, ++ USB_DEVICE_ID_MS_SURFACE_BOOK) }, ++ ++ /* Microsoft Surface Book 2 */ ++ { .driver_data = MT_CLS_EXPORT_ALL_INPUTS, ++ MT_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, ++ USB_DEVICE_ID_MS_SURFACE_BOOK_2) }, ++ ++ /* Microsoft Surface Laptop */ ++ { .driver_data = MT_CLS_EXPORT_ALL_INPUTS, ++ HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, ++ USB_VENDOR_ID_MICROSOFT, ++ USB_DEVICE_ID_MS_SURFACE_VHF) }, ++ ++ /* Microsoft Power Cover */ ++ { .driver_data = MT_CLS_EXPORT_ALL_INPUTS, ++ MT_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, ++ USB_DEVICE_ID_MS_POWER_COVER) }, ++ + /* MosArt panels */ + { .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE, + MT_USB_DEVICE(USB_VENDOR_ID_ASUS, +diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c +index 249d49b6b16c..f284f08ba73b 100644 +--- a/drivers/hid/hid-quirks.c ++++ b/drivers/hid/hid-quirks.c +@@ -111,6 +111,16 @@ static const struct hid_device_id hid_quirks[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_SURFACE_PRO_2), HID_QUIRK_NO_INIT_REPORTS }, + { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TOUCH_COVER_2), HID_QUIRK_NO_INIT_REPORTS }, + { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_2), HID_QUIRK_NO_INIT_REPORTS }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3), HID_QUIRK_NO_INIT_REPORTS }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3), HID_QUIRK_NO_INIT_REPORTS }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_1), HID_QUIRK_NO_INIT_REPORTS }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_2), HID_QUIRK_NO_INIT_REPORTS }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP), HID_QUIRK_NO_INIT_REPORTS }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_4), HID_QUIRK_NO_INIT_REPORTS }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_4_1), HID_QUIRK_NO_INIT_REPORTS }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_SURFACE_BOOK), HID_QUIRK_NO_INIT_REPORTS }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_SURFACE_BOOK_2), HID_QUIRK_NO_INIT_REPORTS }, ++ { HID_DEVICE(BUS_VIRTUAL, 0, USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_SURFACE_VHF), HID_QUIRK_ALWAYS_POLL }, + { HID_USB_DEVICE(USB_VENDOR_ID_MOJO, USB_DEVICE_ID_RETRO_ADAPTER), HID_QUIRK_MULTI_INPUT }, + { HID_USB_DEVICE(USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL), HID_QUIRK_NO_INIT_REPORTS }, + { HID_USB_DEVICE(USB_VENDOR_ID_MULTIPLE_1781, USB_DEVICE_ID_RAPHNET_4NES4SNES_OLD), HID_QUIRK_MULTI_INPUT }, +-- +2.20.1 + diff --git a/patches/4.18/sdcard_reader.patch b/patches/4.18/0007-sdcard_reader.patch similarity index 62% rename from patches/4.18/sdcard_reader.patch rename to patches/4.18/0007-sdcard_reader.patch index 283ae6be1..7fd6c2bdf 100644 --- a/patches/4.18/sdcard_reader.patch +++ b/patches/4.18/0007-sdcard_reader.patch @@ -1,3 +1,12 @@ +From c9eb294b2f6e5e16c09e2b0b9e43fb1982f2d723 Mon Sep 17 00:00:00 2001 +From: qzed +Date: Mon, 24 Dec 2018 14:20:52 +0100 +Subject: [PATCH 7/8] sdcard_reader + +--- + drivers/usb/core/hub.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 1fb266809966..916a323ca79f 100644 --- a/drivers/usb/core/hub.c @@ -12,3 +21,6 @@ index 1fb266809966..916a323ca79f 100644 return; udev->lpm_disable_count--; +-- +2.20.1 + diff --git a/patches/4.18/0008-wifi.patch b/patches/4.18/0008-wifi.patch new file mode 100644 index 000000000..01d31b3ca --- /dev/null +++ b/patches/4.18/0008-wifi.patch @@ -0,0 +1,16 @@ +From fcdceb24f246ff4ffebfcced57e8c10d332a2a0c Mon Sep 17 00:00:00 2001 +From: qzed +Date: Mon, 24 Dec 2018 14:21:12 +0100 +Subject: [PATCH 8/8] wifi + +--- + scripts/leaking_addresses.pl | 0 + 1 file changed, 0 insertions(+), 0 deletions(-) + mode change 100755 => 100644 scripts/leaking_addresses.pl + +diff --git a/scripts/leaking_addresses.pl b/scripts/leaking_addresses.pl +old mode 100755 +new mode 100644 +-- +2.20.1 + diff --git a/patches/4.18/acpi.patch b/patches/4.18/acpi.patch deleted file mode 100644 index 8930d1489..000000000 --- a/patches/4.18/acpi.patch +++ /dev/null @@ -1,1374 +0,0 @@ -diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig -index ac4d48830415..2025f56446a0 100644 ---- a/drivers/platform/x86/Kconfig -+++ b/drivers/platform/x86/Kconfig -@@ -1158,6 +1158,15 @@ config SURFACE_3_BUTTON - ---help--- - This driver handles the power/home/volume buttons on the Microsoft Surface 3 tablet. - -+config ACPI_SURFACE -+ tristate "Microsoft Surface Extras" -+ depends on ACPI -+ depends on ACPI_WMI -+ depends on INPUT -+ ---help--- -+ This driver adds support for access to certain system events -+ on Microsoft Surface devices. -+ - config INTEL_PUNIT_IPC - tristate "Intel P-Unit IPC Driver" - ---help--- -diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile -index 2ba6cb795338..8fd5b93bb20d 100644 ---- a/drivers/platform/x86/Makefile -+++ b/drivers/platform/x86/Makefile -@@ -81,6 +81,9 @@ obj-$(CONFIG_INTEL_PMC_IPC) += intel_pmc_ipc.o - obj-$(CONFIG_SILEAD_DMI) += silead_dmi.o - obj-$(CONFIG_SURFACE_PRO3_BUTTON) += surfacepro3_button.o - obj-$(CONFIG_SURFACE_3_BUTTON) += surface3_button.o -+obj-$(CONFIG_ACPI_SURFACE) += surface_acpi.o -+obj-$(CONFIG_ACPI_SURFACE) += surface_i2c.o -+obj-$(CONFIG_ACPI_SURFACE) += surface_platform.o - obj-$(CONFIG_INTEL_PUNIT_IPC) += intel_punit_ipc.o - obj-$(CONFIG_INTEL_BXTWC_PMIC_TMU) += intel_bxtwc_tmu.o - obj-$(CONFIG_INTEL_TELEMETRY) += intel_telemetry_core.o \ -diff --git a/drivers/platform/x86/surface_acpi.c b/drivers/platform/x86/surface_acpi.c -new file mode 100644 -index 000000000000..c969bda99464 ---- /dev/null -+++ b/drivers/platform/x86/surface_acpi.c -@@ -0,0 +1,485 @@ -+/* -+ * surface_acpi.c - Microsoft Surface ACPI Driver -+ * -+ * 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; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * The full GNU General Public License is included in this distribution in -+ * the file called "COPYING". -+ */ -+ -+#define SURFACE_ACPI_VERSION "0.1" -+#define SURFACE_GEN_VERSION 0x08 -+#define PROC_SURFACE "surface" -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "surface_acpi.h" -+ -+#define SUR_METHOD_DSM "_DSM" -+#define SUR_METHOD_REG "_REG" -+#define SUR_METHOD_STA "_STA" -+#define SUR_METHOD_INI "_INI" -+#define SUR_METHOD_CRS "_CRS" -+ -+#define SUR_QUERY_DEVICE 0x00 -+#define SUR_SET_DVER 0x01 -+#define SUR_GET_BOARD_REVID 0x02 -+#define SUR_BAT1_STATE_CHANGE 0x03 -+#define SUR_BAT1_INFO_CHANGE 0x04 -+#define SUR_PSU_STATE_CHANGE 0x05 -+#define SUR_PSU_INFO_CHANGE 0x06 -+#define SUR_BAT2_STATE_CHANGE 0x07 -+#define SUR_BAT2_INFO_CHANGE 0x08 -+#define SUR_SENSOR_TRIP_POINT 0x09 -+ -+#define REG_AVAILABLE 0x01 -+#define REG_INIT 0x09 -+ -+static char SURFACE_EVENT_GUID[] = "93b666c5-70c6-469f-a215-3d487c91ab3c"; -+static char SUR_SAN_RQST[] = "\\_SB._SAN.RQST"; -+static char SUR_SAN_RQSX[] = "\\_SB._SAN.RQSX"; -+ -+struct surface_acpi_dev { -+ acpi_handle handle; -+ acpi_handle rqst_handle; -+ acpi_handle rqsx_handle; -+ -+ struct acpi_device *san_dev; -+ struct acpi_device *ssh_dev; -+ struct acpi_device *bat1_dev; -+ struct acpi_device *bat2_dev; -+ struct acpi_device *psu_dev; -+ -+ unsigned int bat1_attached:1; -+ unsigned int bat2_attached:1; -+ unsigned int psu_registered:1; -+}; -+ -+static struct surface_acpi_dev *surface_acpi; -+ -+static struct proc_dir_entry *surface_proc_dir; -+ -+static acpi_status surface_acpi_check_status(struct acpi_device *dev) -+{ -+ unsigned long long value; -+ acpi_status status; -+ -+ if (acpi_has_method(dev->handle, SUR_METHOD_STA)) { -+ status = acpi_evaluate_integer(dev->handle, -+ SUR_METHOD_STA, NULL, &value); -+ -+ if (ACPI_FAILURE(status)) { -+ pr_err("surface_acpi: ACPI event failure status %s\n", -+ acpi_format_exception(status)); -+ return AE_ERROR; -+ } -+ } -+ else -+ return AE_NOT_FOUND; -+ -+ return AE_OK; -+} -+ -+static acpi_status surface_acpi_san_reg(void) -+{ -+ union acpi_object in_objs[2], out_objs[1]; -+ struct acpi_object_list params; -+ struct acpi_buffer results; -+ acpi_status status; -+ -+ params.count = ARRAY_SIZE(in_objs); -+ params.pointer = in_objs; -+ in_objs[0].type = ACPI_TYPE_INTEGER; -+ in_objs[0].integer.value = REG_INIT; -+ in_objs[1].type = ACPI_TYPE_INTEGER; -+ in_objs[1].integer.value = REG_AVAILABLE; -+ results.length = sizeof(out_objs); -+ results.pointer = out_objs; -+ -+ if (acpi_has_method(surface_acpi->handle, SUR_METHOD_REG)) { -+ status = acpi_evaluate_object(surface_acpi->handle, -+ SUR_METHOD_REG, ¶ms, &results); -+ -+ if (ACPI_FAILURE(status)) { -+ pr_err("surface_acpi: ACPI event failure status %s\n", -+ acpi_format_exception(status)); -+ return AE_ERROR; -+ } -+ } -+ else -+ return AE_NOT_FOUND; -+ -+ return AE_OK; -+} -+ -+acpi_status surface_acpi_event_handler(u32 event) -+{ -+ union acpi_object in_objs[4], out_objs[5]; -+ struct acpi_object_list params; -+ struct acpi_buffer results; -+ acpi_status status; -+ -+ params.count = ARRAY_SIZE(in_objs); -+ params.pointer = in_objs; -+ in_objs[0].type = ACPI_TYPE_BUFFER; -+ in_objs[0].buffer.length = sizeof(SURFACE_EVENT_GUID); -+ in_objs[0].buffer.pointer = SURFACE_EVENT_GUID; -+ in_objs[1].type = ACPI_TYPE_INTEGER; -+ in_objs[1].integer.value = SUR_QUERY_DEVICE; -+ in_objs[2].type = ACPI_TYPE_INTEGER; -+ in_objs[2].integer.value = event; -+ in_objs[3].type = ACPI_TYPE_PACKAGE; -+ in_objs[3].package.count = 0; -+ in_objs[3].package.elements = SURFACE_GEN_VERSION; -+ results.length = sizeof(out_objs); -+ results.pointer = out_objs; -+ -+ if (acpi_has_method(surface_acpi->handle, SUR_METHOD_DSM)) { -+ status = acpi_evaluate_object(surface_acpi->handle, -+ SUR_METHOD_DSM, ¶ms, &results); -+ -+ if (ACPI_FAILURE(status)) { -+ pr_err("surface_acpi: ACPI event failure status %s\n", -+ acpi_format_exception(status)); -+ return AE_ERROR; -+ } -+ } -+ else -+ return AE_NOT_FOUND; -+ -+ return AE_OK; -+} -+EXPORT_SYMBOL(surface_acpi_event_handler); -+ -+static void surface_acpi_san_load(void) -+{ -+ acpi_status ret; -+ -+ ret = surface_acpi_event_handler(SUR_SET_DVER); -+ if (ACPI_FAILURE(ret)) -+ pr_err("surface_acpi: Error setting Driver Version\n"); -+ -+ ret = surface_acpi_event_handler(SUR_SENSOR_TRIP_POINT); -+ if (ACPI_FAILURE(ret)) -+ pr_err("surface_acpi: Error setting Sensor Trip Point\n"); -+ -+ ret = surface_acpi_event_handler(SUR_BAT1_INFO_CHANGE); -+ if (ACPI_FAILURE(ret)) -+ pr_err("surface_acpi: Error attaching BAT1\n"); -+ else -+ surface_acpi->bat1_attached = 1; -+ -+ ret = surface_acpi_event_handler(SUR_BAT2_INFO_CHANGE); -+ if (ACPI_FAILURE(ret)) -+ pr_err("surface_acpi: Error attaching BAT2\n"); -+ else -+ surface_acpi->bat2_attached = 1; -+ -+ ret = surface_acpi_event_handler(SUR_PSU_INFO_CHANGE); -+ if (ACPI_FAILURE(ret)) -+ pr_err("surface_acpi: Error registering PSU\n"); -+ else -+ surface_acpi->psu_registered = 1; -+} -+ -+static acpi_status surface_acpi_ssh_initialize(void) -+{ -+ acpi_status status; -+ -+ if (acpi_has_method(surface_acpi->ssh_dev->handle, SUR_METHOD_INI)) { -+ status = acpi_evaluate_object(surface_acpi->ssh_dev->handle, -+ SUR_METHOD_INI, NULL, NULL); -+ -+ if (ACPI_FAILURE(status)) { -+ pr_err("surface_acpi: ACPI event failure status %s\n", -+ acpi_format_exception(status)); -+ return AE_ERROR; -+ } -+ } -+ else -+ return AE_NOT_FOUND; -+ -+ return AE_OK; -+} -+ -+static int bat1_proc_show(struct seq_file *m, void *v) -+{ -+ seq_printf(m, "attached: %d\n", surface_acpi->bat1_attached); -+ return 0; -+} -+ -+static int bat1_proc_open(struct inode *inode, struct file *file) -+{ -+ return single_open(file, bat1_proc_show, PDE_DATA(inode)); -+} -+ -+static const struct file_operations bat1_proc_fops = { -+ .owner = THIS_MODULE, -+ .open = bat1_proc_open, -+ .read = seq_read, -+ .llseek = seq_lseek, -+ .release = single_release, -+}; -+ -+static int bat2_proc_show(struct seq_file *m, void *v) -+{ -+ seq_printf(m, "attached: %d\n", surface_acpi->bat2_attached); -+ return 0; -+} -+ -+static int bat2_proc_open(struct inode *inode, struct file *file) -+{ -+ return single_open(file, bat2_proc_show, PDE_DATA(inode)); -+} -+ -+static const struct file_operations bat2_proc_fops = { -+ .owner = THIS_MODULE, -+ .open = bat2_proc_open, -+ .read = seq_read, -+ .llseek = seq_lseek, -+ .release = single_release, -+}; -+ -+static int psu_proc_show(struct seq_file *m, void *v) -+{ -+ seq_printf(m, "registered: %d\n", surface_acpi->psu_registered); -+ return 0; -+} -+ -+static int psu_proc_open(struct inode *inode, struct file *file) -+{ -+ return single_open(file, psu_proc_show, PDE_DATA(inode)); -+} -+ -+static const struct file_operations psu_proc_fops = { -+ .owner = THIS_MODULE, -+ .open = psu_proc_open, -+ .read = seq_read, -+ .llseek = seq_lseek, -+ .release = single_release, -+}; -+ -+static int version_proc_show(struct seq_file *m, void *v) -+{ -+ seq_printf(m, "driver: %s\n", SURFACE_ACPI_VERSION); -+ return 0; -+} -+ -+static int version_proc_open(struct inode *inode, struct file *file) -+{ -+ return single_open(file, version_proc_show, PDE_DATA(inode)); -+} -+ -+static const struct file_operations version_proc_fops = { -+ .owner = THIS_MODULE, -+ .open = version_proc_open, -+ .read = seq_read, -+ .llseek = seq_lseek, -+ .release = single_release, -+}; -+ -+static void create_surface_proc_entries(void) -+{ -+ proc_create_data("BAT1", 0, surface_proc_dir, -+ &bat1_proc_fops, surface_acpi->bat1_attached); -+ proc_create_data("BAT2", 0, surface_proc_dir, -+ &bat2_proc_fops, surface_acpi->bat2_attached); -+ proc_create_data("ADP1", 0, surface_proc_dir, -+ &psu_proc_fops, surface_acpi->psu_registered); -+ proc_create_data("version", 0, surface_proc_dir, -+ &version_proc_fops, SURFACE_ACPI_VERSION); -+} -+ -+static void remove_surface_proc_entries(void) -+{ -+ remove_proc_entry("BAT1", surface_proc_dir); -+ remove_proc_entry("BAT2", surface_proc_dir); -+ remove_proc_entry("ADP1", surface_proc_dir); -+ remove_proc_entry("version", surface_proc_dir); -+} -+ -+static void surface_acpi_notify(struct acpi_device *dev, u32 event) -+{ -+ pr_info("surface_acpi: Event received %x\n", event); -+} -+ -+static void surface_acpi_register_rqst_handler(void) -+{ -+ acpi_status status; -+ -+ status = acpi_get_handle(NULL, SUR_SAN_RQST, &surface_acpi->rqst_handle); -+ if (ACPI_FAILURE(status)) { -+ pr_err("surface_acpi: ACPI event failure status %s\n", -+ acpi_format_exception(status)); -+ } -+} -+ -+static void surface_acpi_register_rqsx_handler(void) -+{ -+ acpi_status status; -+ -+ status = acpi_get_handle(NULL, SUR_SAN_RQSX, &surface_acpi->rqsx_handle); -+ if (ACPI_FAILURE(status)) { -+ pr_err("surface_acpi: ACPI event failure status %s\n", -+ acpi_format_exception(status)); -+ } -+} -+ -+static acpi_status surface_acpi_walk_callback(acpi_handle handle, u32 level, -+ void *context, void **return_value) -+{ -+ struct acpi_device_info *info; -+ -+ if (ACPI_SUCCESS(acpi_get_object_info(handle, &info))) { -+ pr_warn("method: name: %4.4s, args %X\n", -+ (char *)&info->name, info->param_count); -+ -+ kfree(info); -+ } -+ -+ return AE_OK; -+} -+ -+static void surface_acpi_walk_namespace(struct acpi_device *dev) -+{ -+ acpi_status status; -+ -+ status = acpi_walk_namespace(ACPI_TYPE_METHOD, -+ dev->handle, 1, surface_acpi_walk_callback, -+ NULL, NULL, NULL); -+ if (ACPI_FAILURE(status)) -+ pr_warn("surface_acpi: Unable to walk acpi resources\n"); -+} -+ -+static int surface_acpi_add(struct acpi_device *dev) -+{ -+ if (!surface_acpi) -+ { -+ surface_acpi = kzalloc(sizeof(*surface_acpi), GFP_KERNEL); -+ if (!surface_acpi) -+ return AE_NO_MEMORY; -+ } -+ -+ if (acpi_has_method(dev->handle, SUR_METHOD_DSM)) -+ { -+ pr_info("surface_acpi: Attaching device MSHW0091\n"); -+ -+ surface_acpi->san_dev = dev; -+ surface_acpi->handle = dev->handle; -+ -+ surface_acpi_walk_namespace(surface_acpi->san_dev); -+ surface_acpi_check_status(surface_acpi->san_dev); -+ -+ surface_acpi_register_rqst_handler(); -+ surface_acpi_register_rqsx_handler(); -+ -+ surface_acpi_san_reg(); -+ surface_acpi_san_load(); -+ -+ create_surface_proc_entries(); -+ } -+ else if (acpi_has_method(dev->handle, SUR_METHOD_CRS)) -+ { -+ pr_info("surface_acpi: Attaching device MSHW0084\n"); -+ -+ surface_acpi->ssh_dev = dev; -+ -+ surface_acpi_walk_namespace(surface_acpi->ssh_dev); -+ surface_acpi_check_status(surface_acpi->ssh_dev); -+ -+ surface_acpi_ssh_initialize(); -+ //surface_acpi_ssh_load(); -+ } -+ else -+ { -+ pr_info("surface_acpi: Attaching device\n"); -+ } -+ -+ device_init_wakeup(&dev->dev, true); -+ -+ return AE_OK; -+} -+ -+static int surface_acpi_remove(struct acpi_device *dev) -+{ -+ remove_surface_proc_entries(); -+ -+ return AE_OK; -+} -+ -+static const struct acpi_device_id surface_device_ids[] = { -+ {"MSHW0084", 0}, -+ {"MSHW0091", 0}, -+ {"MSHW0124", 0}, -+ {"INT3403", 0}, -+ {"LNXTHERM", 0}, -+ {"PNP0C0A", 0}, -+ {"", 0}, -+}; -+MODULE_DEVICE_TABLE(acpi, surface_device_ids); -+ -+static struct acpi_driver surface_acpi_driver = { -+ .name = "surface_acpi", -+ .owner = THIS_MODULE, -+ .ids = surface_device_ids, -+ .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS, -+ .ops = { -+ .add = surface_acpi_add, -+ .remove = surface_acpi_remove, -+ .notify = surface_acpi_notify, -+ }, -+}; -+ -+static int __init surface_acpi_init(void) -+{ -+ int ret; -+ -+ pr_info("surface_acpi: Microsoft Surface ACPI Driver version %s\n", -+ SURFACE_ACPI_VERSION); -+ -+ surface_proc_dir = proc_mkdir(PROC_SURFACE, acpi_root_dir); -+ if (!surface_proc_dir) { -+ pr_err("surface_acpi: Unable to create proc dir " PROC_SURFACE "\n"); -+ return -ENODEV; -+ } -+ -+ ret = acpi_bus_register_driver(&surface_acpi_driver); -+ if (ret) { -+ pr_err("surface_acpi: Failed to register ACPI driver: %d\n", ret); -+ remove_proc_entry(PROC_SURFACE, acpi_root_dir); -+ } -+ -+ return ret; -+} -+ -+static void __exit surface_acpi_exit(void) -+{ -+ acpi_bus_unregister_driver(&surface_acpi_driver); -+ if (surface_proc_dir) -+ remove_proc_entry(PROC_SURFACE, acpi_root_dir); -+} -+ -+module_init(surface_acpi_init); -+module_exit(surface_acpi_exit); -+ -+MODULE_AUTHOR("Jake Day"); -+MODULE_DESCRIPTION("Microsoft Surface ACPI Driver"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/platform/x86/surface_acpi.h b/drivers/platform/x86/surface_acpi.h -new file mode 100644 -index 000000000000..5b6627c4d6f1 ---- /dev/null -+++ b/drivers/platform/x86/surface_acpi.h -@@ -0,0 +1,18 @@ -+/* -+ * surface_acpi.h - Microsoft Surface ACPI Driver -+ * -+ * 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; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * The full GNU General Public License is included in this distribution in -+ * the file called "COPYING". -+ */ -+ -+acpi_status surface_acpi_event_handler(u32 event); -diff --git a/drivers/platform/x86/surface_i2c.c b/drivers/platform/x86/surface_i2c.c -new file mode 100644 -index 000000000000..fb2cf0cae72f ---- /dev/null -+++ b/drivers/platform/x86/surface_i2c.c -@@ -0,0 +1,696 @@ -+/* -+ * surface_i2c.c - Microsoft Surface I2C Driver -+ * -+ * 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; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * The full GNU General Public License is included in this distribution in -+ * the file called "COPYING". -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "surface_acpi.h" -+ -+#define POLL_INTERVAL (HZ * 2) -+ -+struct surface_i2c_data { -+ struct i2c_client *adp1; -+ struct i2c_client *bat0; -+ unsigned short notify_version; -+ struct task_struct *poll_task; -+ bool kthread_running; -+ bool charging; -+ bool bat_charging; -+ u8 trip_point; -+ s32 full_capacity; -+}; -+ -+struct surface_i2c_lookup { -+ struct surface_i2c_data *cdata; -+ unsigned int n; -+ unsigned int index; -+ int addr; -+}; -+ -+struct surface_i2c_handler_data { -+ struct acpi_connection_info info; -+ struct i2c_client *client; -+}; -+ -+struct bix { -+ u32 revision; -+ u32 power_unit; -+ u32 design_capacity; -+ u32 last_full_charg_capacity; -+ u32 battery_technology; -+ u32 design_voltage; -+ u32 design_capacity_of_warning; -+ u32 design_capacity_of_low; -+ u32 cycle_count; -+ u32 measurement_accuracy; -+ u32 max_sampling_time; -+ u32 min_sampling_time; -+ u32 max_average_interval; -+ u32 min_average_interval; -+ u32 battery_capacity_granularity_1; -+ u32 battery_capacity_granularity_2; -+ char model[10]; -+ char serial[10]; -+ char type[10]; -+ char OEM[10]; -+} __packed; -+ -+struct bst { -+ u32 battery_state; -+ s32 battery_present_rate; -+ u32 battery_remaining_capacity; -+ u32 battery_present_voltage; -+} __packed; -+ -+struct gsb_command { -+ u8 arg0; -+ u8 arg1; -+ u8 arg2; -+} __packed; -+ -+struct gsb_buffer { -+ u8 status; -+ u8 len; -+ u8 ret; -+ union { -+ struct gsb_command cmd; -+ struct bst bst; -+ struct bix bix; -+ } __packed; -+} __packed; -+ -+#define ACPI_BATTERY_STATE_DISCHARGING 0x1 -+#define ACPI_BATTERY_STATE_CHARGING 0x2 -+#define ACPI_BATTERY_STATE_CRITICAL 0x4 -+ -+#define surface_i2c_CMD_DEST_BAT0 0x01 -+#define surface_i2c_CMD_DEST_ADP1 0x03 -+ -+#define surface_i2c_CMD_BAT0_STA 0x01 -+#define surface_i2c_CMD_BAT0_BIX 0x02 -+#define surface_i2c_CMD_BAT0_BCT 0x03 -+#define surface_i2c_CMD_BAT0_BTM 0x04 -+#define surface_i2c_CMD_BAT0_BST 0x05 -+#define surface_i2c_CMD_BAT0_BTP 0x06 -+#define surface_i2c_CMD_ADP1_PSR 0x07 -+#define surface_i2c_CMD_BAT0_PSOC 0x09 -+#define surface_i2c_CMD_BAT0_PMAX 0x0A -+#define surface_i2c_CMD_BAT0_PSRC 0x0B -+#define surface_i2c_CMD_BAT0_CHGI 0x0C -+#define surface_i2c_CMD_BAT0_ARTG 0x0D -+ -+#define surface_i2c_NOTIFY_GET_VERSION 0x00 -+#define surface_i2c_NOTIFY_ADP1 0x01 -+#define surface_i2c_NOTIFY_BAT0_BST 0x02 -+#define surface_i2c_NOTIFY_BAT0_BIX 0x05 -+ -+#define surface_i2c_ADP1_REG_PSR 0x03 -+ -+#define surface_i2c_BAT0_REG_CAPACITY 0x0c -+#define surface_i2c_BAT0_REG_FULL_CHG_CAPACITY 0x0e -+#define surface_i2c_BAT0_REG_DESIGN_CAPACITY 0x40 -+#define surface_i2c_BAT0_REG_VOLTAGE 0x08 -+#define surface_i2c_BAT0_REG_RATE 0x14 -+#define surface_i2c_BAT0_REG_OEM 0x45 -+#define surface_i2c_BAT0_REG_TYPE 0x4e -+#define surface_i2c_BAT0_REG_SERIAL_NO 0x56 -+#define surface_i2c_BAT0_REG_CYCLE_CNT 0x6e -+ -+#define surface_i2c_EV_2_5 0x1ff -+ -+static int surface_i2c_read_block(struct i2c_client *client, u8 reg, u8 *buf, -+ int len) -+{ -+ int status, i; -+ -+ for (i = 0; i < len; i++) { -+ status = i2c_smbus_read_byte_data(client, reg + i); -+ if (status < 0) { -+ buf[i] = 0xff; -+ continue; -+ } -+ -+ buf[i] = (u8)status; -+ } -+ -+ return 0; -+} -+ -+static int -+surface_i2c_notify(struct surface_i2c_data *cdata, u8 arg1, u8 arg2, -+ unsigned int *ret_value) -+{ -+ /*static const guid_t surface_i2c_guid = -+ GUID_INIT(0x93b666c5, 0x70c6, 0x469f, -+ 0xa2, 0x15, 0x3d, 0x48, 0x7c, 0x91, 0xab, 0x3c);*/ -+ -+ struct acpi_device *adev; -+ acpi_handle handle; -+ acpi_status status; -+ -+ handle = ACPI_HANDLE(&cdata->adp1->dev); -+ if (!handle || acpi_bus_get_device(handle, &adev)) -+ return -ENODEV; -+ -+ *ret_value = 0; -+ -+ status = surface_acpi_event_handler(arg2); -+ if (ACPI_FAILURE(status)) { -+ pr_err("surface_i2c: ACPI event failure status %s\n", -+ acpi_format_exception(status)); -+ } -+ -+ return 0; -+} -+ -+static const struct bix default_bix = { -+ .revision = 0x00, -+ .power_unit = 0x00, -+ .design_capacity = 0x1734, -+ .last_full_charg_capacity = 0x1734, -+ .battery_technology = 0x01, -+ .design_voltage = 0x1d92, -+ .design_capacity_of_warning = 0xc8, -+ .design_capacity_of_low = 0xc8, -+ .battery_capacity_granularity_1 = 0x45, -+ .battery_capacity_granularity_2 = 0x11, -+ .cycle_count = 0x01, -+ .measurement_accuracy = 0x00015F90, -+ .max_sampling_time = 0x03E8, -+ .min_sampling_time = 0x03E8, -+ .max_average_interval = 0x03E8, -+ .min_average_interval = 0x03E8, -+ .model = "PNP0C0A", -+ .serial = "1234567890", -+ .type = "SDS-BAT", -+ .OEM = "MICROSOFT", -+}; -+ -+static int surface_i2c_bix(struct surface_i2c_data *cdata, struct bix *bix) -+{ -+ struct i2c_client *client = cdata->bat0; -+ int ret; -+ char buf[10]; -+ -+ *bix = default_bix; -+ -+ /* get design capacity */ -+ ret = i2c_smbus_read_word_data(client, surface_i2c_BAT0_REG_DESIGN_CAPACITY); -+ if (ret < 0) { -+ dev_err(&client->dev, "Error reading design capacity: %d\n", ret); -+ return ret; -+ } -+ bix->design_capacity = le16_to_cpu(ret); -+ -+ /* get last full charge capacity */ -+ ret = i2c_smbus_read_word_data(client, surface_i2c_BAT0_REG_FULL_CHG_CAPACITY); -+ if (ret < 0) { -+ dev_err(&client->dev, "Error reading last full charge capacity: %d\n", ret); -+ return ret; -+ } -+ bix->last_full_charg_capacity = le16_to_cpu(ret); -+ -+ /* get serial number */ -+ ret = surface_i2c_read_block(client, surface_i2c_BAT0_REG_SERIAL_NO, -+ buf, 10); -+ if (ret) { -+ dev_err(&client->dev, "Error reading serial no: %d\n", ret); -+ return ret; -+ } -+ memcpy(bix->serial, buf + 7, 3); -+ memcpy(bix->serial + 3, buf, 6); -+ bix->serial[9] = '\0'; -+ -+ /* get cycle count */ -+ ret = i2c_smbus_read_word_data(client, surface_i2c_BAT0_REG_CYCLE_CNT); -+ if (ret < 0) { -+ dev_err(&client->dev, "Error reading cycle count: %d\n", ret); -+ return ret; -+ } -+ bix->cycle_count = le16_to_cpu(ret); -+ -+ /* get OEM name */ -+ ret = surface_i2c_read_block(client, surface_i2c_BAT0_REG_OEM, buf, 4); -+ if (ret) { -+ dev_err(&client->dev, "Error reading cycle count: %d\n", ret); -+ return ret; -+ } -+ memcpy(bix->OEM, buf, 3); -+ bix->OEM[4] = '\0'; -+ -+ return 0; -+} -+ -+static int surface_i2c_bst(struct surface_i2c_data *cdata, struct bst *bst) -+{ -+ struct i2c_client *client = cdata->bat0; -+ int rate, capacity, voltage, state; -+ s16 tmp; -+ -+ rate = i2c_smbus_read_word_data(client, surface_i2c_BAT0_REG_RATE); -+ if (rate < 0) -+ return rate; -+ -+ capacity = i2c_smbus_read_word_data(client, surface_i2c_BAT0_REG_CAPACITY); -+ if (capacity < 0) -+ return capacity; -+ -+ voltage = i2c_smbus_read_word_data(client, surface_i2c_BAT0_REG_VOLTAGE); -+ if (voltage < 0) -+ return voltage; -+ -+ tmp = le16_to_cpu(rate); -+ bst->battery_present_rate = abs((s32)tmp); -+ -+ state = 0; -+ if ((s32) tmp > 0) -+ state |= ACPI_BATTERY_STATE_CHARGING; -+ else if ((s32) tmp < 0) -+ state |= ACPI_BATTERY_STATE_DISCHARGING; -+ bst->battery_state = state; -+ -+ bst->battery_remaining_capacity = le16_to_cpu(capacity); -+ bst->battery_present_voltage = le16_to_cpu(voltage); -+ -+ return 0; -+} -+ -+static int surface_i2c_adp_psr(struct surface_i2c_data *cdata) -+{ -+ struct i2c_client *client = cdata->adp1; -+ int ret; -+ -+ ret = i2c_smbus_read_byte_data(client, surface_i2c_ADP1_REG_PSR); -+ if (ret < 0) -+ return ret; -+ -+ return ret; -+} -+ -+static int surface_i2c_isr(struct surface_i2c_data *cdata) -+{ -+ struct bst bst; -+ struct bix bix; -+ int ret; -+ bool status, bat_status; -+ -+ ret = surface_i2c_adp_psr(cdata); -+ if (ret < 0) -+ return ret; -+ -+ status = ret; -+ -+ if (status != cdata->charging) -+ surface_i2c_notify(cdata, cdata->notify_version, -+ surface_i2c_NOTIFY_ADP1, &ret); -+ -+ cdata->charging = status; -+ -+ ret = surface_i2c_bst(cdata, &bst); -+ if (ret < 0) -+ return ret; -+ -+ bat_status = bst.battery_state; -+ -+ if (bat_status != cdata->bat_charging) -+ surface_i2c_notify(cdata, cdata->notify_version, -+ surface_i2c_NOTIFY_BAT0_BST, &ret); -+ -+ cdata->bat_charging = bat_status; -+ -+ ret = surface_i2c_bix(cdata, &bix); -+ if (ret < 0) -+ return ret; -+ if (bix.last_full_charg_capacity != cdata->full_capacity) -+ surface_i2c_notify(cdata, cdata->notify_version, -+ surface_i2c_NOTIFY_BAT0_BIX, &ret); -+ -+ cdata->full_capacity = bix.last_full_charg_capacity; -+ -+ return 0; -+} -+ -+static int surface_i2c_poll_task(void *data) -+{ -+ struct surface_i2c_data *cdata = data; -+ int ret = 0; -+ -+ cdata->kthread_running = true; -+ -+ set_freezable(); -+ -+ while (!kthread_should_stop()) { -+ schedule_timeout_interruptible(POLL_INTERVAL); -+ try_to_freeze(); -+ ret = surface_i2c_isr(data); -+ if (ret) -+ goto out; -+ } -+ -+out: -+ cdata->kthread_running = false; -+ return ret; -+} -+ -+static acpi_status -+surface_i2c_space_handler(u32 function, acpi_physical_address command, -+ u32 bits, u64 *value64, -+ void *handler_context, void *region_context) -+{ -+ struct gsb_buffer *gsb = (struct gsb_buffer *)value64; -+ struct surface_i2c_handler_data *data = handler_context; -+ struct acpi_connection_info *info = &data->info; -+ struct acpi_resource_i2c_serialbus *sb; -+ struct i2c_client *client = data->client; -+ struct surface_i2c_data *cdata = i2c_get_clientdata(client); -+ struct acpi_resource *ares; -+ u32 accessor_type = function >> 16; -+ acpi_status ret; -+ int status = 1; -+ -+ ret = acpi_buffer_to_resource(info->connection, info->length, &ares); -+ if (ACPI_FAILURE(ret)) -+ return ret; -+ -+ if (!value64 || ares->type != ACPI_RESOURCE_TYPE_SERIAL_BUS) { -+ ret = AE_BAD_PARAMETER; -+ goto err; -+ } -+ -+ sb = &ares->data.i2c_serial_bus; -+ if (sb->type != ACPI_RESOURCE_SERIAL_TYPE_I2C) { -+ ret = AE_BAD_PARAMETER; -+ goto err; -+ } -+ -+ if (accessor_type != ACPI_GSB_ACCESS_ATTRIB_RAW_PROCESS) { -+ ret = AE_BAD_PARAMETER; -+ goto err; -+ } -+ -+ if (gsb->cmd.arg0 == surface_i2c_CMD_DEST_ADP1 && -+ gsb->cmd.arg1 == surface_i2c_CMD_ADP1_PSR) { -+ ret = surface_i2c_adp_psr(cdata); -+ if (ret >= 0) { -+ status = ret; -+ ret = 0; -+ } -+ goto out; -+ } -+ -+ if (gsb->cmd.arg0 != surface_i2c_CMD_DEST_BAT0) { -+ ret = AE_BAD_PARAMETER; -+ goto err; -+ } -+ -+ switch (gsb->cmd.arg1) { -+ case surface_i2c_CMD_BAT0_STA: -+ status = 1; -+ ret = 0; -+ break; -+ case surface_i2c_CMD_BAT0_BIX: -+ status = 1; -+ ret = surface_i2c_bix(cdata, &gsb->bix); -+ break; -+ case surface_i2c_CMD_BAT0_BTP: -+ status = 1; -+ ret = 0; -+ cdata->trip_point = gsb->cmd.arg2; -+ break; -+ case surface_i2c_CMD_BAT0_BST: -+ status = 1; -+ ret = surface_i2c_bst(cdata, &gsb->bst); -+ break; -+ default: -+ pr_info("command(0x%02x) is not supported.\n", gsb->cmd.arg1); -+ ret = AE_BAD_PARAMETER; -+ goto err; -+ } -+ -+ out: -+ gsb->ret = status; -+ gsb->status = 0; -+ -+ err: -+ ACPI_FREE(ares); -+ return ret; -+} -+ -+static int surface_i2c_install_space_handler(struct i2c_client *client) -+{ -+ acpi_handle handle; -+ struct surface_i2c_handler_data *data; -+ acpi_status status; -+ -+ handle = ACPI_HANDLE(&client->dev); -+ -+ if (!handle) -+ return -ENODEV; -+ -+ data = kzalloc(sizeof(struct surface_i2c_handler_data), -+ GFP_KERNEL); -+ if (!data) -+ return -ENOMEM; -+ -+ data->client = client; -+ status = acpi_bus_attach_private_data(handle, (void *)data); -+ if (ACPI_FAILURE(status)) { -+ kfree(data); -+ return -ENOMEM; -+ } -+ -+ status = acpi_install_address_space_handler(handle, -+ ACPI_ADR_SPACE_GSBUS, -+ &surface_i2c_space_handler, -+ NULL, -+ data); -+ if (ACPI_FAILURE(status)) { -+ dev_err(&client->dev, "Error installing i2c space handler\n"); -+ acpi_bus_detach_private_data(handle); -+ kfree(data); -+ return -ENOMEM; -+ } -+ -+ acpi_walk_dep_device_list(handle); -+ return 0; -+} -+ -+static void surface_i2c_remove_space_handler(struct i2c_client *client) -+{ -+ acpi_handle handle; -+ struct surface_i2c_handler_data *data; -+ acpi_status status; -+ -+ handle = ACPI_HANDLE(&client->dev); -+ -+ if (!handle) -+ return; -+ -+ acpi_remove_address_space_handler(handle, -+ ACPI_ADR_SPACE_GSBUS, -+ &surface_i2c_space_handler); -+ -+ status = acpi_bus_get_private_data(handle, (void **)&data); -+ if (ACPI_SUCCESS(status)) -+ kfree(data); -+ -+ acpi_bus_detach_private_data(handle); -+} -+ -+static int acpi_find_i2c(struct acpi_resource *ares, void *data) -+{ -+ struct surface_i2c_lookup *lookup = data; -+ -+ if (ares->type != ACPI_RESOURCE_TYPE_SERIAL_BUS) -+ return 1; -+ -+ if (lookup->n++ == lookup->index && !lookup->addr) -+ lookup->addr = ares->data.i2c_serial_bus.slave_address; -+ -+ return 1; -+} -+ -+static int surface_i2c_resource_lookup(struct surface_i2c_data *cdata, -+ unsigned int index) -+{ -+ struct i2c_client *client = cdata->adp1; -+ struct acpi_device *adev = ACPI_COMPANION(&client->dev); -+ struct surface_i2c_lookup lookup = { -+ .cdata = cdata, -+ .index = index, -+ }; -+ struct list_head res_list; -+ int ret; -+ -+ INIT_LIST_HEAD(&res_list); -+ -+ ret = acpi_dev_get_resources(adev, &res_list, acpi_find_i2c, &lookup); -+ if (ret < 0) -+ return ret; -+ -+ acpi_dev_free_resource_list(&res_list); -+ -+ if (!lookup.addr) -+ return -ENOENT; -+ -+ return lookup.addr; -+} -+ -+static void surface_i2c_dump_registers(struct i2c_client *client, -+ struct i2c_client *bat0) -+{ -+ char rd_buf[60]; -+ int error, i, c; -+ char buff[17 * 3 * 2] = {0}; -+ -+ dev_info(&client->dev, "dumping registers 0x00 to 0x7F:\n"); -+ -+ for (i = 0; i < 0x80; i += 0x20) { -+ memset(rd_buf, 0, sizeof(rd_buf)); -+ error = surface_i2c_read_block(bat0, i, rd_buf, 0x20); -+ dev_info(&client->dev, " read 0x%02x: %*ph|%*ph\n", -+ i, -+ 0x10, rd_buf, -+ 0x10, rd_buf + 0x10); -+ for (c = 0; c < 0x20; c++) { -+ if (rd_buf[c] >= 0x20 && rd_buf[c] <= 0x7e) { -+ buff[c * 3 + 0] = ' '; -+ buff[c * 3 + 1] = rd_buf[c]; -+ } else { -+ buff[c * 3 + 0] = '-'; -+ buff[c * 3 + 1] = '-'; -+ } -+ buff[c * 3 + 2] = (c + 1) % 0x10 ? ' ' : '|'; -+ } -+ buff[0x1f * 3 + 2] = '\0'; -+ dev_info(&client->dev, "ascii 0x%02x: %s\n", i, buff); -+ } -+} -+ -+static int surface_i2c_probe(struct i2c_client *client) -+{ -+ struct device *dev = &client->dev; -+ struct i2c_client *bat0; -+ struct surface_i2c_data *data; -+ int error, version, addr; -+ -+ pr_info("surface_i2c: Probing for surface i2c device...\n"); -+ -+ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); -+ if (!data) -+ return -ENOMEM; -+ -+ data->adp1 = client; -+ i2c_set_clientdata(client, data); -+ -+ addr = surface_i2c_resource_lookup(data, 1); -+ if (addr < 0) -+ return addr; -+ -+ bat0 = i2c_new_dummy(client->adapter, addr); -+ if (!bat0) -+ return -ENOMEM; -+ -+ data->bat0 = bat0; -+ i2c_set_clientdata(bat0, data); -+ -+ // debugging -+ surface_i2c_dump_registers(client, bat0); -+ -+ pr_info("surface_i2c: Attaching device MSHW0124..."); -+ -+ error = surface_i2c_notify(data, 1, surface_i2c_NOTIFY_GET_VERSION, &version); -+ if (error) -+ goto out_err; -+ -+ data->notify_version = version == surface_i2c_EV_2_5; -+ -+ data->poll_task = kthread_run(surface_i2c_poll_task, data, "surface_i2c_adp"); -+ if (IS_ERR(data->poll_task)) { -+ error = PTR_ERR(data->poll_task); -+ dev_err(&client->dev, "Unable to run kthread err %d\n", error); -+ goto out_err; -+ } -+ -+ //error = surface_i2c_install_space_handler(client); -+ //if (error) -+ // goto out_err; -+ -+ return 0; -+ -+out_err: -+ if (data->kthread_running) -+ kthread_stop(data->poll_task); -+ i2c_unregister_device(data->bat0); -+ return error; -+} -+ -+static int surface_i2c_remove(struct i2c_client *client) -+{ -+ struct surface_i2c_data *cdata = i2c_get_clientdata(client); -+ -+ surface_i2c_remove_space_handler(client); -+ -+ if (cdata->kthread_running) -+ kthread_stop(cdata->poll_task); -+ -+ i2c_unregister_device(cdata->bat0); -+ -+ return 0; -+} -+ -+int surface_i2c_detect(struct i2c_client* client, struct i2c_board_info* board_info) -+{ -+ pr_info("surface_i2c: Detecting surface_i2c device..."); -+ return 0; -+} -+ -+static const struct acpi_device_id surface_i2c_acpi_match[] = { -+ { "MSHW0124", 0 }, -+ { "", 0 } -+}; -+MODULE_DEVICE_TABLE(acpi, surface_i2c_acpi_match); -+ -+static const struct i2c_device_id surface_i2c_id[] = { -+ { "MSHW0124:00", 0 }, -+ { "MSHW0124:01", 0 }, -+ { "", 0 } -+}; -+MODULE_DEVICE_TABLE(i2c, surface_i2c_id); -+ -+static struct i2c_driver surface_i2c_driver = { -+ .probe_new = surface_i2c_probe, -+ .remove = surface_i2c_remove, -+ .detect = surface_i2c_detect, -+ .id_table = surface_i2c_id, -+ .driver = { -+ .name = "surface_i2c", -+ .acpi_match_table = ACPI_PTR(surface_i2c_acpi_match), -+ }, -+}; -+module_i2c_driver(surface_i2c_driver); -+ -+MODULE_AUTHOR("Jake Day"); -+MODULE_DESCRIPTION("Microsoft Surface I2C Driver"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/platform/x86/surface_platform.c b/drivers/platform/x86/surface_platform.c -new file mode 100644 -index 000000000000..7a84340b04bb ---- /dev/null -+++ b/drivers/platform/x86/surface_platform.c -@@ -0,0 +1,67 @@ -+/* -+ * surface_platform.c - Microsoft Surface Platform Driver -+ * -+ * 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; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * The full GNU General Public License is included in this distribution in -+ * the file called "COPYING". -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+struct surface_platform_data { -+ struct device *dev; -+}; -+ -+static int surface_platform_probe(struct platform_device *pdev) -+{ -+ struct surface_platform_data *pdata; -+ -+ platform_set_drvdata(pdev, pdata); -+ return 0; -+} -+ -+static int surface_platform_remove(struct platform_device *pdev) -+{ -+ struct surface_platform_data *pdata = platform_get_drvdata(pdev); -+} -+ -+static const struct acpi_device_id surface_platform_acpi_match[] = { -+ { "MSHW0091", 0 }, -+ { "INT3403", 0 }, -+ { "", 0 } -+}; -+MODULE_DEVICE_TABLE(acpi, surface_platform_acpi_match); -+ -+static struct platform_driver surface_platform_driver = { -+ .probe = surface_platform_probe, -+ .remove = surface_platform_remove, -+ .driver = { -+ .name = "surface_platform", -+ .acpi_match_table = ACPI_PTR(surface_platform_acpi_match), -+ }, -+}; -+module_platform_driver(surface_platform_driver); -+ -+MODULE_AUTHOR("Jake Day"); -+MODULE_DESCRIPTION("Microsoft Surface Platform Driver"); -+MODULE_LICENSE("GPL"); -diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c -index 87331565e505..d55f949ee25a 100644 ---- a/kernel/power/suspend.c -+++ b/kernel/power/suspend.c -@@ -520,6 +520,8 @@ int suspend_devices_and_enter(suspend_state_t state) - goto Resume_devices; - } - -+unsigned int resume_delay = 3000; -+ - /** - * suspend_finish - Clean up before finishing the suspend sequence. - * -@@ -528,6 +530,15 @@ int suspend_devices_and_enter(suspend_state_t state) - */ - static void suspend_finish(void) - { -+ if (resume_delay) { -+ /* Give kernel threads a head start, such that usb-storage -+ * can detect devices before syslog attempts to write log -+ * messages from the suspend code. -+ */ -+ thaw_kernel_threads(); -+ pr_debug("PM: Sleeping for %d milliseconds.\n", resume_delay); -+ msleep(resume_delay); -+ } - suspend_thaw_processes(); - pm_notifier_call_chain(PM_POST_SUSPEND); - pm_restore_console(); -diff --git a/kernel/sysctl.c b/kernel/sysctl.c -index 2d9837c0aff4..ac704bf71f45 100644 ---- a/kernel/sysctl.c -+++ b/kernel/sysctl.c -@@ -308,7 +308,16 @@ static int min_extfrag_threshold; - static int max_extfrag_threshold = 1000; - #endif - -+extern unsigned int resume_delay; -+ - static struct ctl_table kern_table[] = { -+ { -+ .procname = "resume_delay", -+ .data = &resume_delay, -+ .maxlen = sizeof(unsigned int), -+ .mode = 0644, -+ .proc_handler = proc_dointvec, -+ }, - { - .procname = "sched_child_runs_first", - .data = &sysctl_sched_child_runs_first, diff --git a/patches/4.18/keyboards_and_covers.patch b/patches/4.18/keyboards_and_covers.patch deleted file mode 100644 index af551ead9..000000000 --- a/patches/4.18/keyboards_and_covers.patch +++ /dev/null @@ -1,555 +0,0 @@ -diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h -index c7981ddd8776..914a19b4290a 100644 ---- a/drivers/hid/hid-ids.h -+++ b/drivers/hid/hid-ids.h -@@ -793,11 +793,21 @@ - #define USB_DEVICE_ID_MS_DIGITAL_MEDIA_3KV1 0x0732 - #define USB_DEVICE_ID_MS_DIGITAL_MEDIA_600 0x0750 - #define USB_DEVICE_ID_MS_COMFORT_MOUSE_4500 0x076c --#define USB_DEVICE_ID_MS_COMFORT_KEYBOARD 0x00e3 --#define USB_DEVICE_ID_MS_SURFACE_PRO_2 0x0799 --#define USB_DEVICE_ID_MS_TOUCH_COVER_2 0x07a7 --#define USB_DEVICE_ID_MS_TYPE_COVER_2 0x07a9 --#define USB_DEVICE_ID_MS_POWER_COVER 0x07da -+#define USB_DEVICE_ID_MS_COMFORT_KEYBOARD 0x00e3 -+#define USB_DEVICE_ID_MS_SURFACE_PRO_2 0x0799 -+#define USB_DEVICE_ID_MS_TOUCH_COVER_2 0x07a7 -+#define USB_DEVICE_ID_MS_TYPE_COVER_2 0x07a9 -+#define USB_DEVICE_ID_MS_TYPE_COVER_3 0x07de -+#define USB_DEVICE_ID_MS_TYPE_COVER_PRO_3 0x07dc -+#define USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_1 0x07de -+#define USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_2 0x07e2 -+#define USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP 0x07dd -+#define USB_DEVICE_ID_MS_TYPE_COVER_PRO_4 0x07e8 -+#define USB_DEVICE_ID_MS_TYPE_COVER_PRO_4_1 0x07e4 -+#define USB_DEVICE_ID_MS_SURFACE_BOOK 0x07cd -+#define USB_DEVICE_ID_MS_SURFACE_BOOK_2 0x0922 -+#define USB_DEVICE_ID_MS_SURFACE_LAPTOP 0xf001 -+#define USB_DEVICE_ID_MS_POWER_COVER 0x07da - - #define USB_VENDOR_ID_MOJO 0x8282 - #define USB_DEVICE_ID_RETRO_ADAPTER 0x3201 -diff --git a/drivers/hid/hid-microsoft.c b/drivers/hid/hid-microsoft.c -index 96e7d3231d2f..e55097221eec 100644 ---- a/drivers/hid/hid-microsoft.c -+++ b/drivers/hid/hid-microsoft.c -@@ -278,7 +278,8 @@ static const struct hid_device_id ms_devices[] = { - .driver_data = MS_HIDINPUT }, - { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_COMFORT_KEYBOARD), - .driver_data = MS_ERGONOMY}, -- -+ { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_SURFACE_LAPTOP), -+ .driver_data = MS_HIDINPUT}, - { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_BT), - .driver_data = MS_PRESENTER }, - { } -diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c -index a0e053c4dc1c..5298793b1eaf 100644 ---- a/drivers/hid/hid-multitouch.c -+++ b/drivers/hid/hid-multitouch.c -@@ -1754,6 +1754,58 @@ static const struct hid_device_id mt_devices[] = { - HID_USB_DEVICE(USB_VENDOR_ID_LG, - USB_DEVICE_ID_LG_MELFAS_MT) }, - -+ /* Microsoft Touch Cover */ -+ { .driver_data = MT_CLS_EXPORT_ALL_INPUTS, -+ MT_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, -+ USB_DEVICE_ID_MS_TOUCH_COVER_2) }, -+ -+ /* Microsoft Type Cover */ -+ { .driver_data = MT_CLS_EXPORT_ALL_INPUTS, -+ MT_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, -+ USB_DEVICE_ID_MS_TYPE_COVER_2) }, -+ { .driver_data = MT_CLS_EXPORT_ALL_INPUTS, -+ MT_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, -+ USB_DEVICE_ID_MS_TYPE_COVER_3) }, -+ { .driver_data = MT_CLS_EXPORT_ALL_INPUTS, -+ MT_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, -+ USB_DEVICE_ID_MS_TYPE_COVER_PRO_3) }, -+ { .driver_data = MT_CLS_EXPORT_ALL_INPUTS, -+ MT_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, -+ USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_1) }, -+ { .driver_data = MT_CLS_EXPORT_ALL_INPUTS, -+ MT_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, -+ USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_2) }, -+ { .driver_data = MT_CLS_EXPORT_ALL_INPUTS, -+ MT_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, -+ USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP) }, -+ { .driver_data = MT_CLS_EXPORT_ALL_INPUTS, -+ MT_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, -+ USB_DEVICE_ID_MS_TYPE_COVER_PRO_4) }, -+ { .driver_data = MT_CLS_EXPORT_ALL_INPUTS, -+ MT_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, -+ USB_DEVICE_ID_MS_TYPE_COVER_PRO_4_1) }, -+ -+ /* Microsoft Surface Book */ -+ { .driver_data = MT_CLS_EXPORT_ALL_INPUTS, -+ MT_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, -+ USB_DEVICE_ID_MS_SURFACE_BOOK) }, -+ -+ /* Microsoft Surface Book 2 */ -+ { .driver_data = MT_CLS_EXPORT_ALL_INPUTS, -+ MT_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, -+ USB_DEVICE_ID_MS_SURFACE_BOOK_2) }, -+ -+ /* Microsoft Surface Laptop */ -+ { .driver_data = MT_CLS_EXPORT_ALL_INPUTS, -+ HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, -+ USB_VENDOR_ID_MICROSOFT, -+ USB_DEVICE_ID_MS_SURFACE_LAPTOP) }, -+ -+ /* Microsoft Power Cover */ -+ { .driver_data = MT_CLS_EXPORT_ALL_INPUTS, -+ MT_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, -+ USB_DEVICE_ID_MS_POWER_COVER) }, -+ - /* MosArt panels */ - { .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE, - MT_USB_DEVICE(USB_VENDOR_ID_ASUS, -diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c -index 249d49b6b16c..28fa76011df3 100644 ---- a/drivers/hid/hid-quirks.c -+++ b/drivers/hid/hid-quirks.c -@@ -111,6 +111,16 @@ static const struct hid_device_id hid_quirks[] = { - { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_SURFACE_PRO_2), HID_QUIRK_NO_INIT_REPORTS }, - { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TOUCH_COVER_2), HID_QUIRK_NO_INIT_REPORTS }, - { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_2), HID_QUIRK_NO_INIT_REPORTS }, -+ { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3), HID_QUIRK_NO_INIT_REPORTS }, -+ { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3), HID_QUIRK_NO_INIT_REPORTS }, -+ { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_1), HID_QUIRK_NO_INIT_REPORTS }, -+ { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_2), HID_QUIRK_NO_INIT_REPORTS }, -+ { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP), HID_QUIRK_NO_INIT_REPORTS }, -+ { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_4), HID_QUIRK_NO_INIT_REPORTS }, -+ { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_4_1), HID_QUIRK_NO_INIT_REPORTS }, -+ { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_SURFACE_BOOK), HID_QUIRK_NO_INIT_REPORTS }, -+ { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_SURFACE_BOOK_2), HID_QUIRK_NO_INIT_REPORTS }, -+ { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_SURFACE_LAPTOP), HID_QUIRK_ALWAYS_POLL }, - { HID_USB_DEVICE(USB_VENDOR_ID_MOJO, USB_DEVICE_ID_RETRO_ADAPTER), HID_QUIRK_MULTI_INPUT }, - { HID_USB_DEVICE(USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL), HID_QUIRK_NO_INIT_REPORTS }, - { HID_USB_DEVICE(USB_VENDOR_ID_MULTIPLE_1781, USB_DEVICE_ID_RAPHNET_4NES4SNES_OLD), HID_QUIRK_MULTI_INPUT }, -diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile -index 28c4cede2d91..4afa91fdb4da 100644 ---- a/drivers/platform/x86/Makefile -+++ b/drivers/platform/x86/Makefile -@@ -85,6 +85,8 @@ obj-$(CONFIG_SURFACEBOOK2_BUTTON) += surfacebook2_button.o - obj-$(CONFIG_ACPI_SURFACE) += surface_acpi.o - obj-$(CONFIG_ACPI_SURFACE) += surface_i2c.o - obj-$(CONFIG_ACPI_SURFACE) += surface_platform.o -+obj-$(CONFIG_ACPI_SURFACE) += surface_vhf.o -+obj-$(CONFIG_ACPI_SURFACE) += surface_vhf_keyboard.o - obj-$(CONFIG_INTEL_PUNIT_IPC) += intel_punit_ipc.o - obj-$(CONFIG_INTEL_BXTWC_PMIC_TMU) += intel_bxtwc_tmu.o - obj-$(CONFIG_INTEL_TELEMETRY) += intel_telemetry_core.o \ -diff --git a/drivers/platform/x86/surface_vhf.c b/drivers/platform/x86/surface_vhf.c -new file mode 100644 -index 000000000000..2e9f2a670455 ---- /dev/null -+++ b/drivers/platform/x86/surface_vhf.c -@@ -0,0 +1,328 @@ -+/* -+ * surface_vhf.c - Microsoft Surface Virtual HID Framework Driver -+ * -+ * 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; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * The full GNU General Public License is included in the distribution in -+ * the file called "COPYING". -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Jake Day"); -+ -+#define STATUS_REG 0x0C -+#define DATA_REG 0x10 -+#define DATA_AVAIL 0x2 -+ -+static const struct acpi_device_id surface_vhf_ids[] = { -+ {"MSHW0096", 0}, -+ {"", 0}, -+}; -+ -+struct surface_kbd { -+ struct input_dev *input; -+ struct resource *res; -+ void __iomem *io_base; -+ struct clk *clk; -+ unsigned short keycodes[256]; -+}; -+ -+struct kbd_platform_data { -+ const struct matrix_keymap_data *keymap; -+ bool rep; -+}; -+ -+static const struct key_entry surface_vhf_keymap[] = { -+ { KE_KEY, 1, { KEY_ESC } }, -+ { KE_KEY, 2, { KEY_F1 } }, -+ { KE_KEY, 3, { KEY_F2 } }, -+ { KE_KEY, 4, { KEY_F3 } }, -+ { KE_KEY, 5, { KEY_F4 } }, -+ { KE_KEY, 6, { KEY_F5 } }, -+ { KE_KEY, 7, { KEY_F6 } }, -+ { KE_KEY, 8, { KEY_F7 } }, -+ { KE_KEY, 9, { KEY_F8 } }, -+ { KE_KEY, 10, { KEY_F9 } }, -+ { KE_KEY, 11, { KEY_F10 } }, -+ { KE_KEY, 12, { KEY_F11 } }, -+ { KE_KEY, 13, { KEY_F12 } }, -+ { KE_KEY, 14, { KEY_POWER } }, -+ { KE_KEY, 15, { KEY_DELETE } }, -+ { KE_KEY, 16, { KEY_GRAVE } }, -+ { KE_KEY, 17, { KEY_1 } }, -+ { KE_KEY, 18, { KEY_2 } }, -+ { KE_KEY, 19, { KEY_3 } }, -+ { KE_KEY, 20, { KEY_4 } }, -+ { KE_KEY, 21, { KEY_5 } }, -+ { KE_KEY, 23, { KEY_6 } }, -+ { KE_KEY, 23, { KEY_7 } }, -+ { KE_KEY, 24, { KEY_8 } }, -+ { KE_KEY, 25, { KEY_9 } }, -+ { KE_KEY, 26, { KEY_0 } }, -+ { KE_KEY, 27, { KEY_MINUS } }, -+ { KE_KEY, 28, { KEY_EQUAL } }, -+ { KE_KEY, 29, { KEY_BACKSPACE } }, -+ { KE_KEY, 30, { KEY_TAB } }, -+ { KE_KEY, 31, { KEY_Q } }, -+ { KE_KEY, 32, { KEY_W } }, -+ { KE_KEY, 33, { KEY_E } }, -+ { KE_KEY, 34, { KEY_R } }, -+ { KE_KEY, 35, { KEY_T } }, -+ { KE_KEY, 36, { KEY_Y } }, -+ { KE_KEY, 37, { KEY_U } }, -+ { KE_KEY, 38, { KEY_I } }, -+ { KE_KEY, 39, { KEY_O } }, -+ { KE_KEY, 40, { KEY_P } }, -+ { KE_KEY, 41, { KEY_LEFTBRACE } }, -+ { KE_KEY, 42, { KEY_RIGHTBRACE } }, -+ { KE_KEY, 43, { KEY_BACKSLASH } }, -+ { KE_KEY, 44, { KEY_CAPSLOCK } }, -+ { KE_KEY, 45, { KEY_A } }, -+ { KE_KEY, 46, { KEY_S } }, -+ { KE_KEY, 47, { KEY_D } }, -+ { KE_KEY, 48, { KEY_F } }, -+ { KE_KEY, 49, { KEY_G } }, -+ { KE_KEY, 50, { KEY_H } }, -+ { KE_KEY, 51, { KEY_J } }, -+ { KE_KEY, 52, { KEY_K } }, -+ { KE_KEY, 53, { KEY_L } }, -+ { KE_KEY, 54, { KEY_SEMICOLON } }, -+ { KE_KEY, 55, { KEY_APOSTROPHE } }, -+ { KE_KEY, 56, { KEY_ENTER } }, -+ { KE_KEY, 57, { KEY_LEFTSHIFT } }, -+ { KE_KEY, 58, { KEY_Z } }, -+ { KE_KEY, 59, { KEY_X } }, -+ { KE_KEY, 60, { KEY_C } }, -+ { KE_KEY, 61, { KEY_V } }, -+ { KE_KEY, 62, { KEY_B } }, -+ { KE_KEY, 63, { KEY_N } }, -+ { KE_KEY, 64, { KEY_M } }, -+ { KE_KEY, 65, { KEY_COMMA } }, -+ { KE_KEY, 66, { KEY_DOT } }, -+ { KE_KEY, 67, { KEY_SLASH } }, -+ { KE_KEY, 68, { KEY_RIGHTSHIFT } }, -+ { KE_KEY, 69, { KEY_LEFTCTRL } }, -+ { KE_KEY, 70, { KEY_FN } }, -+ { KE_KEY, 71, { KEY_KPASTERISK } }, -+ { KE_KEY, 72, { KEY_LEFTALT } }, -+ { KE_KEY, 73, { KEY_SPACE } }, -+ { KE_KEY, 74, { KEY_RIGHTALT } }, -+ { KE_KEY, 75, { KEY_MENU } }, -+ { KE_KEY, 76, { KEY_LEFT } }, -+ { KE_KEY, 77, { KEY_UP } }, -+ { KE_KEY, 78, { KEY_DOWN } }, -+ { KE_KEY, 79, { KEY_RIGHT } }, -+ { KE_END }, -+}; -+ -+ -+static irqreturn_t surface_kbd_interrupt(int irq, void *dev_id) -+{ -+ struct surface_kbd *kbd = dev_id; -+ struct input_dev *input = kbd->input; -+ unsigned int key; -+ u8 sts, val; -+ -+ sts = readb(kbd->io_base + STATUS_REG); -+ if (!(sts & DATA_AVAIL)) -+ return IRQ_NONE; -+ -+ val = readb(kbd->io_base + DATA_REG); -+ key = kbd->keycodes[val]; -+ -+ input_event(input, EV_MSC, MSC_SCAN, val); -+ input_report_key(input, key, 1); -+ input_sync(input); -+ -+ writeb(0, kbd->io_base + STATUS_REG); -+ -+ return IRQ_HANDLED; -+} -+ -+static int surface_vhf_probe(struct platform_device *pdev) -+{ -+ struct resource *res; -+ struct surface_kbd *kbd; -+ struct input_dev *input_dev; -+ int error; -+ int ret; -+ int irq; -+ -+ pr_info("Surface VHF found\n"); -+ -+ pr_info("Surface VHF resources: %u\n", pdev->num_resources); -+ -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ if (!res) { -+ dev_err(&pdev->dev, "Surface VHF: No keyboard resource defined\n"); -+ return -EBUSY; -+ } -+ -+ irq = platform_get_irq(pdev, 0); -+ if (irq < 0) { -+ dev_err(&pdev->dev, "not able to get irq for the device\n"); -+ return irq; -+ } -+ -+ kbd = kzalloc(sizeof(*kbd), GFP_KERNEL); -+ input_dev = input_allocate_device(); -+ if (!kbd || !input_dev) { -+ dev_err(&pdev->dev, "Surface VHF: Out of memory\n"); -+ error = -ENOMEM; -+ goto err_free_mem; -+ } -+ -+ kbd->input = input_dev; -+ -+ /*kbd->res = request_mem_region(res->start, resource_size(res), -+ pdev->name); -+ if (!kbd->res) { -+ dev_err(&pdev->dev, "keyboard region already claimed\n"); -+ error = -EBUSY; -+ goto err_free_mem; -+ }*/ -+ -+ kbd->io_base = ioremap(res->start, resource_size(res)); -+ if (!kbd->io_base) { -+ dev_err(&pdev->dev, "Surface VHF: ioremap failed for kbd region\n"); -+ error = -ENOMEM; -+ goto err_release_mem_region; -+ } -+ -+ kbd->clk = clk_get(&pdev->dev, NULL); -+ if (IS_ERR(kbd->clk)) { -+ error = PTR_ERR(kbd->clk); -+ goto err_iounmap; -+ } -+ -+ input_dev->name = "Surface Laptop Keyboard"; -+ input_dev->phys = "keyboard/input0"; -+ input_dev->dev.parent = &pdev->dev; -+ input_dev->id.bustype = BUS_HOST; -+ input_dev->id.vendor = 0x045e; -+ input_dev->id.product = 0xf001; -+ input_dev->id.version = 0x0001; -+ -+ __set_bit(EV_KEY, input_dev->evbit); -+ input_set_capability(input_dev, EV_MSC, MSC_SCAN); -+ -+ input_dev->keycode = kbd->keycodes; -+ input_dev->keycodesize = sizeof(kbd->keycodes[0]); -+ input_dev->keycodemax = ARRAY_SIZE(kbd->keycodes); -+ -+ input_set_drvdata(input_dev, kbd); -+ -+ ret = sparse_keymap_setup(input_dev, surface_vhf_keymap, NULL); -+ if (ret) -+ return ret; -+ -+ error = request_irq(irq, surface_kbd_interrupt, 0, "keyboard", kbd); -+ if (error) { -+ dev_err(&pdev->dev, "Surface VHF: Request_irq fail\n"); -+ goto err_put_clk; -+ } -+ -+ error = input_register_device(input_dev); -+ if (error) { -+ dev_err(&pdev->dev, "Surface VHF: Unable to register keyboard device\n"); -+ return 0; -+ } -+ -+ device_init_wakeup(&pdev->dev, 1); -+ platform_set_drvdata(pdev, kbd); -+ -+ return 0; -+ -+/*err_free_irq: -+ free_irq(kbd->irq, kbd);*/ -+err_put_clk: -+ clk_put(kbd->clk); -+err_iounmap: -+ iounmap(kbd->io_base); -+err_release_mem_region: -+ release_mem_region(res->start, resource_size(res)); -+err_free_mem: -+ input_free_device(input_dev); -+ kfree(kbd); -+ -+ return error; -+} -+ -+static int surface_vhf_remove(struct platform_device *pdev) -+{ -+ device_init_wakeup(&pdev->dev, false); -+ -+ return 0; -+} -+ -+static struct platform_driver surface_vhf_driver = { -+ .driver = { -+ .name = "surface_vhf", -+ .acpi_match_table = surface_vhf_ids, -+ }, -+ .probe = surface_vhf_probe, -+ .remove = surface_vhf_remove, -+}; -+MODULE_DEVICE_TABLE(acpi, surface_vhf_ids); -+ -+static acpi_status __init -+check_acpi_dev(acpi_handle handle, u32 lvl, void *context, void **rv) -+{ -+ const struct acpi_device_id *ids = context; -+ struct acpi_device *dev; -+ -+ if (acpi_bus_get_device(handle, &dev) != 0) -+ return AE_OK; -+ -+ if (acpi_match_device_ids(dev, ids) == 0) -+ if (acpi_create_platform_device(dev, NULL)) -+ dev_info(&dev->dev, -+ "Surface VHF: Created platform device\n"); -+ -+ return AE_OK; -+} -+ -+static int __init surface_vhf_init(void) -+{ -+ acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, -+ ACPI_UINT32_MAX, check_acpi_dev, NULL, -+ (void *)surface_vhf_ids, NULL); -+ -+ return platform_driver_register(&surface_vhf_driver); -+} -+module_init(surface_vhf_init); -+ -+static void __exit surface_vhf_exit(void) -+{ -+ platform_driver_unregister(&surface_vhf_driver); -+} -+module_exit(surface_vhf_exit); -diff --git a/drivers/platform/x86/surface_vhf_keyboard.c b/drivers/platform/x86/surface_vhf_keyboard.c -new file mode 100644 -index 000000000000..c619d599e4ea ---- /dev/null -+++ b/drivers/platform/x86/surface_vhf_keyboard.c -@@ -0,0 +1,73 @@ -+/* -+ * surface_vhf_keyboard.c - Microsoft Surface Virtual HID Framework Keyboard Device -+ * -+ * 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; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * The full GNU General Public License is included in the distribution in -+ * the file called "COPYING". -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Jake Day"); -+ -+static struct resource surface_vhf_keyboard_resources[] = { -+ { -+ .start = 0x1a7bbaf9, -+ .end = 0x2d356b9e, -+ .flags = IORESOURCE_MEM, -+ .name = "io-memory" -+ }, -+ { -+ .start = 21, -+ .end = 21, -+ .flags = IORESOURCE_IRQ, -+ .name = "irq", -+ } -+}; -+ -+static struct platform_device surface_vhf_keyboard = { -+ .name = "surface_vhf", -+ .resource = surface_vhf_keyboard_resources, -+ .num_resources = ARRAY_SIZE(surface_vhf_keyboard_resources), -+}; -+ -+static int __init surface_hid_init(void) -+{ -+ return platform_device_register(&surface_vhf_keyboard); -+} -+module_init(surface_hid_init); -+ -+static void __exit surface_hid_exit(void) -+{ -+ platform_device_unregister(&surface_vhf_keyboard); -+} -+module_exit(surface_hid_exit); diff --git a/patches/4.18/wifi.patch b/patches/4.18/wifi.patch deleted file mode 100644 index b7fa9efc5..000000000 --- a/patches/4.18/wifi.patch +++ /dev/null @@ -1,3 +0,0 @@ -diff --git a/scripts/leaking_addresses.pl b/scripts/leaking_addresses.pl -old mode 100755 -new mode 100644