Compare commits

...

10 Commits

Author SHA1 Message Date
Bastien Nocera 21b36d969b Disable debug
And bump version for test builds
2016-07-20 14:35:12 +02:00
Bastien Nocera da075d68de Stability fixes for Marvell Wi-Fi
https://bugzilla.kernel.org/show_bug.cgi?id=109681#c56
2016-07-20 14:16:10 +02:00
Bastien Nocera 301ce22ee9 Add sound support 2016-07-20 14:16:09 +02:00
Bastien Nocera 4fb17af00d Add driver specifically for the LID device 2016-07-19 14:22:56 +02:00
Bastien Nocera 47f491acca Fix original LID state and make sensor hub work 2016-07-19 14:22:55 +02:00
Bastien Nocera 983b6e8279 Add Surface 3 battery support
Both patches from:
https://bugzilla.kernel.org/show_bug.cgi?id=106231#c39
2016-07-19 14:22:55 +02:00
Bastien Nocera 6526ccbb68 Add support for the hardware buttons
Volume Up/Down, Windows key and power button.
2016-07-19 14:22:55 +02:00
Bastien Nocera d884e8fd12 Add Surface 3 touch cover fixes
Should make the touchpad multitouch work without breaking the CapsLock LED.
2016-07-19 14:22:55 +02:00
Bastien Nocera 999484ba1d Add Surface 3 touchscreen and pen support 2016-07-19 14:22:55 +02:00
Bastien Nocera f0c45f08df Prepare for Surface 3 patches 2016-07-19 14:22:55 +02:00
33 changed files with 4114 additions and 61 deletions

View File

@ -0,0 +1,187 @@
From de1715d88a5e80cc14455db1cf758cdf970fff22 Mon Sep 17 00:00:00 2001
From: Benjamin Tissoires <benjamin.tissoires@redhat.com>
Date: Thu, 12 May 2016 15:47:27 +0200
Subject: [PATCH 1/3] HID: input: rework HID_QUIRK_MULTI_INPUT
The purpose of HID_QUIRK_MULTI_INPUT is to have an input device per
report id. This is useful when the HID device presents several HID
collections of different device types.
The current implementation of hid-input creates one input node per id per
type (input or output). This is problematic for the LEDs of a keyboard as
they are often set through an output report. The current code creates
one input node with all the keyboard keys, and one other with only the
LEDs.
To solve this, we use a two-passes way:
- first, we initialize all input nodes and associate one per report id
- then, we register all the input nodes
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
---
drivers/hid/hid-input.c | 95 ++++++++++++++++++++++++++++---------------------
include/linux/hid.h | 1 +
2 files changed, 55 insertions(+), 41 deletions(-)
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index bcfaf32..bb2ec45 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -1458,6 +1458,31 @@ static void hidinput_cleanup_hidinput(struct hid_device *hid,
kfree(hidinput);
}
+static struct hid_input *hidinput_match(struct hid_report *report)
+{
+ struct hid_device *hid = report->device;
+ struct hid_input *hidinput;
+
+ list_for_each_entry(hidinput, &hid->inputs, list) {
+ if (hidinput->report &&
+ hidinput->report->id == report->id)
+ return hidinput;
+ }
+
+ return NULL;
+}
+
+static inline void hidinput_configure_usages(struct hid_input *hidinput,
+ struct hid_report *report)
+{
+ int i, j;
+
+ for (i = 0; i < report->maxfield; i++)
+ for (j = 0; j < report->field[i]->maxusage; j++)
+ hidinput_configure_usage(hidinput, report->field[i],
+ report->field[i]->usage + j);
+}
+
/*
* Register the input device; print a message.
* Configure the input layer interface
@@ -1468,8 +1493,8 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
{
struct hid_driver *drv = hid->driver;
struct hid_report *report;
- struct hid_input *hidinput = NULL;
- int i, j, k;
+ struct hid_input *next, *hidinput = NULL;
+ int i, k;
INIT_LIST_HEAD(&hid->inputs);
INIT_WORK(&hid->led_work, hidinput_led_worker);
@@ -1499,43 +1524,40 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
if (!report->maxfield)
continue;
+ /*
+ * Find the previous hidinput report attached
+ * to this report id.
+ */
+ if (hid->quirks & HID_QUIRK_MULTI_INPUT)
+ hidinput = hidinput_match(report);
+
if (!hidinput) {
hidinput = hidinput_allocate(hid);
if (!hidinput)
goto out_unwind;
}
- for (i = 0; i < report->maxfield; i++)
- for (j = 0; j < report->field[i]->maxusage; j++)
- hidinput_configure_usage(hidinput, report->field[i],
- report->field[i]->usage + j);
-
- if ((hid->quirks & HID_QUIRK_NO_EMPTY_INPUT) &&
- !hidinput_has_been_populated(hidinput))
- continue;
+ hidinput_configure_usages(hidinput, report);
- if (hid->quirks & HID_QUIRK_MULTI_INPUT) {
- /* This will leave hidinput NULL, so that it
- * allocates another one if we have more inputs on
- * the same interface. Some devices (e.g. Happ's
- * UGCI) cram a lot of unrelated inputs into the
- * same interface. */
+ if (hid->quirks & HID_QUIRK_MULTI_INPUT)
hidinput->report = report;
- if (drv->input_configured &&
- drv->input_configured(hid, hidinput))
- goto out_cleanup;
- if (input_register_device(hidinput->input))
- goto out_cleanup;
- hidinput = NULL;
- }
}
}
- if (hidinput && (hid->quirks & HID_QUIRK_NO_EMPTY_INPUT) &&
- !hidinput_has_been_populated(hidinput)) {
- /* no need to register an input device not populated */
- hidinput_cleanup_hidinput(hid, hidinput);
- hidinput = NULL;
+ list_for_each_entry_safe(hidinput, next, &hid->inputs, list) {
+ if ((hid->quirks & HID_QUIRK_NO_EMPTY_INPUT) &&
+ !hidinput_has_been_populated(hidinput)) {
+ /* no need to register an input device not populated */
+ hidinput_cleanup_hidinput(hid, hidinput);
+ continue;
+ }
+
+ if (drv->input_configured &&
+ drv->input_configured(hid, hidinput))
+ goto out_unwind;
+ if (input_register_device(hidinput->input))
+ goto out_unwind;
+ hidinput->registered = true;
}
if (list_empty(&hid->inputs)) {
@@ -1543,20 +1565,8 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
goto out_unwind;
}
- if (hidinput) {
- if (drv->input_configured &&
- drv->input_configured(hid, hidinput))
- goto out_cleanup;
- if (input_register_device(hidinput->input))
- goto out_cleanup;
- }
-
return 0;
-out_cleanup:
- list_del(&hidinput->list);
- input_free_device(hidinput->input);
- kfree(hidinput);
out_unwind:
/* unwind the ones we already registered */
hidinput_disconnect(hid);
@@ -1573,7 +1583,10 @@ void hidinput_disconnect(struct hid_device *hid)
list_for_each_entry_safe(hidinput, next, &hid->inputs, list) {
list_del(&hidinput->list);
- input_unregister_device(hidinput->input);
+ if (hidinput->registered)
+ input_unregister_device(hidinput->input);
+ else
+ input_free_device(hidinput->input);
kfree(hidinput);
}
diff --git a/include/linux/hid.h b/include/linux/hid.h
index 75b66ec..8a5d697 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -479,6 +479,7 @@ struct hid_input {
struct list_head list;
struct hid_report *report;
struct input_dev *input;
+ bool registered;
};
enum hid_type {
--
2.7.4

View File

@ -0,0 +1,372 @@
From 4feacbc24eea0c5f36728017575cc0ad28d8758b Mon Sep 17 00:00:00 2001
From: Benjamin Tissoires <benjamin.tissoires@redhat.com>
Date: Thu, 19 May 2016 09:24:06 -0700
Subject: [PATCH] Input: add new driver for the Surface 3
This is a basic driver for the Surface 3. I am not so sure it will work
with any firmwares as most values are encoded, but given that I only have
access to my current device with its firmware and I don't have the
datasheet, it should be OK for now.
The Surface Pen is not supported (if it is supposed to be). I'll work on
this when I get one.
Tested-by: Bastien Nocera <hadess@hadess.net>
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
---
drivers/input/touchscreen/Kconfig | 13 ++
drivers/input/touchscreen/Makefile | 1 +
drivers/input/touchscreen/surface3_spi.c | 304 +++++++++++++++++++++++++++++++
3 files changed, 318 insertions(+)
create mode 100644 drivers/input/touchscreen/surface3_spi.c
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 75443bb..c3880b9 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -1085,6 +1085,19 @@ config TOUCHSCREEN_SUR40
To compile this driver as a module, choose M here: the
module will be called sur40.
+config TOUCHSCREEN_SURFACE3_SPI
+ tristate "Ntrig/Microsoft Surface 3 SPI touchscreen"
+ depends on SPI
+ depends on GPIOLIB || COMPILE_TEST
+ help
+ Say Y here if you have the Ntrig/Microsoft SPI touchscreen
+ controller chip as found on the Surface 3 in your system.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called surface3_spi.
+
config TOUCHSCREEN_SX8654
tristate "Semtech SX8654 touchscreen"
depends on I2C
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 4b518c7..75af04d 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -66,6 +66,7 @@ obj-$(CONFIG_TOUCHSCREEN_ST1232) += st1232.o
obj-$(CONFIG_TOUCHSCREEN_STMPE) += stmpe-ts.o
obj-$(CONFIG_TOUCHSCREEN_SUN4I) += sun4i-ts.o
obj-$(CONFIG_TOUCHSCREEN_SUR40) += sur40.o
+obj-$(CONFIG_TOUCHSCREEN_SURFACE3_SPI) += surface3_spi.o
obj-$(CONFIG_TOUCHSCREEN_TI_AM335X_TSC) += ti_am335x_tsc.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o
diff --git a/drivers/input/touchscreen/surface3_spi.c b/drivers/input/touchscreen/surface3_spi.c
new file mode 100644
index 0000000..e18e742
--- /dev/null
+++ b/drivers/input/touchscreen/surface3_spi.c
@@ -0,0 +1,304 @@
+/*
+ * Driver for Ntrig/Microsoft Touchscreens over SPI
+ *
+ * Copyright (c) 2016 Red Hat Inc.
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; version 2 of the License.
+ */
+
+#include <linux/kernel.h>
+
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/input.h>
+#include <linux/input/mt.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/spi/spi.h>
+#include <linux/acpi.h>
+
+#include <asm/unaligned.h>
+
+#define SURFACE3_PACKET_SIZE 264
+
+struct surface3_ts_data {
+ struct spi_device *spi;
+ struct gpio_desc *gpiod_rst[2];
+ struct input_dev *input_dev;
+
+ u8 rd_buf[SURFACE3_PACKET_SIZE] ____cacheline_aligned;
+};
+
+struct surface3_ts_data_finger {
+ u8 status;
+ __le16 tracking_id;
+ __le16 x;
+ __le16 cx;
+ __le16 y;
+ __le16 cy;
+ __le16 width;
+ __le16 height;
+ u32 padding;
+} __packed;
+
+static int surface3_spi_read(struct surface3_ts_data *ts_data)
+{
+ struct spi_device *spi = ts_data->spi;
+
+ memset(ts_data->rd_buf, 0, sizeof(ts_data->rd_buf));
+ return spi_read(spi, ts_data->rd_buf, sizeof(ts_data->rd_buf));
+}
+
+static void surface3_spi_report_touch(struct surface3_ts_data *ts_data,
+ struct surface3_ts_data_finger *finger)
+{
+ int st = finger->status & 0x01;
+ int slot;
+
+ slot = input_mt_get_slot_by_key(ts_data->input_dev,
+ get_unaligned_le16(&finger->tracking_id));
+ if (slot < 0)
+ return;
+
+ input_mt_slot(ts_data->input_dev, slot);
+ input_mt_report_slot_state(ts_data->input_dev, MT_TOOL_FINGER, st);
+ if (st) {
+ input_report_abs(ts_data->input_dev,
+ ABS_MT_POSITION_X,
+ get_unaligned_le16(&finger->x));
+ input_report_abs(ts_data->input_dev,
+ ABS_MT_POSITION_Y,
+ get_unaligned_le16(&finger->y));
+ input_report_abs(ts_data->input_dev,
+ ABS_MT_WIDTH_MAJOR,
+ get_unaligned_le16(&finger->width));
+ input_report_abs(ts_data->input_dev,
+ ABS_MT_WIDTH_MINOR,
+ get_unaligned_le16(&finger->height));
+ }
+}
+
+static void surface3_spi_process(struct surface3_ts_data *ts_data)
+{
+ const char header[] = {0xff, 0xff, 0xff, 0xff, 0xa5, 0x5a, 0xe7, 0x7e,
+ 0x01, 0xd2, 0x00, 0x80, 0x01, 0x03, 0x03};
+ u8 *data = ts_data->rd_buf;
+ u16 timestamp;
+ unsigned int i;
+
+ if (memcmp(header, data, sizeof(header)))
+ dev_err(&ts_data->spi->dev,
+ "%s header error: %*ph, ignoring...\n",
+ __func__, (int)sizeof(header), data);
+
+ timestamp = get_unaligned_le16(&data[15]);
+
+ for (i = 0; i < 13; i++) {
+ struct surface3_ts_data_finger *finger;
+
+ finger = (struct surface3_ts_data_finger *)&data[17 +
+ i * sizeof(struct surface3_ts_data_finger)];
+
+ /*
+ * When bit 5 of status is 1, it marks the end of the report:
+ * - touch present: 0xe7
+ * - touch released: 0xe4
+ * - nothing valuable: 0xff
+ */
+ if (finger->status & 0x10)
+ break;
+
+ surface3_spi_report_touch(ts_data, finger);
+ }
+
+ input_mt_sync_frame(ts_data->input_dev);
+ input_sync(ts_data->input_dev);
+}
+
+static irqreturn_t surface3_spi_irq_handler(int irq, void *dev_id)
+{
+ struct surface3_ts_data *data = dev_id;
+
+ if (surface3_spi_read(data))
+ return IRQ_HANDLED;
+
+ dev_dbg(&data->spi->dev, "%s received -> %*ph\n",
+ __func__, SURFACE3_PACKET_SIZE, data->rd_buf);
+ surface3_spi_process(data);
+
+ return IRQ_HANDLED;
+}
+
+static void surface3_spi_power(struct surface3_ts_data *data, bool on)
+{
+ gpiod_set_value(data->gpiod_rst[0], on);
+ gpiod_set_value(data->gpiod_rst[1], on);
+ /* let the device settle a little */
+ msleep(20);
+}
+
+/**
+ * surface3_spi_get_gpio_config - Get GPIO config from ACPI/DT
+ *
+ * @ts: surface3_spi_ts_data pointer
+ */
+static int surface3_spi_get_gpio_config(struct surface3_ts_data *data)
+{
+ int error;
+ struct device *dev;
+ struct gpio_desc *gpiod;
+ int i;
+
+ dev = &data->spi->dev;
+
+ /* Get the reset lines GPIO pin number */
+ for (i = 0; i < 2; i++) {
+ gpiod = devm_gpiod_get_index(dev, NULL, i, GPIOD_OUT_LOW);
+ if (IS_ERR(gpiod)) {
+ error = PTR_ERR(gpiod);
+ if (error != -EPROBE_DEFER)
+ dev_err(dev,
+ "Failed to get power GPIO %d: %d\n",
+ i,
+ error);
+ return error;
+ }
+
+ data->gpiod_rst[i] = gpiod;
+ }
+
+ return 0;
+}
+
+static int surface3_spi_create_input(struct surface3_ts_data *data)
+{
+ struct input_dev *input;
+ int error;
+
+ input = devm_input_allocate_device(&data->spi->dev);
+ if (!input)
+ return -ENOMEM;
+
+ data->input_dev = input;
+
+ input_set_abs_params(input, ABS_MT_POSITION_X, 0, 9600, 0, 0);
+ input_abs_set_res(input, ABS_MT_POSITION_X, 40);
+ input_set_abs_params(input, ABS_MT_POSITION_Y, 0, 7200, 0, 0);
+ input_abs_set_res(input, ABS_MT_POSITION_Y, 48);
+ input_set_abs_params(input, ABS_MT_WIDTH_MAJOR, 0, 1024, 0, 0);
+ input_set_abs_params(input, ABS_MT_WIDTH_MINOR, 0, 1024, 0, 0);
+ input_mt_init_slots(input, 10, INPUT_MT_DIRECT);
+
+ input->name = "Surface3 SPI Capacitive TouchScreen";
+ input->phys = "input/ts";
+ input->id.bustype = BUS_SPI;
+ input->id.vendor = 0x045e; /* Microsoft */
+ input->id.product = 0x0000;
+ input->id.version = 0x0000;
+
+ error = input_register_device(input);
+ if (error) {
+ dev_err(&data->spi->dev,
+ "Failed to register input device: %d", error);
+ return error;
+ }
+
+ return 0;
+}
+
+static int surface3_spi_probe(struct spi_device *spi)
+{
+ struct surface3_ts_data *data;
+ int error;
+
+ /* Set up SPI*/
+ spi->bits_per_word = 8;
+ spi->mode = SPI_MODE_0;
+ error = spi_setup(spi);
+ if (error)
+ return error;
+
+ data = devm_kzalloc(&spi->dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ data->spi = spi;
+ spi_set_drvdata(spi, data);
+
+ error = surface3_spi_get_gpio_config(data);
+ if (error)
+ return error;
+
+ surface3_spi_power(data, true);
+ surface3_spi_power(data, false);
+ surface3_spi_power(data, true);
+
+ error = surface3_spi_create_input(data);
+ if (error)
+ return error;
+
+ error = devm_request_threaded_irq(&spi->dev, spi->irq,
+ NULL, surface3_spi_irq_handler,
+ IRQF_ONESHOT,
+ "Surface3-irq", data);
+ if (error)
+ return error;
+
+ return 0;
+}
+
+static int __maybe_unused surface3_spi_suspend(struct device *dev)
+{
+ struct spi_device *spi = to_spi_device(dev);
+ struct surface3_ts_data *data = spi_get_drvdata(spi);
+
+ disable_irq(data->spi->irq);
+
+ surface3_spi_power(data, false);
+
+ return 0;
+}
+
+static int __maybe_unused surface3_spi_resume(struct device *dev)
+{
+ struct spi_device *spi = to_spi_device(dev);
+ struct surface3_ts_data *data = spi_get_drvdata(spi);
+
+ surface3_spi_power(data, true);
+
+ enable_irq(data->spi->irq);
+
+ return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(surface3_spi_pm_ops,
+ surface3_spi_suspend,
+ surface3_spi_resume);
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id surface3_spi_acpi_match[] = {
+ { "MSHW0037", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(acpi, surface3_spi_acpi_match);
+#endif
+
+static struct spi_driver surface3_spi_driver = {
+ .driver = {
+ .name = "Surface3-spi",
+ .acpi_match_table = ACPI_PTR(surface3_spi_acpi_match),
+ .pm = &surface3_spi_pm_ops,
+ },
+ .probe = surface3_spi_probe,
+};
+
+module_spi_driver(surface3_spi_driver);
+
+MODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@gmail.com>");
+MODULE_DESCRIPTION("Surface 3 SPI touchscreen driver");
+MODULE_LICENSE("GPL v2");
--
2.7.4

View File

@ -0,0 +1,37 @@
From 7e990a7b8f8bd62a806c4804608d00640352841f Mon Sep 17 00:00:00 2001
From: Benjamin Tissoires <benjamin.tissoires@redhat.com>
Date: Thu, 12 May 2016 11:21:13 +0200
Subject: [PATCH 1/6] Input - soc_button_array: use gpio_is_valid()
gpio_keys will later use gpio_is_valid(). To match the actual
behavior, we should use it here too.
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
---
drivers/input/misc/soc_button_array.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/input/misc/soc_button_array.c b/drivers/input/misc/soc_button_array.c
index c14b827..bbd433c 100644
--- a/drivers/input/misc/soc_button_array.c
+++ b/drivers/input/misc/soc_button_array.c
@@ -17,6 +17,7 @@
#include <linux/acpi.h>
#include <linux/gpio/consumer.h>
#include <linux/gpio_keys.h>
+#include <linux/gpio.h>
#include <linux/platform_device.h>
/*
@@ -92,7 +93,7 @@ soc_button_device_create(struct platform_device *pdev,
continue;
gpio = soc_button_lookup_gpio(&pdev->dev, info->acpi_index);
- if (gpio < 0)
+ if (!gpio_is_valid(gpio))
continue;
gpio_keys[n_buttons].type = info->event_type;
--
2.7.4

View File

@ -0,0 +1,106 @@
From 427ee20610a7c252e99d08e08e70a4203c6059d0 Mon Sep 17 00:00:00 2001
From: Stephen Just <stephenjust@gmail.com>
Date: Fri, 27 May 2016 16:28:09 -0700
Subject: [PATCH] Input: surface3_spi - Prepare to add support for Surface Pen
Surface Pens can be supported by handling a second report type. Prepare
for this change.
Signed-off-by: Stephen Just <stephenjust@gmail.com>
Reviewed-and-tested-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
---
drivers/input/touchscreen/surface3_spi.c | 39 +++++++++++++++++++++-----------
1 file changed, 26 insertions(+), 13 deletions(-)
diff --git a/drivers/input/touchscreen/surface3_spi.c b/drivers/input/touchscreen/surface3_spi.c
index e18e742..e6cea7e 100644
--- a/drivers/input/touchscreen/surface3_spi.c
+++ b/drivers/input/touchscreen/surface3_spi.c
@@ -26,6 +26,8 @@
#define SURFACE3_PACKET_SIZE 264
+#define SURFACE3_REPORT_TOUCH 0xd2
+
struct surface3_ts_data {
struct spi_device *spi;
struct gpio_desc *gpiod_rst[2];
@@ -83,19 +85,10 @@ static void surface3_spi_report_touch(struct surface3_ts_data *ts_data,
}
}
-static void surface3_spi_process(struct surface3_ts_data *ts_data)
+static void surface3_spi_process_touch(struct surface3_ts_data *ts_data, u8 *data)
{
- const char header[] = {0xff, 0xff, 0xff, 0xff, 0xa5, 0x5a, 0xe7, 0x7e,
- 0x01, 0xd2, 0x00, 0x80, 0x01, 0x03, 0x03};
- u8 *data = ts_data->rd_buf;
u16 timestamp;
unsigned int i;
-
- if (memcmp(header, data, sizeof(header)))
- dev_err(&ts_data->spi->dev,
- "%s header error: %*ph, ignoring...\n",
- __func__, (int)sizeof(header), data);
-
timestamp = get_unaligned_le16(&data[15]);
for (i = 0; i < 13; i++) {
@@ -120,6 +113,26 @@ static void surface3_spi_process(struct surface3_ts_data *ts_data)
input_sync(ts_data->input_dev);
}
+static void surface3_spi_process(struct surface3_ts_data *ts_data)
+{
+ const char header[] = {
+ 0xff, 0xff, 0xff, 0xff, 0xa5, 0x5a, 0xe7, 0x7e, 0x01
+ };
+ u8 *data = ts_data->rd_buf;
+
+ if (memcmp(header, data, sizeof(header)))
+ dev_err(&ts_data->spi->dev,
+ "%s header error: %*ph, ignoring...\n",
+ __func__, (int)sizeof(header), data);
+
+ if (data[9] == SURFACE3_REPORT_TOUCH)
+ surface3_spi_process_touch(ts_data, data);
+ else
+ dev_err(&ts_data->spi->dev,
+ "%s unknown packet type: %x, ignoring...\n",
+ __func__, data[9]);
+}
+
static irqreturn_t surface3_spi_irq_handler(int irq, void *dev_id)
{
struct surface3_ts_data *data = dev_id;
@@ -175,7 +188,7 @@ static int surface3_spi_get_gpio_config(struct surface3_ts_data *data)
return 0;
}
-static int surface3_spi_create_input(struct surface3_ts_data *data)
+static int surface3_spi_create_touch_input(struct surface3_ts_data *data)
{
struct input_dev *input;
int error;
@@ -198,7 +211,7 @@ static int surface3_spi_create_input(struct surface3_ts_data *data)
input->phys = "input/ts";
input->id.bustype = BUS_SPI;
input->id.vendor = 0x045e; /* Microsoft */
- input->id.product = 0x0000;
+ input->id.product = 0x0001;
input->id.version = 0x0000;
error = input_register_device(input);
@@ -238,7 +251,7 @@ static int surface3_spi_probe(struct spi_device *spi)
surface3_spi_power(data, false);
surface3_spi_power(data, true);
- error = surface3_spi_create_input(data);
+ error = surface3_spi_create_touch_input(data);
if (error)
return error;
--
2.7.4

View File

@ -0,0 +1,191 @@
From 72fb4765ac9eea56a94282f29cdc70706f21494e Mon Sep 17 00:00:00 2001
From: Stephen Just <stephenjust@gmail.com>
Date: Fri, 27 May 2016 16:29:39 -0700
Subject: [PATCH] Input: surface3_spi - add surface pen support for Surface 3
This change creates a second input device which will handle input from
a Surface Pen. The Surface Pen supplies a different packet header than
touch events, so it is simple to handle one or the other.
This patch handles both the newer Surface Pen with one button, and the
older variant with a second button to switch to Eraser mode.
Signed-off-by: Stephen Just <stephenjust@gmail.com>
Reviewed-and-tested-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
---
drivers/input/touchscreen/surface3_spi.c | 114 ++++++++++++++++++++++++++++++-
1 file changed, 112 insertions(+), 2 deletions(-)
diff --git a/drivers/input/touchscreen/surface3_spi.c b/drivers/input/touchscreen/surface3_spi.c
index e6cea7e..e12fb9b 100644
--- a/drivers/input/touchscreen/surface3_spi.c
+++ b/drivers/input/touchscreen/surface3_spi.c
@@ -27,11 +27,14 @@
#define SURFACE3_PACKET_SIZE 264
#define SURFACE3_REPORT_TOUCH 0xd2
+#define SURFACE3_REPORT_PEN 0x16
struct surface3_ts_data {
struct spi_device *spi;
struct gpio_desc *gpiod_rst[2];
struct input_dev *input_dev;
+ struct input_dev *pen_input_dev;
+ int pen_tool;
u8 rd_buf[SURFACE3_PACKET_SIZE] ____cacheline_aligned;
};
@@ -48,6 +51,14 @@ struct surface3_ts_data_finger {
u32 padding;
} __packed;
+struct surface3_ts_data_pen {
+ u8 status;
+ __le16 x;
+ __le16 y;
+ __le16 pressure;
+ u8 padding;
+} __packed;
+
static int surface3_spi_read(struct surface3_ts_data *ts_data)
{
struct spi_device *spi = ts_data->spi;
@@ -113,6 +124,53 @@ static void surface3_spi_process_touch(struct surface3_ts_data *ts_data, u8 *dat
input_sync(ts_data->input_dev);
}
+static void surface3_spi_report_pen(struct surface3_ts_data *ts_data,
+ struct surface3_ts_data_pen *pen)
+{
+ struct input_dev *dev = ts_data->pen_input_dev;
+ int st = pen->status;
+ int prox = st & 0x01;
+ int rubber = st & 0x18;
+ int tool = (prox && rubber) ? BTN_TOOL_RUBBER : BTN_TOOL_PEN;
+
+ /* fake proximity out to switch tools */
+ if (ts_data->pen_tool != tool) {
+ input_report_key(dev, ts_data->pen_tool, 0);
+ input_sync(dev);
+ ts_data->pen_tool = tool;
+ }
+
+ input_report_key(dev, BTN_TOUCH, st & 0x12);
+
+ input_report_key(dev, ts_data->pen_tool, prox);
+
+ if (st) {
+ input_report_key(dev,
+ BTN_STYLUS,
+ st & 0x04);
+
+ input_report_abs(dev,
+ ABS_X,
+ get_unaligned_le16(&pen->x));
+ input_report_abs(dev,
+ ABS_Y,
+ get_unaligned_le16(&pen->y));
+ input_report_abs(dev,
+ ABS_PRESSURE,
+ get_unaligned_le16(&pen->pressure));
+ }
+}
+
+static void surface3_spi_process_pen(struct surface3_ts_data *ts_data, u8 *data)
+{
+ struct surface3_ts_data_pen *pen;
+
+ pen = (struct surface3_ts_data_pen *)&data[15];
+
+ surface3_spi_report_pen(ts_data, pen);
+ input_sync(ts_data->pen_input_dev);
+}
+
static void surface3_spi_process(struct surface3_ts_data *ts_data)
{
const char header[] = {
@@ -125,12 +183,19 @@ static void surface3_spi_process(struct surface3_ts_data *ts_data)
"%s header error: %*ph, ignoring...\n",
__func__, (int)sizeof(header), data);
- if (data[9] == SURFACE3_REPORT_TOUCH)
+ switch (data[9]) {
+ case SURFACE3_REPORT_TOUCH:
surface3_spi_process_touch(ts_data, data);
- else
+ break;
+ case SURFACE3_REPORT_PEN:
+ surface3_spi_process_pen(ts_data, data);
+ break;
+ default:
dev_err(&ts_data->spi->dev,
"%s unknown packet type: %x, ignoring...\n",
__func__, data[9]);
+ break;
+ }
}
static irqreturn_t surface3_spi_irq_handler(int irq, void *dev_id)
@@ -224,6 +289,47 @@ static int surface3_spi_create_touch_input(struct surface3_ts_data *data)
return 0;
}
+static int surface3_spi_create_pen_input(struct surface3_ts_data *data)
+{
+ struct input_dev *input;
+ int error;
+
+ input = devm_input_allocate_device(&data->spi->dev);
+ if (!input)
+ return -ENOMEM;
+
+ data->pen_input_dev = input;
+ data->pen_tool = BTN_TOOL_PEN;
+
+ __set_bit(INPUT_PROP_DIRECT, input->propbit);
+ __set_bit(INPUT_PROP_POINTER, input->propbit);
+ input_set_abs_params(input, ABS_X, 0, 9600, 0, 0);
+ input_abs_set_res(input, ABS_X, 40);
+ input_set_abs_params(input, ABS_Y, 0, 7200, 0, 0);
+ input_abs_set_res(input, ABS_Y, 48);
+ input_set_abs_params(input, ABS_PRESSURE, 0, 1024, 0, 0);
+ input_set_capability(input, EV_KEY, BTN_TOUCH);
+ input_set_capability(input, EV_KEY, BTN_STYLUS);
+ input_set_capability(input, EV_KEY, BTN_TOOL_PEN);
+ input_set_capability(input, EV_KEY, BTN_TOOL_RUBBER);
+
+ input->name = "Surface3 SPI Pen Input";
+ input->phys = "input/ts";
+ input->id.bustype = BUS_SPI;
+ input->id.vendor = 0x045e; /* Microsoft */
+ input->id.product = 0x0002;
+ input->id.version = 0x0000;
+
+ error = input_register_device(input);
+ if (error) {
+ dev_err(&data->spi->dev,
+ "Failed to register input device: %d", error);
+ return error;
+ }
+
+ return 0;
+}
+
static int surface3_spi_probe(struct spi_device *spi)
{
struct surface3_ts_data *data;
@@ -255,6 +361,10 @@ static int surface3_spi_probe(struct spi_device *spi)
if (error)
return error;
+ error = surface3_spi_create_pen_input(data);
+ if (error)
+ return error;
+
error = devm_request_threaded_irq(&spi->dev, spi->irq,
NULL, surface3_spi_irq_handler,
IRQF_ONESHOT,
--
2.7.4

View File

@ -0,0 +1,41 @@
From a3df5bf1d383e45c54875355556bc8b3bb2889c5 Mon Sep 17 00:00:00 2001
From: Benjamin Tissoires <benjamin.tissoires@redhat.com>
Date: Tue, 31 May 2016 10:34:45 +0200
Subject: [PATCH 1/2] WIP: acpi/button: remove pointer to old lid_sysfs on
unbind
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
---
drivers/acpi/button.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c
index 5c3b091..e413599 100644
--- a/drivers/acpi/button.c
+++ b/drivers/acpi/button.c
@@ -188,9 +188,11 @@ done:
remove_dev_dir:
remove_proc_entry(acpi_device_bid(device),
acpi_lid_dir);
+ acpi_lid_dir = NULL;
acpi_device_dir(device) = NULL;
remove_lid_dir:
remove_proc_entry(ACPI_BUTTON_SUBCLASS_LID, acpi_button_dir);
+ acpi_button_dir = NULL;
remove_button_dir:
remove_proc_entry(ACPI_BUTTON_CLASS, acpi_root_dir);
goto done;
@@ -207,8 +209,10 @@ static int acpi_button_remove_fs(struct acpi_device *device)
acpi_device_dir(device));
remove_proc_entry(acpi_device_bid(device),
acpi_lid_dir);
+ acpi_lid_dir = NULL;
acpi_device_dir(device) = NULL;
remove_proc_entry(ACPI_BUTTON_SUBCLASS_LID, acpi_button_dir);
+ acpi_button_dir = NULL;
remove_proc_entry(ACPI_BUTTON_CLASS, acpi_root_dir);
return 0;
--
2.7.4

View File

@ -0,0 +1,108 @@
From 72023d2508fdd513a92e9dd25d1cc0999a0f32ee Mon Sep 17 00:00:00 2001
From: Benjamin Tissoires <benjamin.tissoires@redhat.com>
Date: Fri, 27 May 2016 17:13:50 +0200
Subject: [PATCH] WIP: i2c-hid enabled S0 S3
---
drivers/hid/i2c-hid/i2c-hid.c | 37 +++++++++++++++++++++++++++++++++++++
1 file changed, 37 insertions(+)
diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c
index b3ec4f2..d0b1355 100644
--- a/drivers/hid/i2c-hid/i2c-hid.c
+++ b/drivers/hid/i2c-hid/i2c-hid.c
@@ -154,6 +154,8 @@ struct i2c_hid {
struct mutex reset_lock;
};
+static int i2c_hid_acpi_power(struct i2c_client *client, int lvl);
+
static int __i2c_hid_command(struct i2c_client *client,
const struct i2c_hid_cmd *command, u8 reportID,
u8 reportType, u8 *args, int args_len,
@@ -245,6 +247,7 @@ static int i2c_hid_get_report(struct i2c_client *client, u8 reportType,
i2c_hid_dbg(ihid, "%s\n", __func__);
+ pm_runtime_get_sync(&client->dev);
if (reportID >= 0x0F) {
args[args_len++] = reportID;
reportID = 0x0F;
@@ -261,6 +264,7 @@ static int i2c_hid_get_report(struct i2c_client *client, u8 reportType,
return ret;
}
+ pm_runtime_put(&client->dev);
return 0;
}
@@ -584,6 +588,9 @@ static int i2c_hid_get_raw_report(struct hid_device *hid,
ret_count = ihid->rawbuf[0] | (ihid->rawbuf[1] << 8);
+ i2c_hid_dbg(ihid, "report (len=%d): %*ph\n",
+ (int)ask_count, (int)ask_count, ihid->rawbuf);
+
if (ret_count <= 2)
return 0;
@@ -789,6 +796,8 @@ static int i2c_hid_power(struct hid_device *hid, int lvl)
pm_runtime_put(&client->dev);
break;
}
+
+ i2c_hid_acpi_power(client, lvl);
return 0;
}
@@ -909,12 +918,38 @@ static const struct acpi_device_id i2c_hid_acpi_match[] = {
{ },
};
MODULE_DEVICE_TABLE(acpi, i2c_hid_acpi_match);
+
+static int i2c_hid_acpi_power(struct i2c_client *client, int lvl)
+{
+ int error = 0;
+
+ pr_err("%s lvl: %d %s:%d\n", __func__, lvl, __FILE__, __LINE__);
+
+ switch (lvl) {
+ case PM_HINT_FULLON:
+ error = acpi_bus_set_power(ACPI_HANDLE(&client->dev), ACPI_STATE_D0);
+ break;
+ case PM_HINT_NORMAL:
+ error = acpi_bus_set_power(ACPI_HANDLE(&client->dev), ACPI_STATE_D3);
+ break;
+ }
+ if (error)
+ dev_warn(&client->dev, "%s: error changing power state: %d\n", __func__, error);
+
+ return 0;
+}
+
#else
static inline int i2c_hid_acpi_pdata(struct i2c_client *client,
struct i2c_hid_platform_data *pdata)
{
return -ENODEV;
}
+
+static inline int i2c_hid_acpi_power(struct i2c_client *client, int lvl)
+{
+ return 0;
+}
#endif
#ifdef CONFIG_OF
@@ -1004,6 +1039,8 @@ static int i2c_hid_probe(struct i2c_client *client,
ihid->client = client;
+ i2c_hid_acpi_power(client, PM_HINT_FULLON);
+
hidRegister = ihid->pdata.hid_descriptor_address;
ihid->wHIDDescRegister = cpu_to_le16(hidRegister);
--
2.7.4

View File

@ -0,0 +1,91 @@
From 5144a26d49d40c1847e0af496d78c54eb29f570f Mon Sep 17 00:00:00 2001
From: Benjamin Tissoires <benjamin.tissoires@redhat.com>
Date: Thu, 26 May 2016 15:29:10 +0200
Subject: [PATCH] gpiolib-acpi: make sure we trigger the events at least once
on boot
The Surface 3 has its _LID state controlled by an ACPI operation region
triggered by a GPIO event:
OperationRegion (GPOR, GeneralPurposeIo, Zero, One)
Field (GPOR, ByteAcc, NoLock, Preserve)
{
Connection (
GpioIo (Shared, PullNone, 0x0000, 0x0000, IoRestrictionNone,
"\\_SB.GPO0", 0x00, ResourceConsumer, ,
)
{ // Pin list
0x004C
}
),
HELD, 1
}
Method (_E4C, 0, Serialized) // _Exx: Edge-Triggered GPE
{
If ((HELD == One))
{
^^LID.LIDB = One
}
Else
{
^^LID.LIDB = Zero
Notify (LID, 0x80) // Status Change
}
Notify (^^PCI0.SPI1.NTRG, One) // Device Check
}
Currently, the state of LIDB is wrong until the user actually closes or
open the cover. We need to trigger the GPIO event once to update the
internal ACPI state.
Coincidentally, this also enables the integrated HID sensor hub which also
requires an ACPI gpio operation region to start initialization.
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
---
drivers/gpio/gpiolib-acpi.c | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c
index 2dc5258..71775a0 100644
--- a/drivers/gpio/gpiolib-acpi.c
+++ b/drivers/gpio/gpiolib-acpi.c
@@ -175,7 +175,7 @@ static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares,
irq_handler_t handler = NULL;
struct gpio_desc *desc;
unsigned long irqflags;
- int ret, pin, irq;
+ int ret, pin, irq, value;
if (ares->type != ACPI_RESOURCE_TYPE_GPIO)
return AE_OK;
@@ -214,6 +214,8 @@ static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares,
gpiod_direction_input(desc);
+ value = gpiod_get_value(desc);
+
ret = gpiochip_lock_as_irq(chip, pin);
if (ret) {
dev_err(chip->parent, "Failed to lock GPIO as interrupt\n");
@@ -266,6 +268,15 @@ static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares,
}
list_add_tail(&event->node, &acpi_gpio->events);
+
+ /*
+ * Make sure we trigger the initial state of the IRQ when
+ * using RISING or FALLING.
+ */
+ if (((irqflags & IRQF_TRIGGER_RISING) && value == 1) ||
+ ((irqflags & IRQF_TRIGGER_FALLING) && value == 0))
+ handler(-1, event);
+
return AE_OK;
fail_free_event:
--
2.7.4

View File

@ -0,0 +1,756 @@
From c4827e382726f31e069860af7a9af9bdef4b8bfb Mon Sep 17 00:00:00 2001
From: Benjamin Tissoires <benjamin.tissoires@redhat.com>
Date: Tue, 24 May 2016 22:30:49 +0200
Subject: [PATCH] power: MSHW0011 rev-eng implementation
MSHW0011 replaces the battery firmware by using ACPI operation regions.
The values have been obtained by reverse engineering, and are subject to
errors. Looks like it works on overall pretty well.
I couldn't manage to get the IRQ correctly triggered, so I am using a
good old polling thread to check for changes.
The acpica bits need their own patch with a little more love.
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
---
drivers/acpi/acpica/exfield.c | 11 +
drivers/power/Kconfig | 8 +
drivers/power/Makefile | 1 +
drivers/power/surface3_power.c | 674 +++++++++++++++++++++++++++++++++++++++++
4 files changed, 694 insertions(+)
create mode 100644 drivers/power/surface3_power.c
diff --git a/drivers/acpi/acpica/exfield.c b/drivers/acpi/acpica/exfield.c
index d5d8020..f386675 100644
--- a/drivers/acpi/acpica/exfield.c
+++ b/drivers/acpi/acpica/exfield.c
@@ -413,6 +413,17 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc,
* Data[x-1]: (Bytes 2-x of the arbitrary length data buffer)
*/
length += 2;
+
+ /*
+ * bug? in the MS Surface 3: length is 2 but the command
+ * needs 3 parameters.
+ * Functions like BIX requires a lot of in/out data,
+ * so just take the incoming buffer length as the
+ * reference.
+ */
+ if (accessor_type == 0xf)
+ length = source_desc->buffer.length;
+
function = ACPI_WRITE | (accessor_type << 16);
} else { /* IPMI */
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index 421770d..fb54d8b 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -509,6 +509,14 @@ config AXP20X_POWER
This driver provides support for the power supply features of
AXP20x PMIC.
+config SURFACE3_POWER
+ tristate "Surface 3 power management driver"
+ depends on I2C
+ depends on GPIOLIB
+ help
+ This driver provides support for the power supply features of
+ the Surface 3.
+
endif # POWER_SUPPLY
source "drivers/power/reset/Kconfig"
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index e46b75d..a147a0e 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -74,3 +74,4 @@ obj-$(CONFIG_CHARGER_TPS65217) += tps65217_charger.o
obj-$(CONFIG_POWER_RESET) += reset/
obj-$(CONFIG_AXP288_FUEL_GAUGE) += axp288_fuel_gauge.o
obj-$(CONFIG_AXP288_CHARGER) += axp288_charger.o
+obj-$(CONFIG_SURFACE3_POWER) += surface3_power.o
diff --git a/drivers/power/surface3_power.c b/drivers/power/surface3_power.c
new file mode 100644
index 0000000..eee21d3
--- /dev/null
+++ b/drivers/power/surface3_power.c
@@ -0,0 +1,674 @@
+/*
+ * Supports for the power IC on the Surface 3 tablet.
+ *
+ * (C) Copyright 2016 Red Hat, Inc
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2
+ * of the License.
+ */
+
+/*
+ * This driver has been reverse-engineered by parsing the DSDT of the Surface 3
+ * and looking at the registers of the chips.
+ *
+ * The DSDT allowed to find out that:
+ * - the driver is required for the ACPI BAT0 device to communicate to the chip
+ * through an operation region.
+ * - the various defines for the operation region functions to communicate with
+ * this driver
+ * - the DSM 3f99e367-6220-4955-8b0f-06ef2ae79412 allows to trigger ACPI
+ * events to BAT0 (the code is all available in the DSDT).
+ *
+ * Further findings regarding the 2 chips declared in the MSHW0011 are:
+ * - there are 2 chips declared:
+ * . 0x22 seems to control the ADP1 line status (and probably the charger)
+ * . 0x55 controls the battery directly
+ * - the battery chip uses a SMBus protocol (using plain SMBus allows non
+ * destructive commands):
+ * . the commands/registers used are in the range 0x00..0x7F
+ * . if bit 8 (0x80) is set in the SMBus command, the returned value is the
+ * same as when it is not set. There is a high chance this bit is the
+ * read/write
+ * . the various registers semantic as been deduced by observing the register
+ * dumps.
+ */
+
+#include <linux/kernel.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/acpi.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+
+#include <asm/unaligned.h>
+
+#define POLL_INTERVAL (HZ * 2)
+
+static bool dump_registers;
+module_param_named(dump_registers, dump_registers, bool, 0644);
+MODULE_PARM_DESC(dump_registers,
+ "Dump the SMBus register at probe (debugging only).");
+
+struct mshw0011_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;
+};
+
+struct mshw0011_lookup {
+ struct mshw0011_data *cdata;
+ unsigned int n;
+ unsigned int index;
+ int addr;
+};
+
+struct mshw0011_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 MSHW0011_CMD_DEST_BAT0 0x01
+#define MSHW0011_CMD_DEST_ADP1 0x03
+
+#define MSHW0011_CMD_BAT0_STA 0x01
+#define MSHW0011_CMD_BAT0_BIX 0x02
+#define MSHW0011_CMD_BAT0_BCT 0x03
+#define MSHW0011_CMD_BAT0_BTM 0x04
+#define MSHW0011_CMD_BAT0_BST 0x05
+#define MSHW0011_CMD_BAT0_BTP 0x06
+#define MSHW0011_CMD_ADP1_PSR 0x07
+#define MSHW0011_CMD_BAT0_PSOC 0x09
+#define MSHW0011_CMD_BAT0_PMAX 0x0A
+#define MSHW0011_CMD_BAT0_PSRC 0x0B
+#define MSHW0011_CMD_BAT0_CHGI 0x0C
+#define MSHW0011_CMD_BAT0_ARTG 0x0D
+
+#define MSHW0011_NOTIFY_GET_VERSION 0x00
+#define MSHW0011_NOTIFY_ADP1 0x01
+#define MSHW0011_NOTIFY_BAT0 0x02
+
+#define MSHW0011_ADP1_REG_PSR 0x03
+
+#define MSHW0011_BAT0_REG_CAPACITY 0x0c
+#define MSHW0011_BAT0_REG_VOLTAGE 0x08
+#define MSHW0011_BAT0_REG_RATE 0x14
+#define MSHW0011_BAT0_REG_OEM 0x45
+#define MSHW0011_BAT0_REG_TYPE 0x4e
+#define MSHW0011_BAT0_REG_SERIAL_NO 0x56
+#define MSHW0011_BAT0_REG_CYCLE_CNT 0x6e
+
+#define MSHW0011_EV_2_5 0x1ff
+
+static int mshw0011_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
+mshw0011_notify(struct mshw0011_data *cdata, u8 arg1, u8 arg2,
+ unsigned int *ret_value)
+{
+ static const u8 mshw0011_guid[] = {
+ 0x67, 0xE3, 0x99, 0x3F, 0x20, 0x62, 0x55, 0x49,
+ 0x8b, 0x0f, 0x06, 0xef, 0x2a, 0xe7, 0x94, 0x12,
+ };
+ union acpi_object *obj;
+ struct acpi_device *adev;
+ acpi_handle handle;
+ unsigned int i;
+
+ handle = ACPI_HANDLE(&cdata->adp1->dev);
+ if (!handle || acpi_bus_get_device(handle, &adev))
+ return -ENODEV;
+
+ obj = acpi_evaluate_dsm_typed(handle, mshw0011_guid, arg1, arg2, NULL,
+ ACPI_TYPE_BUFFER);
+ if (!obj) {
+ dev_err(&cdata->adp1->dev, "device _DSM execution failed\n");
+ return -ENODEV;
+ }
+
+ *ret_value = 0;
+ for (i = 0; i < obj->buffer.length; i++)
+ *ret_value |= obj->buffer.pointer[i] << (i * 8);
+
+ ACPI_FREE(obj);
+ return 0;
+}
+
+static const struct bix default_bix = {
+ .revision = 0x00,
+ .power_unit = 0x01,
+ .design_capacity = 0x1dca,
+ .last_full_charg_capacity = 0x1dca,
+ .battery_technology = 0x01,
+ .design_voltage = 0x10df,
+ .design_capacity_of_warning = 0x8f,
+ .design_capacity_of_low = 0x47,
+ .cycle_count = 0xffffffff,
+ .measurement_accuracy = 0x00015F90,
+ .max_sampling_time = 0x03E8,
+ .min_sampling_time = 0x03E8,
+ .max_average_interval = 0x03E8,
+ .min_average_interval = 0x03E8,
+ .battery_capacity_granularity_1 = 0x45,
+ .battery_capacity_granularity_2 = 0x11,
+ .model = "P11G8M",
+ .serial = "",
+ .type = "LION",
+ .OEM = "",
+};
+
+static int mshw0011_bix(struct mshw0011_data *cdata, struct bix *bix)
+{
+ struct i2c_client *client = cdata->bat0;
+ int ret;
+ char buf[10];
+
+ *bix = default_bix;
+
+ /* get serial number */
+ ret = mshw0011_i2c_read_block(client, MSHW0011_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, MSHW0011_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 = mshw0011_i2c_read_block(client, MSHW0011_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 mshw0011_bst(struct mshw0011_data *cdata, struct bst *bst)
+{
+ struct i2c_client *client = cdata->bat0;
+ int rate, capacity, voltage;
+ s16 tmp;
+
+ rate = i2c_smbus_read_word_data(client, MSHW0011_BAT0_REG_RATE);
+ if (rate < 0)
+ return rate;
+
+ capacity = i2c_smbus_read_word_data(client, MSHW0011_BAT0_REG_CAPACITY);
+ if (capacity < 0)
+ return capacity;
+
+ voltage = i2c_smbus_read_word_data(client, MSHW0011_BAT0_REG_VOLTAGE);
+ if (voltage < 0)
+ return voltage;
+
+ tmp = le16_to_cpu(rate);
+ bst->battery_present_rate = (s32)tmp;
+ bst->battery_state = bst->battery_present_rate < 0 ? 0x01 : 0x02;
+ bst->battery_remaining_capacity = le16_to_cpu(capacity);
+ bst->battery_present_voltage = le16_to_cpu(voltage);
+
+ return 0;
+}
+
+static int mshw0011_adp_psr(struct mshw0011_data *cdata)
+{
+ struct i2c_client *client = cdata->adp1;
+ int ret;
+
+ ret = i2c_smbus_read_byte_data(client, MSHW0011_ADP1_REG_PSR);
+ if (ret < 0)
+ return ret;
+
+ return ret;
+}
+
+static int mshw0011_isr(struct mshw0011_data *cdata)
+{
+ struct bst bst;
+ int ret;
+ bool status, bat_status;
+
+ ret = mshw0011_adp_psr(cdata);
+ if (ret < 0)
+ return ret;
+
+ status = ret;
+
+ if (status != cdata->charging)
+ mshw0011_notify(cdata, cdata->notify_version,
+ MSHW0011_NOTIFY_ADP1, &ret);
+
+ cdata->charging = status;
+
+ ret = mshw0011_bst(cdata, &bst);
+ if (ret < 0)
+ return ret;
+
+ bat_status = bst.battery_present_rate >= 0;
+
+ if (bat_status != cdata->bat_charging)
+ mshw0011_notify(cdata, cdata->notify_version,
+ MSHW0011_NOTIFY_BAT0, &ret);
+
+ cdata->bat_charging = bat_status;
+
+ return 0;
+}
+
+static int mshw0011_poll_task(void *data)
+{
+ struct mshw0011_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 = mshw0011_isr(data);
+ if (ret)
+ goto out;
+ }
+
+out:
+ cdata->kthread_running = false;
+ return ret;
+}
+
+static acpi_status
+mshw0011_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 mshw0011_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 mshw0011_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 == MSHW0011_CMD_DEST_ADP1 &&
+ gsb->cmd.arg1 == MSHW0011_CMD_ADP1_PSR) {
+ ret = mshw0011_adp_psr(cdata);
+ if (ret >= 0) {
+ status = ret;
+ ret = 0;
+ }
+ goto out;
+ }
+
+ if (gsb->cmd.arg0 != MSHW0011_CMD_DEST_BAT0) {
+ ret = AE_BAD_PARAMETER;
+ goto err;
+ }
+
+ switch (gsb->cmd.arg1) {
+ case MSHW0011_CMD_BAT0_STA:
+ status = 1;
+ ret = 0;
+ break;
+ case MSHW0011_CMD_BAT0_BIX:
+ status = 1;
+ ret = mshw0011_bix(cdata, &gsb->bix);
+ break;
+ case MSHW0011_CMD_BAT0_BTP:
+ status = 1;
+ ret = 0;
+ cdata->trip_point = gsb->cmd.arg2;
+ break;
+ case MSHW0011_CMD_BAT0_BST:
+ status = 1;
+ ret = mshw0011_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 mshw0011_install_space_handler(struct i2c_client *client)
+{
+ acpi_handle handle;
+ struct mshw0011_handler_data *data;
+ acpi_status status;
+
+ handle = ACPI_HANDLE(&client->dev);
+
+ if (!handle)
+ return -ENODEV;
+
+ data = kzalloc(sizeof(struct mshw0011_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,
+ &mshw0011_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 mshw0011_remove_space_handler(struct i2c_client *client)
+{
+ acpi_handle handle;
+ struct mshw0011_handler_data *data;
+ acpi_status status;
+
+ handle = ACPI_HANDLE(&client->dev);
+
+ if (!handle)
+ return;
+
+ acpi_remove_address_space_handler(handle,
+ ACPI_ADR_SPACE_GSBUS,
+ &mshw0011_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 mshw0011_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 mshw0011_i2c_resource_lookup(struct mshw0011_data *cdata,
+ unsigned int index)
+{
+ struct i2c_client *client = cdata->adp1;
+ struct acpi_device *adev = ACPI_COMPANION(&client->dev);
+ struct mshw0011_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 mshw0011_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 = mshw0011_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 mshw0011_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct device *dev = &client->dev;
+ struct i2c_client *bat0;
+ struct mshw0011_data *data;
+ int error, version, addr;
+
+ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ data->adp1 = client;
+ i2c_set_clientdata(client, data);
+
+ addr = mshw0011_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);
+
+ if (dump_registers)
+ mshw0011_dump_registers(client, bat0);
+
+ error = mshw0011_notify(data, 1, MSHW0011_NOTIFY_GET_VERSION, &version);
+ if (error)
+ goto out_err;
+
+ data->notify_version = version == MSHW0011_EV_2_5;
+
+ data->poll_task = kthread_run(mshw0011_poll_task, data, "mshw0011_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 = mshw0011_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 mshw0011_remove(struct i2c_client *client)
+{
+ struct mshw0011_data *cdata = i2c_get_clientdata(client);
+
+ mshw0011_remove_space_handler(client);
+
+ if (cdata->kthread_running)
+ kthread_stop(cdata->poll_task);
+
+ i2c_unregister_device(cdata->bat0);
+
+ return 0;
+}
+
+static const struct i2c_device_id mshw0011_id[] = {
+ { "MSHW0011:00", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, mshw0011_id);
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id mshw0011_acpi_match[] = {
+ { "MSHW0011", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(acpi, mshw0011_acpi_match);
+#endif
+
+static struct i2c_driver mshw0011_driver = {
+ .probe = mshw0011_probe,
+ .remove = mshw0011_remove,
+ .id_table = mshw0011_id,
+ .driver = {
+ .name = "mshw0011",
+ .acpi_match_table = ACPI_PTR(mshw0011_acpi_match),
+ },
+};
+module_i2c_driver(mshw0011_driver);
+
+MODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@gmail.com>");
+MODULE_DESCRIPTION("mshw0011 driver");
+MODULE_LICENSE("GPL v2");
--
2.5.0

View File

@ -0,0 +1,98 @@
From 0e81c6dd0106dfb2ddb065077f596756ea429adc Mon Sep 17 00:00:00 2001
From: Benjamin Tissoires <benjamin.tissoires@redhat.com>
Date: Thu, 12 May 2016 15:32:08 +0200
Subject: [PATCH 2/3] HID: multitouch: enable the Surface 3 Type Cover to
report multitouch data
There is no reasons to filter out keyboard and consumer control collections
in hid-multitouch.
With the previous hid-input fix, there is now a full support of the Type
Cover and we can remove all specific bits from hid-core and hid-microsoft.
hid-multitouch will automatically set HID_QUIRK_NO_INIT_REPORTS so we can
also remove it from the list of ushbid quirks.
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
---
drivers/hid/hid-core.c | 2 --
drivers/hid/hid-ids.h | 1 -
drivers/hid/hid-microsoft.c | 2 --
drivers/hid/hid-multitouch.c | 4 +++-
drivers/hid/usbhid/hid-quirks.c | 1 -
5 files changed, 3 insertions(+), 7 deletions(-)
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index efd8f8c..1bbbe6c 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -727,7 +727,6 @@ static void hid_scan_collection(struct hid_parser *parser, unsigned type)
(hid->product == USB_DEVICE_ID_MS_TYPE_COVER_PRO_3 ||
hid->product == USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_2 ||
hid->product == USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP ||
- hid->product == USB_DEVICE_ID_MS_TYPE_COVER_3 ||
hid->product == USB_DEVICE_ID_MS_POWER_COVER) &&
hid->group == HID_GROUP_MULTITOUCH)
hid->group = HID_GROUP_GENERIC;
@@ -1979,7 +1978,6 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP) },
- { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_7K) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_600) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_3KV1) },
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 191c981..c54d0a9 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -708,7 +708,6 @@
#define USB_DEVICE_ID_MS_TYPE_COVER_PRO_3 0x07dc
#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_3 0x07de
#define USB_DEVICE_ID_MS_POWER_COVER 0x07da
#define USB_VENDOR_ID_MOJO 0x8282
diff --git a/drivers/hid/hid-microsoft.c b/drivers/hid/hid-microsoft.c
index e924d55..cf6920b 100644
--- a/drivers/hid/hid-microsoft.c
+++ b/drivers/hid/hid-microsoft.c
@@ -288,8 +288,6 @@ static const struct hid_device_id ms_devices[] = {
.driver_data = MS_HIDINPUT },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP),
.driver_data = MS_HIDINPUT },
- { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3),
- .driver_data = MS_HIDINPUT },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_POWER_COVER),
.driver_data = MS_HIDINPUT },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_COMFORT_KEYBOARD),
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index 95b7d61..dd279d7 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -835,7 +835,9 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
if (!td->mtclass.export_all_inputs &&
field->application != HID_DG_TOUCHSCREEN &&
field->application != HID_DG_PEN &&
- field->application != HID_DG_TOUCHPAD)
+ field->application != HID_DG_TOUCHPAD &&
+ field->application != HID_GD_KEYBOARD &&
+ field->application != HID_CP_CONSUMER_CONTROL)
return -1;
/*
diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c
index b4b8c6a..baf2bad 100644
--- a/drivers/hid/usbhid/hid-quirks.c
+++ b/drivers/hid/usbhid/hid-quirks.c
@@ -98,7 +98,6 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_2, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP, HID_QUIRK_NO_INIT_REPORTS },
- { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_POWER_COVER, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_NEXIO, USB_DEVICE_ID_NEXIO_MULTITOUCH_PTI0750, HID_QUIRK_NO_INIT_REPORTS },
--
2.7.4

View File

@ -0,0 +1,34 @@
From dc16436c048a734bffabefb79508c39795f2a8bb Mon Sep 17 00:00:00 2001
From: Benjamin Tissoires <benjamin.tissoires@redhat.com>
Date: Fri, 13 May 2016 15:52:20 +0200
Subject: [PATCH 2/6] Input - soc_button_array: bail out earlier if gpiod_count
is null
The PNP0C40 device of the Surface 3 doesn't have any GPIO attached to it.
Instead of trying to access the GPIO, request the count beforehand and
bail out if it is null or if an error is returned.
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
---
drivers/input/misc/soc_button_array.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/drivers/input/misc/soc_button_array.c b/drivers/input/misc/soc_button_array.c
index bbd433c..5467d04 100644
--- a/drivers/input/misc/soc_button_array.c
+++ b/drivers/input/misc/soc_button_array.c
@@ -167,6 +167,11 @@ static int soc_button_probe(struct platform_device *pdev)
button_info = (struct soc_button_info *)id->driver_data;
+ if (gpiod_count(&pdev->dev, KBUILD_MODNAME) <= 0) {
+ dev_info(&pdev->dev, "no GPIO attached, ignoring...\n");
+ return -ENODEV;
+ }
+
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
--
2.7.4

View File

@ -0,0 +1,373 @@
From 59131c2cc6f95e7517d73b2e8eefa890284ddf08 Mon Sep 17 00:00:00 2001
From: Benjamin Tissoires <benjamin.tissoires@redhat.com>
Date: Fri, 3 Jun 2016 18:41:02 +0200
Subject: [PATCH 2/2] WIP: add custom surface3 platform device for controlling
LID and hotplug
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
---
drivers/platform/x86/Kconfig | 12 ++
drivers/platform/x86/Makefile | 1 +
drivers/platform/x86/surface3-wmi.c | 315 ++++++++++++++++++++++++++++++++++++
3 files changed, 328 insertions(+)
create mode 100644 drivers/platform/x86/surface3-wmi.c
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 3ec0025..376999b 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -363,6 +363,18 @@ config IDEAPAD_LAPTOP
This is a driver for Lenovo IdeaPad netbooks contains drivers for
rfkill switch, hotkey, fan control and backlight control.
+config SURFACE3_WMI
+ tristate "Surface 3 WMI Driver"
+ depends on ACPI_WMI
+ depends on DMI
+ depends on INPUT
+ depends on SPI
+ ---help---
+ Say Y here if you have a Surface 3.
+
+ To compile this driver as a module, choose M here: the module will
+ be called surface3-wmi.
+
config THINKPAD_ACPI
tristate "ThinkPad ACPI Laptop Extras"
depends on ACPI
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index 9b11b40..7324919 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -34,6 +34,7 @@ obj-$(CONFIG_PANASONIC_LAPTOP) += panasonic-laptop.o
obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o
obj-$(CONFIG_ACPI_WMI) += wmi.o
obj-$(CONFIG_MSI_WMI) += msi-wmi.o
+obj-$(CONFIG_SURFACE3_WMI) += surface3-wmi.o
obj-$(CONFIG_TOPSTAR_LAPTOP) += topstar-laptop.o
# toshiba_acpi must link after wmi to ensure that wmi devices are found
diff --git a/drivers/platform/x86/surface3-wmi.c b/drivers/platform/x86/surface3-wmi.c
new file mode 100644
index 0000000..92f7a38
--- /dev/null
+++ b/drivers/platform/x86/surface3-wmi.c
@@ -0,0 +1,315 @@
+/*
+ * Driver for the LID cover switch of the Surface 3
+ *
+ * Copyright (c) 2016 Red Hat Inc.
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; version 2 of the License.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#include <linux/acpi.h>
+#include <linux/dmi.h>
+#include <linux/input.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+
+MODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@redhat.com>");
+MODULE_DESCRIPTION("Surface 3 platform driver");
+MODULE_LICENSE("GPL");
+
+#define ACPI_BUTTON_HID_LID "PNP0C0D"
+#define SPI_CTL_OBJ_NAME "SPI"
+#define SPI_TS_OBJ_NAME "NTRG"
+
+#define SURFACE3_LID_GUID "F7CC25EC-D20B-404C-8903-0ED4359C18AE"
+
+MODULE_ALIAS("wmi:" SURFACE3_LID_GUID);
+
+static const struct dmi_system_id surface3_dmi_table[] = {
+#if defined(CONFIG_X86)
+ {
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Surface 3"),
+ },
+ },
+#endif
+ { }
+};
+
+struct surface3_wmi {
+ struct platform_device *spi_master_pdev;
+ struct acpi_device *spi_master_adev;
+ struct acpi_device *touchscreen_adev;
+ struct acpi_device *pnp0c0d_adev;
+ struct acpi_hotplug_context hp;
+ struct input_dev *input;
+};
+
+static struct platform_device *s3_wmi_pdev;
+
+static struct surface3_wmi s3_wmi;
+
+static DEFINE_MUTEX(s3_wmi_lock);
+
+static int s3_wmi_query_block(const char *guid, int instance, int *ret)
+{
+ acpi_status status;
+ union acpi_object *obj;
+
+ struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
+
+ mutex_lock(&s3_wmi_lock);
+ status = wmi_query_block(guid, instance, &output);
+
+ obj = output.pointer;
+
+ if (!obj || obj->type != ACPI_TYPE_INTEGER) {
+ if (obj) {
+ pr_err("query block returned object "
+ "type: %d - buffer length:%d\n", obj->type,
+ obj->type == ACPI_TYPE_BUFFER ?
+ obj->buffer.length : 0);
+ }
+ kfree(obj);
+ return -EINVAL;
+ }
+ *ret = obj->integer.value;
+ kfree(obj);
+ mutex_unlock(&s3_wmi_lock);
+ return 0;
+}
+
+static inline int s3_wmi_query_lid(int *ret)
+{
+ return s3_wmi_query_block(SURFACE3_LID_GUID, 0, ret);
+}
+
+static int s3_wmi_send_lid_state(int *return_value)
+{
+ int ret, lid_sw;
+
+ ret = s3_wmi_query_lid(&lid_sw);
+ if (ret)
+ return ret;
+
+ input_report_switch(s3_wmi.input, SW_LID, lid_sw);
+ input_sync(s3_wmi.input);
+
+ if (return_value)
+ *return_value = lid_sw;
+
+ return 0;
+}
+
+static int s3_wmi_hp_notify(struct acpi_device *adev, u32 value)
+{
+ int ret, lid_sw;
+ ret = s3_wmi_send_lid_state(&lid_sw);
+ if (ret)
+ return ret;
+
+ if (lid_sw) {
+ platform_device_unregister(s3_wmi.spi_master_pdev);
+ acpi_bus_trim(s3_wmi.spi_master_adev);
+ } else {
+ acpi_bus_scan(s3_wmi.spi_master_adev->handle);
+ }
+
+ return 0;
+}
+
+static acpi_status s3_wmi_attach_spi_device(acpi_handle handle,
+ u32 level,
+ void *data,
+ void **return_value)
+{
+ struct acpi_device *adev, **ts_adev;
+
+ if (acpi_bus_get_device(handle, &adev))
+ return AE_OK;
+
+ ts_adev = data;
+
+ if (strncmp(acpi_device_bid(adev), SPI_TS_OBJ_NAME,
+ strlen(SPI_TS_OBJ_NAME)))
+ return AE_OK;
+
+ if (*ts_adev) {
+ pr_err("duplicate entry %s\n", SPI_TS_OBJ_NAME);
+ return AE_OK;
+ }
+
+ *ts_adev = adev;
+
+ return AE_OK;
+}
+
+static int s3_wmi_check_platform_device(struct device *dev, void *data)
+{
+ struct acpi_device *adev, *ts_adev;
+ acpi_handle handle;
+ acpi_status status;
+
+ /* ignore non ACPI devices */
+ handle = ACPI_HANDLE(dev);
+ if (!handle || acpi_bus_get_device(handle, &adev))
+ return 0;
+
+ /* check for LID ACPI switch */
+ if (!strcmp(ACPI_BUTTON_HID_LID, acpi_device_hid(adev))) {
+ s3_wmi.pnp0c0d_adev = adev;
+ return 0;
+ }
+
+ /* ignore non SPI controllers */
+ if (strncmp(acpi_device_bid(adev), SPI_CTL_OBJ_NAME,
+ strlen(SPI_CTL_OBJ_NAME)))
+ return 0;
+
+ status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1,
+ s3_wmi_attach_spi_device, NULL,
+ &ts_adev, NULL);
+ if (ACPI_FAILURE(status))
+ dev_warn(dev, "failed to enumerate SPI slaves\n");
+
+ if (!ts_adev)
+ return 0;
+
+ s3_wmi.spi_master_pdev = to_platform_device(dev);
+ s3_wmi.spi_master_adev = adev;
+ s3_wmi.touchscreen_adev = ts_adev;
+
+ return 0;
+}
+
+static int s3_wmi_create_and_register_input(struct platform_device *pdev)
+{
+ struct input_dev *input;
+ int error;
+
+ input = devm_input_allocate_device(&pdev->dev);
+ if (!input)
+ return -ENOMEM;
+
+ input->name = "Lid Switch";
+ input->phys = "button/input0";
+ input->id.bustype = BUS_HOST;
+ input->id.product = 0x0005;
+
+ input_set_capability(input, EV_SW, SW_LID);
+
+ error = input_register_device(input);
+ if (error)
+ goto out_err;
+
+ s3_wmi.input = input;
+
+ return 0;
+ out_err:
+ input_free_device(s3_wmi.input);
+ return error;
+}
+
+static int __init s3_wmi_probe(struct platform_device *pdev)
+{
+ int error;
+
+ if (!dmi_check_system(surface3_dmi_table))
+ return -ENODEV;
+
+ memset(&s3_wmi, 0, sizeof(s3_wmi));
+
+ bus_for_each_dev(&platform_bus_type, NULL, NULL,
+ s3_wmi_check_platform_device);
+
+ if (!s3_wmi.touchscreen_adev)
+ return -ENODEV;
+
+ acpi_bus_trim(s3_wmi.pnp0c0d_adev);
+
+ error = s3_wmi_create_and_register_input(pdev);
+ if (error)
+ goto restore_acpi_lid;
+
+ acpi_initialize_hp_context(s3_wmi.touchscreen_adev, &s3_wmi.hp,
+ s3_wmi_hp_notify, NULL);
+
+ s3_wmi_send_lid_state(NULL);
+
+ return 0;
+
+ restore_acpi_lid:
+ acpi_bus_scan(s3_wmi.pnp0c0d_adev->handle);
+ return error;
+}
+
+static int s3_wmi_remove(struct platform_device *device)
+{
+ /* remove the hotplug context from the acpi device */
+ s3_wmi.touchscreen_adev->hp = NULL;
+
+ /* reinstall the actual PNPC0C0D LID default handle */
+ acpi_bus_scan(s3_wmi.pnp0c0d_adev->handle);
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int s3_wmi_resume(struct device *dev)
+{
+ s3_wmi_send_lid_state(NULL);
+ return 0;
+}
+#endif
+static SIMPLE_DEV_PM_OPS(s3_wmi_pm, NULL, s3_wmi_resume);
+
+static struct platform_driver s3_wmi_driver = {
+ .driver = {
+ .name = "surface3-wmi",
+ .pm = &s3_wmi_pm,
+ },
+ .remove = s3_wmi_remove,
+};
+
+static int __init s3_wmi_init(void)
+{
+ int error;
+
+ s3_wmi_pdev = platform_device_alloc("surface3-wmi", -1);
+ if (!s3_wmi_pdev)
+ return -ENOMEM;
+
+ error = platform_device_add(s3_wmi_pdev);
+ if (error)
+ goto err_device_put;
+
+ error = platform_driver_probe(&s3_wmi_driver, s3_wmi_probe);
+ if (error)
+ goto err_device_del;
+
+ pr_info("Surface 3 WMI Extras loaded\n");
+ return 0;
+
+ err_device_del:
+ platform_device_del(s3_wmi_pdev);
+ err_device_put:
+ platform_device_put(s3_wmi_pdev);
+ return error;
+}
+
+static void __exit s3_wmi_exit(void)
+{
+ platform_device_unregister(s3_wmi_pdev);
+ platform_driver_unregister(&s3_wmi_driver);
+}
+
+module_init(s3_wmi_init);
+module_exit(s3_wmi_exit);
--
2.7.4

View File

@ -0,0 +1,139 @@
From bf221e0568393a86b1b41b5ceb313c2580976947 Mon Sep 17 00:00:00 2001
From: Stephen Just <stephenjust@gmail.com>
Date: Tue, 28 Jun 2016 23:37:11 -0600
Subject: [PATCH] power: surface3_power: Improve battery capacity reporting
Read additional registers from the battery device to get more
accurate status reading. Also properly report battery (dis)charge
state and current.
---
drivers/power/surface3_power.c | 55 ++++++++++++++++++++++++++++++++++++------
1 file changed, 48 insertions(+), 7 deletions(-)
diff --git a/drivers/power/surface3_power.c b/drivers/power/surface3_power.c
index eee21d3..ac8155b 100644
--- a/drivers/power/surface3_power.c
+++ b/drivers/power/surface3_power.c
@@ -61,6 +61,7 @@ struct mshw0011_data {
bool charging;
bool bat_charging;
u8 trip_point;
+ s32 full_capacity;
};
struct mshw0011_lookup {
@@ -122,6 +123,10 @@ struct gsb_buffer {
} __packed;
} __packed;
+#define ACPI_BATTERY_STATE_DISCHARGING 0x1
+#define ACPI_BATTERY_STATE_CHARGING 0x2
+#define ACPI_BATTERY_STATE_CRITICAL 0x4
+
#define MSHW0011_CMD_DEST_BAT0 0x01
#define MSHW0011_CMD_DEST_ADP1 0x03
@@ -140,11 +145,14 @@ struct gsb_buffer {
#define MSHW0011_NOTIFY_GET_VERSION 0x00
#define MSHW0011_NOTIFY_ADP1 0x01
-#define MSHW0011_NOTIFY_BAT0 0x02
+#define MSHW0011_NOTIFY_BAT0_BST 0x02
+#define MSHW0011_NOTIFY_BAT0_BIX 0x05
#define MSHW0011_ADP1_REG_PSR 0x03
-#define MSHW0011_BAT0_REG_CAPACITY 0x0c
+#define MSHW0011_BAT0_REG_CAPACITY 0x0c
+#define MSHW0011_BAT0_REG_FULL_CHG_CAPACITY 0x0e
+#define MSHW0011_BAT0_REG_DESIGN_CAPACITY 0x40
#define MSHW0011_BAT0_REG_VOLTAGE 0x08
#define MSHW0011_BAT0_REG_RATE 0x14
#define MSHW0011_BAT0_REG_OEM 0x45
@@ -235,6 +243,22 @@ static int mshw0011_bix(struct mshw0011_data *cdata, struct bix *bix)
*bix = default_bix;
+ /* get design capacity */
+ ret = i2c_smbus_read_word_data(client, MSHW0011_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, MSHW0011_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 = mshw0011_i2c_read_block(client, MSHW0011_BAT0_REG_SERIAL_NO,
buf, 10);
@@ -269,7 +293,7 @@ static int mshw0011_bix(struct mshw0011_data *cdata, struct bix *bix)
static int mshw0011_bst(struct mshw0011_data *cdata, struct bst *bst)
{
struct i2c_client *client = cdata->bat0;
- int rate, capacity, voltage;
+ int rate, capacity, voltage, state;
s16 tmp;
rate = i2c_smbus_read_word_data(client, MSHW0011_BAT0_REG_RATE);
@@ -285,8 +309,15 @@ static int mshw0011_bst(struct mshw0011_data *cdata, struct bst *bst)
return voltage;
tmp = le16_to_cpu(rate);
- bst->battery_present_rate = (s32)tmp;
- bst->battery_state = bst->battery_present_rate < 0 ? 0x01 : 0x02;
+ 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);
@@ -308,6 +339,7 @@ static int mshw0011_adp_psr(struct mshw0011_data *cdata)
static int mshw0011_isr(struct mshw0011_data *cdata)
{
struct bst bst;
+ struct bix bix;
int ret;
bool status, bat_status;
@@ -327,14 +359,23 @@ static int mshw0011_isr(struct mshw0011_data *cdata)
if (ret < 0)
return ret;
- bat_status = bst.battery_present_rate >= 0;
+ bat_status = bst.battery_state;
if (bat_status != cdata->bat_charging)
mshw0011_notify(cdata, cdata->notify_version,
- MSHW0011_NOTIFY_BAT0, &ret);
+ MSHW0011_NOTIFY_BAT0_BST, &ret);
cdata->bat_charging = bat_status;
+ ret = mshw0011_bix(cdata, &bix);
+ if (ret < 0)
+ return ret;
+ if (bix.last_full_charg_capacity != cdata->full_capacity)
+ mshw0011_notify(cdata, cdata->notify_version,
+ MSHW0011_NOTIFY_BAT0_BIX, &ret);
+
+ cdata->full_capacity = bix.last_full_charg_capacity;
+
return 0;
}
--
2.7.4

View File

@ -0,0 +1,32 @@
From d4b0c0bfd2194496d7a72722829d4283ed5f3141 Mon Sep 17 00:00:00 2001
From: Benjamin Tissoires <benjamin.tissoires@redhat.com>
Date: Fri, 3 Jun 2016 11:49:17 +0200
Subject: [PATCH 3/3] HID: multitouch: set correct class for Surface Type Cover
3
Looks like Microsoft forgot to set the blob discriminating between Win 8
and Win 7 devices...
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
---
drivers/hid/hid-multitouch.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index dd279d7..fa6622a 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -1379,6 +1379,10 @@ static const struct hid_device_id mt_devices[] = {
MT_USB_DEVICE(USB_VENDOR_ID_ILITEK,
USB_DEVICE_ID_ILITEK_MULTITOUCH) },
+ /* Microsoft */
+ { .driver_data = MT_CLS_WIN_8,
+ MT_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, 0x07cd) },
+
/* MosArt panels */
{ .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE,
MT_USB_DEVICE(USB_VENDOR_ID_ASUS,
--
2.7.4

View File

@ -0,0 +1,47 @@
From 3a6162d1b35218b4fc684a0c95e103ce68105bb5 Mon Sep 17 00:00:00 2001
From: Benjamin Tissoires <benjamin.tissoires@redhat.com>
Date: Mon, 9 May 2016 14:28:25 +0200
Subject: [PATCH 3/6] Input - soc_button_array: make sure one GPIO is not
assigned twice
The Surface 3 declares twice the GPIO as GpioInt and GpioIo in its
ACPI table. Given that we do not keep the gpiod around, but the actual
number associated to, there is a chance while enumerating the GPIOs that
one gets assigned twice. Make sure a previous button has not been mapped
already to the current button to prevent such failure.
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
---
drivers/input/misc/soc_button_array.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/drivers/input/misc/soc_button_array.c b/drivers/input/misc/soc_button_array.c
index 5467d04..cb5cce3 100644
--- a/drivers/input/misc/soc_button_array.c
+++ b/drivers/input/misc/soc_button_array.c
@@ -77,7 +77,7 @@ soc_button_device_create(struct platform_device *pdev,
struct gpio_keys_platform_data *gpio_keys_pdata;
int n_buttons = 0;
int gpio;
- int error;
+ int i, error;
gpio_keys_pdata = devm_kzalloc(&pdev->dev,
sizeof(*gpio_keys_pdata) +
@@ -96,6 +96,13 @@ soc_button_device_create(struct platform_device *pdev,
if (!gpio_is_valid(gpio))
continue;
+ for (i = 0; i < n_buttons; i++) {
+ if (gpio_keys[i].gpio == gpio)
+ break;
+ }
+ if (i < n_buttons)
+ continue; /* the GPIO has already been assigned */
+
gpio_keys[n_buttons].type = info->event_type;
gpio_keys[n_buttons].code = info->event_code;
gpio_keys[n_buttons].gpio = gpio;
--
2.7.4

View File

@ -0,0 +1,54 @@
From de9a764d3063d5c1743eab8b1a994b02119767a0 Mon Sep 17 00:00:00 2001
From: Benjamin Tissoires <benjamin.tissoires@redhat.com>
Date: Fri, 13 May 2016 15:54:15 +0200
Subject: [PATCH 4/6] Input - soc_button_array: allow to specify active_low
The Surface 3 has the "Windows" key active high, and not low. We need
a way to specify it in the description.
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
---
drivers/input/misc/soc_button_array.c | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/drivers/input/misc/soc_button_array.c b/drivers/input/misc/soc_button_array.c
index cb5cce3..077e06e4 100644
--- a/drivers/input/misc/soc_button_array.c
+++ b/drivers/input/misc/soc_button_array.c
@@ -34,6 +34,7 @@ struct soc_button_info {
unsigned int event_code;
bool autorepeat;
bool wakeup;
+ bool active_low;
};
/*
@@ -106,7 +107,7 @@ soc_button_device_create(struct platform_device *pdev,
gpio_keys[n_buttons].type = info->event_type;
gpio_keys[n_buttons].code = info->event_code;
gpio_keys[n_buttons].gpio = gpio;
- gpio_keys[n_buttons].active_low = 1;
+ gpio_keys[n_buttons].active_low = info->active_low;
gpio_keys[n_buttons].desc = info->name;
gpio_keys[n_buttons].wakeup = info->wakeup;
n_buttons++;
@@ -206,11 +207,11 @@ static int soc_button_probe(struct platform_device *pdev)
}
static struct soc_button_info soc_button_PNP0C40[] = {
- { "power", 0, EV_KEY, KEY_POWER, false, true },
- { "home", 1, EV_KEY, KEY_LEFTMETA, false, true },
- { "volume_up", 2, EV_KEY, KEY_VOLUMEUP, true, false },
- { "volume_down", 3, EV_KEY, KEY_VOLUMEDOWN, true, false },
- { "rotation_lock", 4, EV_SW, SW_ROTATE_LOCK, false, false },
+ { "power", 0, EV_KEY, KEY_POWER, false, true, true },
+ { "home", 1, EV_KEY, KEY_LEFTMETA, false, true, true },
+ { "volume_up", 2, EV_KEY, KEY_VOLUMEUP, true, false, true },
+ { "volume_down", 3, EV_KEY, KEY_VOLUMEDOWN, true, false, true },
+ { "rotation_lock", 4, EV_SW, SW_ROTATE_LOCK, false, false, true },
{ }
};
--
2.7.4

View File

@ -0,0 +1,255 @@
From 7423522630722f7aad88afb097776e41b52d1b22 Mon Sep 17 00:00:00 2001
From: Benjamin Tissoires <benjamin.tissoires@redhat.com>
Date: Fri, 13 May 2016 15:56:56 +0200
Subject: [PATCH 5/6] Input - soc_button_array: export part of the internals
The MS Surfaces are not directly using the PNP0C40 device for the buttons
but instead a MSHW0028. This one is bound on a I2C bus and so we need to
use a separate driver for it.
One noticeable change is that the original soc_button_array fails
to rmmod and then modprobe when using KBUILD_MODNAME as the gpiod con_id
with the Surface 3. Add this as a parameter of the new API.
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
---
drivers/input/misc/soc_button_array.c | 108 +++++++++++++++++++--------------
include/linux/input/soc_button_array.h | 37 +++++++++++
2 files changed, 98 insertions(+), 47 deletions(-)
create mode 100644 include/linux/input/soc_button_array.h
diff --git a/drivers/input/misc/soc_button_array.c b/drivers/input/misc/soc_button_array.c
index 077e06e4..96012f9 100644
--- a/drivers/input/misc/soc_button_array.c
+++ b/drivers/input/misc/soc_button_array.c
@@ -19,23 +19,7 @@
#include <linux/gpio_keys.h>
#include <linux/gpio.h>
#include <linux/platform_device.h>
-
-/*
- * Definition of buttons on the tablet. The ACPI index of each button
- * is defined in section 2.8.7.2 of "Windows ACPI Design Guide for SoC
- * Platforms"
- */
-#define MAX_NBUTTONS 5
-
-struct soc_button_info {
- const char *name;
- int acpi_index;
- unsigned int event_type;
- unsigned int event_code;
- bool autorepeat;
- bool wakeup;
- bool active_low;
-};
+#include <linux/input/soc_button_array.h>
/*
* Some of the buttons like volume up/down are auto repeat, while others
@@ -51,12 +35,13 @@ struct soc_button_data {
/*
* Get the Nth GPIO number from the ACPI object.
*/
-static int soc_button_lookup_gpio(struct device *dev, int acpi_index)
+static int soc_button_lookup_gpio(struct device *dev, const char *con_id,
+ int acpi_index)
{
struct gpio_desc *desc;
int gpio;
- desc = gpiod_get_index(dev, KBUILD_MODNAME, acpi_index, GPIOD_ASIS);
+ desc = gpiod_get_index(dev, con_id, acpi_index, GPIOD_ASIS);
if (IS_ERR(desc))
return PTR_ERR(desc);
@@ -68,7 +53,8 @@ static int soc_button_lookup_gpio(struct device *dev, int acpi_index)
}
static struct platform_device *
-soc_button_device_create(struct platform_device *pdev,
+soc_button_device_create(struct device *dev,
+ const char *gpiod_con_id,
const struct soc_button_info *button_info,
bool autorepeat)
{
@@ -80,7 +66,7 @@ soc_button_device_create(struct platform_device *pdev,
int gpio;
int i, error;
- gpio_keys_pdata = devm_kzalloc(&pdev->dev,
+ gpio_keys_pdata = devm_kzalloc(dev,
sizeof(*gpio_keys_pdata) +
sizeof(*gpio_keys) * MAX_NBUTTONS,
GFP_KERNEL);
@@ -93,7 +79,9 @@ soc_button_device_create(struct platform_device *pdev,
if (info->autorepeat != autorepeat)
continue;
- gpio = soc_button_lookup_gpio(&pdev->dev, info->acpi_index);
+ gpio = soc_button_lookup_gpio(dev,
+ gpiod_con_id,
+ info->acpi_index);
if (!gpio_is_valid(gpio))
continue;
@@ -142,14 +130,12 @@ soc_button_device_create(struct platform_device *pdev,
err_free_pdev:
platform_device_put(pd);
err_free_mem:
- devm_kfree(&pdev->dev, gpio_keys_pdata);
+ devm_kfree(dev, gpio_keys_pdata);
return ERR_PTR(error);
}
-static int soc_button_remove(struct platform_device *pdev)
+int soc_dev_button_remove(struct soc_button_data *priv)
{
- struct soc_button_data *priv = platform_get_drvdata(pdev);
-
int i;
for (i = 0; i < BUTTON_TYPES; i++)
@@ -158,40 +144,28 @@ static int soc_button_remove(struct platform_device *pdev)
return 0;
}
+EXPORT_SYMBOL_GPL(soc_dev_button_remove);
-static int soc_button_probe(struct platform_device *pdev)
+int soc_dev_button_enumerate(struct device *dev, struct soc_button_data *priv,
+ const char *gpiod_con_id,
+ struct soc_button_info *button_info)
{
- struct device *dev = &pdev->dev;
- const struct acpi_device_id *id;
- struct soc_button_info *button_info;
- struct soc_button_data *priv;
struct platform_device *pd;
int i;
int error;
- id = acpi_match_device(dev->driver->acpi_match_table, dev);
- if (!id)
- return -ENODEV;
-
- button_info = (struct soc_button_info *)id->driver_data;
-
- if (gpiod_count(&pdev->dev, KBUILD_MODNAME) <= 0) {
- dev_info(&pdev->dev, "no GPIO attached, ignoring...\n");
+ if (gpiod_count(dev, gpiod_con_id) <= 0) {
+ dev_info(dev, "no GPIO attached, ignoring...\n");
return -ENODEV;
}
- priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
- if (!priv)
- return -ENOMEM;
-
- platform_set_drvdata(pdev, priv);
-
for (i = 0; i < BUTTON_TYPES; i++) {
- pd = soc_button_device_create(pdev, button_info, i == 0);
+ pd = soc_button_device_create(dev, gpiod_con_id, button_info,
+ i == 0);
if (IS_ERR(pd)) {
error = PTR_ERR(pd);
if (error != -ENODEV) {
- soc_button_remove(pdev);
+ soc_dev_button_remove(priv);
return error;
}
continue;
@@ -205,6 +179,46 @@ static int soc_button_probe(struct platform_device *pdev)
return 0;
}
+EXPORT_SYMBOL_GPL(soc_dev_button_enumerate);
+
+struct soc_button_data *soc_dev_button_data_allocate(struct device *dev)
+{
+ return devm_kzalloc(dev, sizeof(struct soc_button_data), GFP_KERNEL);
+}
+EXPORT_SYMBOL_GPL(soc_dev_button_data_allocate);
+
+static int soc_button_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ const struct acpi_device_id *id;
+ struct soc_button_info *button_info;
+ struct soc_button_data *priv;
+ int error;
+
+ id = acpi_match_device(dev->driver->acpi_match_table, dev);
+ if (!id)
+ return -ENODEV;
+
+ button_info = (struct soc_button_info *)id->driver_data;
+
+ priv = soc_dev_button_data_allocate(dev);
+ if (!priv)
+ return -ENOMEM;
+
+ error = soc_dev_button_enumerate(dev, priv, KBUILD_MODNAME,
+ button_info);
+ if (error)
+ return error;
+
+ platform_set_drvdata(pdev, priv);
+
+ return 0;
+}
+
+static int soc_button_remove(struct platform_device *pdev)
+{
+ return soc_dev_button_remove(platform_get_drvdata(pdev));
+}
static struct soc_button_info soc_button_PNP0C40[] = {
{ "power", 0, EV_KEY, KEY_POWER, false, true, true },
diff --git a/include/linux/input/soc_button_array.h b/include/linux/input/soc_button_array.h
new file mode 100644
index 0000000..634ce90
--- /dev/null
+++ b/include/linux/input/soc_button_array.h
@@ -0,0 +1,37 @@
+/*
+ * Supports for the button array on SoC tablets originally running
+ * Windows 8.
+ *
+ * (C) Copyright 2014 Intel Corporation
+ * (C) Copyright 2016 Red Hat, Inc
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2
+ * of the License.
+ */
+
+/*
+ * Definition of buttons on the tablet. The ACPI index of each button
+ * is defined in section 2.8.7.2 of "Windows ACPI Design Guide for SoC
+ * Platforms"
+ */
+#define MAX_NBUTTONS 5
+
+struct soc_button_info {
+ const char *name;
+ int acpi_index;
+ unsigned int event_type;
+ unsigned int event_code;
+ bool autorepeat;
+ bool wakeup;
+ bool active_low;
+};
+
+struct soc_button_data;
+
+struct soc_button_data *soc_dev_button_data_allocate(struct device *dev);
+int soc_dev_button_remove(struct soc_button_data *priv);
+int soc_dev_button_enumerate(struct device *dev, struct soc_button_data *priv,
+ const char *gpiod_con_id,
+ struct soc_button_info *button_info);
--
2.7.4

View File

@ -0,0 +1,181 @@
From d25373cf47d005fbab3b363a32fa9d890ead1a51 Mon Sep 17 00:00:00 2001
From: Benjamin Tissoires <benjamin.tissoires@redhat.com>
Date: Fri, 13 May 2016 17:54:09 +0200
Subject: [PATCH 6/6] Input - surface3_button_array: Introduce button support
for the Surface 3
The Surface 3 is not following the ACPI spec for PNP0C40, but nearly.
The device is connected to a I2C device that might have some magic
but we don't know about.
Just create the device after the enumeration and use the declared GPIOs
to provide button support.
The Surface Pro 3 is using an ACPI driver and matches against the bid
of the device ("VGBI") but I think it also could use this. To prevent
this driver to be used on the Surface Pro, we add a match on the
Surface 3 bid "TEV2".
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
---
drivers/input/misc/Kconfig | 9 +++
drivers/input/misc/Makefile | 1 +
drivers/input/misc/surface3_button_array.c | 115 +++++++++++++++++++++++++++++
3 files changed, 125 insertions(+)
create mode 100644 drivers/input/misc/surface3_button_array.c
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index efb0ca8..6f99d3b 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -776,6 +776,15 @@ config INPUT_SOC_BUTTON_ARRAY
To compile this driver as a module, choose M here: the
module will be called soc_button_array.
+config INPUT_SURFACE3_BUTTON_ARRAY
+ tristate "Microsoft Surface 3 SoC Button Array"
+ depends on INPUT_SOC_BUTTON_ARRAY
+ help
+ Say Y here if you have a MS Surface tablet.
+
+ To compile this driver as a module, choose M here: the
+ module will be called surface3_button_array.
+
config INPUT_DRV260X_HAPTICS
tristate "TI DRV260X haptics support"
depends on INPUT && I2C
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index 6a1e5e2..020b24a 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -67,6 +67,7 @@ obj-$(CONFIG_INPUT_SGI_BTNS) += sgi_btns.o
obj-$(CONFIG_INPUT_SIRFSOC_ONKEY) += sirfsoc-onkey.o
obj-$(CONFIG_INPUT_SOC_BUTTON_ARRAY) += soc_button_array.o
obj-$(CONFIG_INPUT_SPARCSPKR) += sparcspkr.o
+obj-$(CONFIG_INPUT_SURFACE3_BUTTON_ARRAY) += surface3_button_array.o
obj-$(CONFIG_INPUT_TPS65218_PWRBUTTON) += tps65218-pwrbutton.o
obj-$(CONFIG_INPUT_TWL4030_PWRBUTTON) += twl4030-pwrbutton.o
obj-$(CONFIG_INPUT_TWL4030_VIBRA) += twl4030-vibra.o
diff --git a/drivers/input/misc/surface3_button_array.c b/drivers/input/misc/surface3_button_array.c
new file mode 100644
index 0000000..b48307c
--- /dev/null
+++ b/drivers/input/misc/surface3_button_array.c
@@ -0,0 +1,115 @@
+/*
+ * Supports for the button array on the Surface tablets.
+ *
+ * (C) Copyright 2016 Red Hat, Inc
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2
+ * of the License.
+ */
+
+#include <linux/kernel.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/acpi.h>
+#include <linux/input/soc_button_array.h>
+#include <uapi/linux/input-event-codes.h>
+
+struct soc_device_info {
+ const char * const *obj_names;
+ struct soc_button_info *buttons;
+};
+
+static int surface3_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ const char *bid, *obj_name;
+ struct soc_device_info *device_info;
+ struct soc_button_data *priv;
+ int error;
+ int i;
+
+ if (!id->driver_data)
+ return -EINVAL;
+
+ device_info = (struct soc_device_info *)id->driver_data;
+
+ if (device_info->obj_names) {
+ bid = acpi_device_bid(ACPI_COMPANION(&client->dev));
+ i = 0;
+ do {
+ obj_name = device_info->obj_names[i++];
+ if (obj_name && !strcmp(bid, obj_name))
+ break;
+ } while (obj_name);
+ /* no acpi_device_bid match, bail out */
+ if (!obj_name)
+ return -ENODEV;
+ }
+
+ priv = soc_dev_button_data_allocate(&client->dev);
+ if (!priv)
+ return -ENOMEM;
+
+ error = soc_dev_button_enumerate(&client->dev, priv, NULL,
+ device_info->buttons);
+ if (error)
+ return error;
+
+ i2c_set_clientdata(client, priv);
+
+ return 0;
+}
+
+static int surface3_remove(struct i2c_client *client)
+{
+ return soc_dev_button_remove(i2c_get_clientdata(client));
+}
+
+static struct soc_button_info soc_button_surface3[] = {
+ { "power", 0, EV_KEY, KEY_POWER, false, true, true },
+ { "home", 1, EV_KEY, KEY_LEFTMETA, false, true, false },
+ { "volume_up", 2, EV_KEY, KEY_VOLUMEUP, true, false, true },
+ { "volume_down", 3, EV_KEY, KEY_VOLUMEDOWN, true, false, true },
+ { }
+};
+
+static const char * const soc_device_obj_names_surface3[] = {
+ "TEV2",
+ 0,
+};
+
+static const struct soc_device_info soc_device_surface3 = {
+ .obj_names = soc_device_obj_names_surface3,
+ .buttons = soc_button_surface3,
+};
+
+static const struct i2c_device_id surface3_id[] = {
+ { "MSHW0028:00", (unsigned long)&soc_device_surface3 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, surface3_id);
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id surface3_acpi_match[] = {
+ { "MSHW0028", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(acpi, surface3_acpi_match);
+#endif
+
+static struct i2c_driver surface3_driver = {
+ .probe = surface3_probe,
+ .remove = surface3_remove,
+ .id_table = surface3_id,
+ .driver = {
+ .name = "surface3",
+ .acpi_match_table = ACPI_PTR(surface3_acpi_match),
+ },
+};
+module_i2c_driver(surface3_driver);
+
+MODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@gmail.com>");
+MODULE_DESCRIPTION("surface3 button array driver");
+MODULE_LICENSE("GPL v2");
--
2.7.4

View File

@ -0,0 +1,33 @@
From 5d554ea4f287665b839975ecb11bd29d49a5c9b5 Mon Sep 17 00:00:00 2001
From: Vinod Koul <vinod.koul@intel.com>
Date: Fri, 8 Jul 2016 18:30:17 +0530
Subject: ASoC: Intel: cht: fix uninit variable warning
Kbuild bot reports that we might use dai_index uninitialized.
sound/soc/intel/boards/cht_bsw_rt5645.c:391:37: warning: 'dai_index' may be used uninitialized in this function [-Wmaybe-uninitialized]
Since it is theoretically possible, set it while initializing.
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
---
sound/soc/intel/boards/cht_bsw_rt5645.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c
index f26c7b8..56056ed 100644
--- a/sound/soc/intel/boards/cht_bsw_rt5645.c
+++ b/sound/soc/intel/boards/cht_bsw_rt5645.c
@@ -357,7 +357,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
char codec_name[16];
struct sst_acpi_mach *mach;
const char *i2c_name = NULL;
- int dai_index;
+ int dai_index = 0;
drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_ATOMIC);
if (!drv)
--
cgit v0.12

View File

@ -0,0 +1,48 @@
From patchwork Fri Jul 15 13:37:04 2016
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Subject: [1/2] mwifiex: fix PCIe legacy interrupt problem
From: Amitkumar Karwar <akarwar@marvell.com>
X-Patchwork-Id: 9232091
Message-Id: <1468589825-9188-1-git-send-email-akarwar@marvell.com>
To: <linux-wireless@vger.kernel.org>
Cc: Cathy Luo <cluo@marvell.com>, Nishant Sarmukadam <nishants@marvell.com>,
Amitkumar Karwar <akarwar@marvell.com>
Date: Fri, 15 Jul 2016 19:07:04 +0530
In corner case, we may end up processing same interrupt twice.
We have a logic to read pending interrupts at the end of interrupt
processing routine. It has a race with interrupts read in interrupt
handler. This patch solves the problem by ORing the interrupt bitmap
in this case.
The symptom for this bug is below messages in dmesg log.
[ 11.522123] mwifiex_pcie 0000:01:00.0: CMD_RESP: invalid cmd resp
[ 11.680412] mwifiex_pcie 0000:01:00.0: There is no command but got cmdrsp
Link: https://bugzilla.kernel.org/show_bug.cgi?id=109681
Signed-off-by: Amitkumar Karwar <akarwar@marvell.com>
Signed-off-by: Cathy Luo <cluo@marvell.com>
---
drivers/net/wireless/marvell/mwifiex/pcie.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c
index d61d4ad..38bd62e 100644
--- a/drivers/net/wireless/marvell/mwifiex/pcie.c
+++ b/drivers/net/wireless/marvell/mwifiex/pcie.c
@@ -2300,6 +2300,12 @@ static int mwifiex_process_pcie_int(struct mwifiex_adapter *adapter)
}
}
+ if (!card->msi_enable) {
+ spin_lock_irqsave(&adapter->int_lock, flags);
+ pcie_ireg |= adapter->int_status;
+ adapter->int_status = 0;
+ spin_unlock_irqrestore(&adapter->int_lock, flags);
+ }
}
mwifiex_dbg(adapter, INTR,
"info: cmd_sent=%d data_sent=%d\n",

View File

@ -0,0 +1,34 @@
From patchwork Fri Jul 15 13:37:05 2016
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Subject: [2/2] mwifiex: update command response skb length correctly
From: Amitkumar Karwar <akarwar@marvell.com>
X-Patchwork-Id: 9232093
Message-Id: <1468589825-9188-2-git-send-email-akarwar@marvell.com>
To: <linux-wireless@vger.kernel.org>
Cc: Cathy Luo <cluo@marvell.com>, Nishant Sarmukadam <nishants@marvell.com>,
Amitkumar Karwar <akarwar@marvell.com>
Date: Fri, 15 Jul 2016 19:07:05 +0530
Same skb is being reused for storing command response from firmware
in PCIe chipsets. There was a bug while updating the skb length.
This patch ensures skb length correctly gets updated based on rx_len.
Signed-off-by: Amitkumar Karwar <akarwar@marvell.com>
---
drivers/net/wireless/marvell/mwifiex/pcie.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c
index 38bd62e..a6af85d 100644
--- a/drivers/net/wireless/marvell/mwifiex/pcie.c
+++ b/drivers/net/wireless/marvell/mwifiex/pcie.c
@@ -1616,6 +1616,7 @@ static int mwifiex_pcie_process_cmd_complete(struct mwifiex_adapter *adapter)
pkt_len = *((__le16 *)skb->data);
rx_len = le16_to_cpu(pkt_len);
+ skb_put(skb, MWIFIEX_UPLD_SIZE - skb->len);
skb_trim(skb, rx_len);
skb_pull(skb, INTF_HEADER_LEN);

View File

@ -0,0 +1,46 @@
From d41376ca8ba74e954ba931c69271d0b29546a202 Mon Sep 17 00:00:00 2001
From: Brian Norris <briannorris@chromium.org>
Date: Thu, 30 Jun 2016 15:21:02 -0700
Subject: mwifiex: mask PCIe interrupts before removal
The PCIe driver didn't mask the host interrupts before trying to tear
down. This causes lockups at reboot or rmmod when using MSI-X on 8997,
since the MSI handler gets confused and locks up the system.
Also tested on 8897, which does not support MSI-X (and wasn't
experiencing this same bug). No regressions seen there.
Signed-off-by: Brian Norris <briannorris@chromium.org>
Tested-by: Douglas Anderson <dianders@chromium.org>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
---
drivers/net/wireless/marvell/mwifiex/pcie.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c
index 012733c..c7f5df8 100644
--- a/drivers/net/wireless/marvell/mwifiex/pcie.c
+++ b/drivers/net/wireless/marvell/mwifiex/pcie.c
@@ -440,6 +440,11 @@ static int mwifiex_pcie_disable_host_int(struct mwifiex_adapter *adapter)
return 0;
}
+static void mwifiex_pcie_disable_host_int_noerr(struct mwifiex_adapter *adapter)
+{
+ WARN_ON(mwifiex_pcie_disable_host_int(adapter));
+}
+
/*
* This function enables the host interrupt.
*
@@ -2946,6 +2951,7 @@ static struct mwifiex_if_ops pcie_ops = {
.register_dev = mwifiex_register_dev,
.unregister_dev = mwifiex_unregister_dev,
.enable_int = mwifiex_pcie_enable_host_int,
+ .disable_int = mwifiex_pcie_disable_host_int_noerr,
.process_int_status = mwifiex_process_int_status,
.host_to_card = mwifiex_pcie_host_to_card,
.wakeup = mwifiex_pm_wakeup_card,
--
cgit v0.12

View File

@ -0,0 +1,32 @@
From 24dad509ed5528bbbe31ff17f9fb39c0473ec8f4 Mon Sep 17 00:00:00 2001
From: Vinod Koul <vinod.koul@intel.com>
Date: Fri, 8 Jul 2016 18:30:18 +0530
Subject: ASoC: Intel: atom: statify cht_quirk
Sparse rightly warns:
sound/soc/intel/atom/sst/sst_acpi.c:353:22: warning: symbol 'cht_quirk' was not declared. Should it be static?
So statify this
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
---
sound/soc/intel/atom/sst/sst_acpi.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c
index 82a374d..4d31849 100644
--- a/sound/soc/intel/atom/sst/sst_acpi.c
+++ b/sound/soc/intel/atom/sst/sst_acpi.c
@@ -350,7 +350,7 @@ static struct sst_acpi_mach cht_surface_mach = {
"10EC5640", "cht-bsw-rt5645", "intel/fw_sst_22a8.bin", "cht-bsw", NULL,
&chv_platform_data };
-struct sst_acpi_mach *cht_quirk(void *arg)
+static struct sst_acpi_mach *cht_quirk(void *arg)
{
struct sst_acpi_mach *mach = arg;
--
cgit v0.12

View File

@ -0,0 +1,33 @@
From 141bcf099076df1a74317a5b14dcd56c933b9de8 Mon Sep 17 00:00:00 2001
From: Heinrich Schuchardt <xypron.glpk@gmx.de>
Date: Wed, 18 May 2016 01:16:01 +0200
Subject: mwiflex: avoid possible null pointer dereference
Do not dereference card before checking against NULL value.
Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
---
drivers/net/wireless/marvell/mwifiex/pcie.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c
index 9246ce8..a35db02 100644
--- a/drivers/net/wireless/marvell/mwifiex/pcie.c
+++ b/drivers/net/wireless/marvell/mwifiex/pcie.c
@@ -2901,10 +2901,11 @@ static void mwifiex_unregister_dev(struct mwifiex_adapter *adapter)
{
struct pcie_service_card *card = adapter->card;
const struct mwifiex_pcie_card_reg *reg;
- struct pci_dev *pdev = card->dev;
+ struct pci_dev *pdev;
int i;
if (card) {
+ pdev = card->dev;
if (card->msix_enable) {
for (i = 0; i < MWIFIEX_NUM_MSIX_VECTORS; i++)
synchronize_irq(card->msix_entries[i].vector);
--
cgit v0.12

View File

@ -0,0 +1,356 @@
From vinod.koul@intel.com Fri Jul 8 12:03:22 2016
Return-Path: <vinod.koul@intel.com>
Delivered-To: hadess@hadess.net
Received: from spool.mail.gandi.net (mspool1-d.mgt.gandi.net [10.0.21.131])
by nmboxes111.sd2.0x35.net (Postfix) with ESMTP id 79E3B21C96
for <hadess@hadess.net>; Fri, 8 Jul 2016 12:03:22 +0200 (CEST)
Received: from mfilter40-d.gandi.net (mfilter40-d.gandi.net
[217.70.178.171]) by spool.mail.gandi.net (Postfix) with ESMTP id
700992260FC for <hadess@hadess.net>; Fri, 8 Jul 2016 12:03:22 +0200 (CEST)
X-Virus-Scanned: Debian amavisd-new at mfilter40-d.gandi.net
Received: from spool.mail.gandi.net ([IPv6:::ffff:10.0.21.131]) by
mfilter40-d.gandi.net (mfilter40-d.gandi.net [::ffff:10.0.15.180])
(amavisd-new, port 10024) with ESMTP id qK5K-waPj4Ol for
<hadess@hadess.net>; Fri, 8 Jul 2016 12:03:20 +0200 (CEST)
Received: from mga14.intel.com (mga14.intel.com [192.55.52.115])
by spool.mail.gandi.net (Postfix) with ESMTP id D6DE42260D7
for <bugzilla@hadess.net>; Fri, 8 Jul 2016 12:03:09 +0200 (CEST)
Received: from fmsmga003.fm.intel.com ([10.253.24.29])
by fmsmga103.fm.intel.com with ESMTP; 08 Jul 2016 03:02:59 -0700
X-ExtLoop1: 1
X-IronPort-AV: E=Sophos;i="5.28,329,1464678000";
d="scan'208";a="731352416"
Received: from vkoul-udesk7.iind.intel.com ([10.223.84.143])
by FMSMGA003.fm.intel.com with ESMTP; 08 Jul 2016 03:02:55 -0700
From: Vinod Koul <vinod.koul@intel.com>
To: alsa-devel@alsa-project.org
Cc: broonie@kernel.org,
liam.r.girdwood@linux.intel.com,
patches.audio@intel.com,
Stephen Just <stephenjust@gmail.com>,
Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>,
apterix@gmail.com,
bugzilla@hadess.net,
Vinod Koul <vinod.koul@intel.com>,
Sachin Mokashi <sachinx.mokashi@intel.com>
Subject: [PATCH 1/3] ASoC: Intel: Atom: Add quirk for Surface 3
Date: Fri, 8 Jul 2016 15:39:49 +0530
Message-Id: <1467972591-29175-2-git-send-email-vinod.koul@intel.com>
X-Mailer: git-send-email 1.9.1
In-Reply-To: <1467972591-29175-1-git-send-email-vinod.koul@intel.com>
References: <1467972591-29175-1-git-send-email-vinod.koul@intel.com>
X-Evolution-Source: 1353784233.13280.3@sirocco.hadess.net
Content-Transfer-Encoding: 8bit
Mime-Version: 1.0
Surface 3 is CHT based device which shows up with RT5645 codec. But the
BIOS reports ACPI ID as 5640!
To solve this, add a DMI overide for cht-5640 machine.
Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=98001
Signed-off-by: Sachin Mokashi <sachinx.mokashi@intel.com>
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
---
sound/soc/intel/atom/sst/sst_acpi.c | 44 ++++++++++++++++++++++++++++++++++++-
sound/soc/intel/common/sst-acpi.h | 2 +-
2 files changed, 44 insertions(+), 2 deletions(-)
diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c
index 3bc4b63b2f9d..82a374d885a7 100644
--- a/sound/soc/intel/atom/sst/sst_acpi.c
+++ b/sound/soc/intel/atom/sst/sst_acpi.c
@@ -28,6 +28,7 @@
#include <linux/firmware.h>
#include <linux/pm_runtime.h>
#include <linux/pm_qos.h>
+#include <linux/dmi.h>
#include <linux/acpi.h>
#include <asm/platform_sst_audio.h>
#include <sound/core.h>
@@ -237,6 +238,9 @@ static int sst_acpi_probe(struct platform_device *pdev)
dev_err(dev, "No matching machine driver found\n");
return -ENODEV;
}
+ if (mach->machine_quirk)
+ mach = mach->machine_quirk(mach);
+
pdata = mach->pdata;
ret = kstrtouint(id->id, 16, &dev_id);
@@ -320,6 +324,44 @@ static int sst_acpi_remove(struct platform_device *pdev)
return 0;
}
+static unsigned long cht_machine_id;
+
+#define CHT_SURFACE_MACH 1
+
+static int cht_surface_quirk_cb(const struct dmi_system_id *id)
+{
+ cht_machine_id = CHT_SURFACE_MACH;
+ return 1;
+}
+
+
+static const struct dmi_system_id cht_table[] = {
+ {
+ .callback = cht_surface_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Surface 3"),
+ },
+ },
+};
+
+
+static struct sst_acpi_mach cht_surface_mach = {
+ "10EC5640", "cht-bsw-rt5645", "intel/fw_sst_22a8.bin", "cht-bsw", NULL,
+ &chv_platform_data };
+
+struct sst_acpi_mach *cht_quirk(void *arg)
+{
+ struct sst_acpi_mach *mach = arg;
+
+ dmi_check_system(cht_table);
+
+ if (cht_machine_id == CHT_SURFACE_MACH)
+ return &cht_surface_mach;
+ else
+ return mach;
+}
+
static struct sst_acpi_mach sst_acpi_bytcr[] = {
{"10EC5640", "bytcr_rt5640", "intel/fw_sst_0f28.bin", "bytcr_rt5640", NULL,
&byt_rvp_platform_data },
@@ -343,7 +385,7 @@ static struct sst_acpi_mach sst_acpi_chv[] = {
{"193C9890", "cht-bsw-max98090", "intel/fw_sst_22a8.bin", "cht-bsw", NULL,
&chv_platform_data },
/* some CHT-T platforms rely on RT5640, use Baytrail machine driver */
- {"10EC5640", "bytcr_rt5640", "intel/fw_sst_22a8.bin", "bytcr_rt5640", NULL,
+ {"10EC5640", "bytcr_rt5640", "intel/fw_sst_22a8.bin", "bytcr_rt5640", cht_quirk,
&chv_platform_data },
{},
diff --git a/sound/soc/intel/common/sst-acpi.h b/sound/soc/intel/common/sst-acpi.h
index 8398cb227ba9..504b0e4fedd4 100644
--- a/sound/soc/intel/common/sst-acpi.h
+++ b/sound/soc/intel/common/sst-acpi.h
@@ -40,6 +40,6 @@ struct sst_acpi_mach {
/* board name */
const char *board;
- void (*machine_quirk)(void);
+ struct sst_acpi_mach * (*machine_quirk)(void *arg);
void *pdata;
};
--
1.9.1
From vinod.koul@intel.com Fri Jul 8 12:03:22 2016
Return-Path: <vinod.koul@intel.com>
Delivered-To: hadess@hadess.net
Received: from spool.mail.gandi.net (mspool1-d.mgt.gandi.net [10.0.21.131])
by nmboxes111.sd2.0x35.net (Postfix) with ESMTP id 94C7121C96
for <hadess@hadess.net>; Fri, 8 Jul 2016 12:03:22 +0200 (CEST)
Received: from mfilter49-d.gandi.net (mfilter49-d.gandi.net
[217.70.178.180]) by spool.mail.gandi.net (Postfix) with ESMTP id
9155C226069 for <hadess@hadess.net>; Fri, 8 Jul 2016 12:03:22 +0200 (CEST)
X-Virus-Scanned: Debian amavisd-new at mfilter49-d.gandi.net
Received: from spool.mail.gandi.net ([IPv6:::ffff:10.0.21.131]) by
mfilter49-d.gandi.net (mfilter49-d.gandi.net [::ffff:10.0.15.180])
(amavisd-new, port 10024) with ESMTP id DHVDC0Ilq6FQ for
<hadess@hadess.net>; Fri, 8 Jul 2016 12:03:20 +0200 (CEST)
Received: from mga14.intel.com (mga14.intel.com [192.55.52.115])
by spool.mail.gandi.net (Postfix) with ESMTP id 709442260E5
for <bugzilla@hadess.net>; Fri, 8 Jul 2016 12:03:10 +0200 (CEST)
Received: from fmsmga003.fm.intel.com ([10.253.24.29])
by fmsmga103.fm.intel.com with ESMTP; 08 Jul 2016 03:03:02 -0700
X-ExtLoop1: 1
X-IronPort-AV: E=Sophos;i="5.28,329,1464678000";
d="scan'208";a="731352436"
Received: from vkoul-udesk7.iind.intel.com ([10.223.84.143])
by FMSMGA003.fm.intel.com with ESMTP; 08 Jul 2016 03:02:58 -0700
From: Vinod Koul <vinod.koul@intel.com>
To: alsa-devel@alsa-project.org
Cc: broonie@kernel.org,
liam.r.girdwood@linux.intel.com,
patches.audio@intel.com,
Stephen Just <stephenjust@gmail.com>,
Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>,
apterix@gmail.com,
bugzilla@hadess.net,
Vinod Koul <vinod.koul@intel.com>,
Sachin Mokashi <sachinx.mokashi@intel.com>
Subject: [PATCH 2/3] ASoC: rt5645: Add ACPI ID 10EC5640
Date: Fri, 8 Jul 2016 15:39:50 +0530
Message-Id: <1467972591-29175-3-git-send-email-vinod.koul@intel.com>
X-Mailer: git-send-email 1.9.1
In-Reply-To: <1467972591-29175-1-git-send-email-vinod.koul@intel.com>
References: <1467972591-29175-1-git-send-email-vinod.koul@intel.com>
X-Evolution-Source: 1353784233.13280.3@sirocco.hadess.net
Content-Transfer-Encoding: 8bit
Mime-Version: 1.0
Some CHT platforms use RT5645 codec which has entry 10EC5640 so add it.
Also add DMI quirk for jack detection.
Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=98001
Signed-off-by: Sachin Mokashi <sachinx.mokashi@intel.com>
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
[Jack detection]
Suggested-by: Stephen Just <stephenjust@gmail.com>
---
sound/soc/codecs/rt5645.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c
index 3c6594da6c9c..761ca88c4cdd 100644
--- a/sound/soc/codecs/rt5645.c
+++ b/sound/soc/codecs/rt5645.c
@@ -3531,6 +3531,7 @@ MODULE_DEVICE_TABLE(i2c, rt5645_i2c_id);
static const struct acpi_device_id rt5645_acpi_match[] = {
{ "10EC5645", 0 },
{ "10EC5650", 0 },
+ { "10EC5640", 0 },
{},
};
MODULE_DEVICE_TABLE(acpi, rt5645_acpi_match);
@@ -3561,6 +3562,12 @@ static const struct dmi_system_id dmi_platform_intel_braswell[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "Setzer"),
},
},
+ {
+ .ident = "Microsoft Surface 3",
+ .matches = {
+ DMI_MATCH(DMI_PRODUCT_NAME, "Surface 3"),
+ },
+ },
{ }
};
--
1.9.1
From vinod.koul@intel.com Fri Jul 8 12:03:25 2016
Return-Path: <vinod.koul@intel.com>
Delivered-To: hadess@hadess.net
Received: from spool.mail.gandi.net (mspool7-d.mgt.gandi.net [10.0.21.138])
by nmboxes111.sd2.0x35.net (Postfix) with ESMTP id E535621C96
for <hadess@hadess.net>; Fri, 8 Jul 2016 12:03:25 +0200 (CEST)
Received: from mfilter17-d.gandi.net (mfilter17-d.gandi.net
[217.70.178.145]) by spool.mail.gandi.net (Postfix) with ESMTP id
E2A5419F3BC for <hadess@hadess.net>; Fri, 8 Jul 2016 12:03:25 +0200 (CEST)
X-Virus-Scanned: Debian amavisd-new at mfilter17-d.gandi.net
Received: from spool.mail.gandi.net ([IPv6:::ffff:10.0.21.138]) by
mfilter17-d.gandi.net (mfilter17-d.gandi.net [::ffff:10.0.15.180])
(amavisd-new, port 10024) with ESMTP id iqTV1YWaYo1Y for
<hadess@hadess.net>; Fri, 8 Jul 2016 12:03:24 +0200 (CEST)
Received: from mga14.intel.com (mga14.intel.com [192.55.52.115])
by spool.mail.gandi.net (Postfix) with ESMTP id E5E3A19F3E5
for <bugzilla@hadess.net>; Fri, 8 Jul 2016 12:03:10 +0200 (CEST)
Received: from fmsmga003.fm.intel.com ([10.253.24.29])
by fmsmga103.fm.intel.com with ESMTP; 08 Jul 2016 03:03:05 -0700
X-ExtLoop1: 1
X-IronPort-AV: E=Sophos;i="5.28,329,1464678000";
d="scan'208";a="731352499"
Received: from vkoul-udesk7.iind.intel.com ([10.223.84.143])
by FMSMGA003.fm.intel.com with ESMTP; 08 Jul 2016 03:03:02 -0700
From: Vinod Koul <vinod.koul@intel.com>
To: alsa-devel@alsa-project.org
Cc: broonie@kernel.org,
liam.r.girdwood@linux.intel.com,
patches.audio@intel.com,
Stephen Just <stephenjust@gmail.com>,
Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>,
apterix@gmail.com,
bugzilla@hadess.net,
Vinod Koul <vinod.koul@intel.com>,
Sachin Mokashi <sachinx.mokashi@intel.com>
Subject: [PATCH 3/3] ASoC: Intel: Add surface3 entry in CHT-RT5645 machine
Date: Fri, 8 Jul 2016 15:39:51 +0530
Message-Id: <1467972591-29175-4-git-send-email-vinod.koul@intel.com>
X-Mailer: git-send-email 1.9.1
In-Reply-To: <1467972591-29175-1-git-send-email-vinod.koul@intel.com>
References: <1467972591-29175-1-git-send-email-vinod.koul@intel.com>
X-Evolution-Source: 1353784233.13280.3@sirocco.hadess.net
Content-Transfer-Encoding: 8bit
Mime-Version: 1.0
Surface3 device is a CHT machine, so add entry for it.
Also update the HID from BIOS.
Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=98001
Signed-off-by: Sachin Mokashi <sachinx.mokashi@intel.com>
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
---
sound/soc/intel/boards/cht_bsw_rt5645.c | 20 +++++++++++++++++++-
1 file changed, 19 insertions(+), 1 deletion(-)
diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c
index d7ef292c402d..f26c7b8545ae 100644
--- a/sound/soc/intel/boards/cht_bsw_rt5645.c
+++ b/sound/soc/intel/boards/cht_bsw_rt5645.c
@@ -30,6 +30,7 @@
#include <sound/jack.h>
#include "../../codecs/rt5645.h"
#include "../atom/sst-atom-controls.h"
+#include "../common/sst-acpi.h"
#define CHT_PLAT_CLK_3_HZ 19200000
#define CHT_CODEC_DAI "rt5645-aif1"
@@ -340,10 +341,13 @@ static struct snd_soc_card snd_soc_card_chtrt5650 = {
};
static struct cht_acpi_card snd_soc_cards[] = {
+ {"10EC5640", CODEC_TYPE_RT5645, &snd_soc_card_chtrt5645},
{"10EC5645", CODEC_TYPE_RT5645, &snd_soc_card_chtrt5645},
{"10EC5650", CODEC_TYPE_RT5650, &snd_soc_card_chtrt5650},
};
+static char cht_rt5640_codec_name[16]; /* i2c-<HID>:00 with HID being 8 chars */
+
static int snd_cht_mc_probe(struct platform_device *pdev)
{
int ret_val = 0;
@@ -351,6 +355,9 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
struct cht_mc_private *drv;
struct snd_soc_card *card = snd_soc_cards[0].soc_card;
char codec_name[16];
+ struct sst_acpi_mach *mach;
+ const char *i2c_name = NULL;
+ int dai_index;
drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_ATOMIC);
if (!drv)
@@ -366,12 +373,23 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
}
}
card->dev = &pdev->dev;
+ mach = card->dev->platform_data;
sprintf(codec_name, "i2c-%s:00", drv->acpi_card->codec_id);
/* set correct codec name */
for (i = 0; i < ARRAY_SIZE(cht_dailink); i++)
- if (!strcmp(card->dai_link[i].codec_name, "i2c-10EC5645:00"))
+ if (!strcmp(card->dai_link[i].codec_name, "i2c-10EC5645:00")) {
card->dai_link[i].codec_name = kstrdup(codec_name, GFP_KERNEL);
+ dai_index = i;
+ }
+
+ /* fixup codec name based on HID */
+ i2c_name = sst_acpi_find_name_from_hid(mach->id);
+ if (i2c_name != NULL) {
+ snprintf(cht_rt5640_codec_name, sizeof(cht_rt5640_codec_name),
+ "%s%s", "i2c-", i2c_name);
+ cht_dailink[dai_index].codec_name = cht_rt5640_codec_name;
+ }
snd_soc_card_set_drvdata(card, drv);
ret_val = devm_snd_soc_register_card(&pdev->dev, card);
--
1.9.1

View File

@ -0,0 +1,72 @@
From 473dfbfa09934cea0d08cc9023c749a5fce10cb0 Mon Sep 17 00:00:00 2001
From: Amitkumar Karwar <akarwar@marvell.com>
Date: Thu, 30 Jun 2016 22:24:57 +0530
Subject: mwifiex: Change default firmware for PCIe8997 chipset
PCIe-USB8997 variant is being used in the product. Let's change default
firmware from PCIe-UART to PCIe-USB. So by default PCIe-USB firmware would
be downloaded if version register doesn't give any information.
Signed-off-by: Amitkumar Karwar <akarwar@marvell.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
---
drivers/net/wireless/marvell/mwifiex/pcie.c | 12 ++++++------
drivers/net/wireless/marvell/mwifiex/pcie.h | 4 ++--
2 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c
index 1b1e266..012733c 100644
--- a/drivers/net/wireless/marvell/mwifiex/pcie.c
+++ b/drivers/net/wireless/marvell/mwifiex/pcie.c
@@ -2841,20 +2841,20 @@ static void mwifiex_pcie_get_fw_name(struct mwifiex_adapter *adapter)
version &= 0x7;
switch (revision_id) {
case PCIE8997_V2:
- if (version == CHIP_VER_PCIEUSB)
+ if (version == CHIP_VER_PCIEUART)
strcpy(adapter->fw_name,
- PCIEUSB8997_FW_NAME_V2);
+ PCIEUART8997_FW_NAME_V2);
else
strcpy(adapter->fw_name,
- PCIEUART8997_FW_NAME_V2);
+ PCIEUSB8997_FW_NAME_V2);
break;
case PCIE8997_Z:
- if (version == CHIP_VER_PCIEUSB)
+ if (version == CHIP_VER_PCIEUART)
strcpy(adapter->fw_name,
- PCIEUSB8997_FW_NAME_Z);
+ PCIEUART8997_FW_NAME_Z);
else
strcpy(adapter->fw_name,
- PCIEUART8997_FW_NAME_Z);
+ PCIEUSB8997_FW_NAME_Z);
break;
default:
strcpy(adapter->fw_name, PCIE8997_DEFAULT_FW_NAME);
diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.h b/drivers/net/wireless/marvell/mwifiex/pcie.h
index 9c00c7e..f05061c 100644
--- a/drivers/net/wireless/marvell/mwifiex/pcie.h
+++ b/drivers/net/wireless/marvell/mwifiex/pcie.h
@@ -32,7 +32,7 @@
#define PCIE8897_DEFAULT_FW_NAME "mrvl/pcie8897_uapsta.bin"
#define PCIE8897_A0_FW_NAME "mrvl/pcie8897_uapsta_a0.bin"
#define PCIE8897_B0_FW_NAME "mrvl/pcie8897_uapsta.bin"
-#define PCIE8997_DEFAULT_FW_NAME "mrvl/pcieuart8997_combo_v2.bin"
+#define PCIE8997_DEFAULT_FW_NAME "mrvl/pcieusb8997_combo_v2.bin"
#define PCIEUART8997_FW_NAME_Z "mrvl/pcieuart8997_combo.bin"
#define PCIEUART8997_FW_NAME_V2 "mrvl/pcieuart8997_combo_v2.bin"
#define PCIEUSB8997_FW_NAME_Z "mrvl/pcieusb8997_combo.bin"
@@ -48,7 +48,7 @@
#define PCIE8897_B0 0x1200
#define PCIE8997_Z 0x0
#define PCIE8997_V2 0x471
-#define CHIP_VER_PCIEUSB 0x2
+#define CHIP_VER_PCIEUART 0x3
/* Constants for Buffer Descriptor (BD) rings */
#define MWIFIEX_MAX_TXRX_BD 0x20
--
cgit v0.12

View File

@ -1837,13 +1837,13 @@ CONFIG_B43=m
CONFIG_B43_SDIO=y
CONFIG_B43_BCMA=y
CONFIG_B43_BCMA_PIO=y
CONFIG_B43_DEBUG=y
# CONFIG_B43_DEBUG is not set
CONFIG_B43_PHY_LP=y
CONFIG_B43_PHY_N=y
CONFIG_B43_PHY_HT=y
CONFIG_B43_PHY_G=y
CONFIG_B43LEGACY=m
CONFIG_B43LEGACY_DEBUG=y
# CONFIG_B43LEGACY_DEBUG is not set
CONFIG_B43LEGACY_DMA=y
CONFIG_B43LEGACY_PIO=y
CONFIG_B43LEGACY_DMA_AND_PIO_MODE=y
@ -2520,6 +2520,7 @@ CONFIG_TOUCHSCREEN_MCS5000=m
CONFIG_TOUCHSCREEN_MK712=m
CONFIG_TOUCHSCREEN_PENMOUNT=m
# CONFIG_TOUCHSCREEN_SUR40 is not set
CONFIG_TOUCHSCREEN_SURFACE3_SPI=m
# CONFIG_TOUCHSCREEN_TPS6507X is not set
CONFIG_TOUCHSCREEN_TS4800=m
CONFIG_TOUCHSCREEN_TSC_SERIO=m
@ -2562,6 +2563,7 @@ CONFIG_INPUT_RETU_PWRBUTTON=m
CONFIG_INPUT_UINPUT=m
CONFIG_INPUT_WISTRON_BTNS=m
CONFIG_INPUT_ATLAS_BTNS=m
CONFIG_INPUT_SURFACE3_BUTTON_ARRAY=m
CONFIG_INPUT_ATI_REMOTE2=m
CONFIG_INPUT_KEYSPAN_REMOTE=m
@ -4525,6 +4527,7 @@ CONFIG_MFD_VIPERBOARD=m
# CONFIG_TS4800_IRQ is not set
# CONFIG_TWL4030_CORE is not set
# CONFIG_TWL6040_CORE is not set
# CONFIG_SURFACE3_POWER is not set
#
# File systems
@ -5218,7 +5221,7 @@ CONFIG_PM_DEBUG=y
# CONFIG_DPM_WATCHDOG is not set # revisit this in debug
CONFIG_PM_TRACE=y
CONFIG_PM_TRACE_RTC=y
CONFIG_PM_TEST_SUSPEND=y
# CONFIG_PM_TEST_SUSPEND is not set
# CONFIG_PM_OPP is not set
# CONFIG_PM_AUTOSLEEP is not set
# CONFIG_PM_WAKELOCKS is not set

View File

@ -2,102 +2,102 @@ CONFIG_SND_VERBOSE_PRINTK=y
CONFIG_SND_DEBUG=y
CONFIG_SND_PCM_XRUN_DEBUG=y
CONFIG_DEBUG_ATOMIC_SLEEP=y
# CONFIG_DEBUG_ATOMIC_SLEEP is not set
CONFIG_DEBUG_MUTEXES=y
CONFIG_DEBUG_RT_MUTEXES=y
CONFIG_DEBUG_LOCK_ALLOC=y
CONFIG_LOCK_TORTURE_TEST=m
CONFIG_PROVE_LOCKING=y
CONFIG_DEBUG_SPINLOCK=y
CONFIG_PROVE_RCU=y
# CONFIG_DEBUG_MUTEXES is not set
# CONFIG_DEBUG_RT_MUTEXES is not set
# CONFIG_DEBUG_LOCK_ALLOC is not set
# CONFIG_LOCK_TORTURE_TEST is not set
# CONFIG_PROVE_LOCKING is not set
# CONFIG_DEBUG_SPINLOCK is not set
# CONFIG_PROVE_RCU is not set
# CONFIG_PROVE_RCU_REPEATEDLY is not set
CONFIG_DEBUG_PER_CPU_MAPS=y
# CONFIG_DEBUG_PER_CPU_MAPS is not set
CONFIG_CPUMASK_OFFSTACK=y
CONFIG_CPU_NOTIFIER_ERROR_INJECT=m
# CONFIG_CPU_NOTIFIER_ERROR_INJECT is not set
CONFIG_FAULT_INJECTION=y
CONFIG_FAILSLAB=y
CONFIG_FAIL_PAGE_ALLOC=y
CONFIG_FAIL_MAKE_REQUEST=y
CONFIG_FAULT_INJECTION_DEBUG_FS=y
CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y
CONFIG_FAIL_IO_TIMEOUT=y
CONFIG_FAIL_MMC_REQUEST=y
# CONFIG_FAULT_INJECTION is not set
# CONFIG_FAILSLAB is not set
# CONFIG_FAIL_PAGE_ALLOC is not set
# CONFIG_FAIL_MAKE_REQUEST is not set
# CONFIG_FAULT_INJECTION_DEBUG_FS is not set
# CONFIG_FAULT_INJECTION_STACKTRACE_FILTER is not set
# CONFIG_FAIL_IO_TIMEOUT is not set
# CONFIG_FAIL_MMC_REQUEST is not set
# CONFIG_F2FS_FAULT_INJECTION is not set
CONFIG_LOCK_STAT=y
# CONFIG_LOCK_STAT is not set
CONFIG_DEBUG_STACK_USAGE=y
# CONFIG_DEBUG_STACK_USAGE is not set
CONFIG_ACPI_DEBUG=y
# CONFIG_ACPI_DEBUG is not set
# CONFIG_ACPI_DEBUGGER is not set
CONFIG_DEBUG_SG=y
CONFIG_DEBUG_PI_LIST=y
# CONFIG_DEBUG_SG is not set
# CONFIG_DEBUG_PI_LIST is not set
# CONFIG_PAGE_EXTENSION is not set
# CONFIG_PAGE_OWNER is not set
# CONFIG_DEBUG_PAGEALLOC is not set
CONFIG_DEBUG_OBJECTS=y
# CONFIG_DEBUG_OBJECTS is not set
# CONFIG_DEBUG_OBJECTS_SELFTEST is not set
CONFIG_DEBUG_OBJECTS_FREE=y
CONFIG_DEBUG_OBJECTS_TIMERS=y
CONFIG_DEBUG_OBJECTS_RCU_HEAD=y
# CONFIG_DEBUG_OBJECTS_FREE is not set
# CONFIG_DEBUG_OBJECTS_TIMERS is not set
# CONFIG_DEBUG_OBJECTS_RCU_HEAD is not set
CONFIG_DEBUG_OBJECTS_ENABLE_DEFAULT=1
CONFIG_X86_PTDUMP=y
CONFIG_ARM64_PTDUMP=y
CONFIG_EFI_PGT_DUMP=y
# CONFIG_ARM64_PTDUMP is not set
# CONFIG_EFI_PGT_DUMP is not set
CONFIG_CAN_DEBUG_DEVICES=y
# CONFIG_CAN_DEBUG_DEVICES is not set
CONFIG_MODULE_FORCE_UNLOAD=y
# CONFIG_MODULE_FORCE_UNLOAD is not set
CONFIG_DEBUG_NOTIFIERS=y
# CONFIG_DEBUG_NOTIFIERS is not set
CONFIG_DMA_API_DEBUG=y
# CONFIG_DMA_API_DEBUG is not set
CONFIG_MMIOTRACE=y
# CONFIG_MMIOTRACE is not set
CONFIG_DEBUG_CREDENTIALS=y
# CONFIG_DEBUG_CREDENTIALS is not set
# off in both production debug and nodebug builds,
# on in rawhide nodebug builds
CONFIG_DEBUG_FORCE_WEAK_PER_CPU=y
# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
CONFIG_EXT4_DEBUG=y
# CONFIG_EXT4_DEBUG is not set
# CONFIG_XFS_WARN is not set
CONFIG_DEBUG_PERF_USE_VMALLOC=y
# CONFIG_DEBUG_PERF_USE_VMALLOC is not set
CONFIG_JBD2_DEBUG=y
# CONFIG_JBD2_DEBUG is not set
CONFIG_NFSD_FAULT_INJECTION=y
# CONFIG_NFSD_FAULT_INJECTION is not set
CONFIG_DEBUG_BLK_CGROUP=y
# CONFIG_DEBUG_BLK_CGROUP is not set
CONFIG_DRBD_FAULT_INJECTION=y
# CONFIG_DRBD_FAULT_INJECTION is not set
CONFIG_ATH_DEBUG=y
CONFIG_CARL9170_DEBUGFS=y
CONFIG_IWLWIFI_DEVICE_TRACING=y
# CONFIG_ATH_DEBUG is not set
# CONFIG_CARL9170_DEBUGFS is not set
# CONFIG_IWLWIFI_DEVICE_TRACING is not set
# CONFIG_RTLWIFI_DEBUG is not set
CONFIG_DEBUG_OBJECTS_WORK=y
# CONFIG_DEBUG_OBJECTS_WORK is not set
CONFIG_DMADEVICES_DEBUG=y
# CONFIG_DMADEVICES_DEBUG is not set
# CONFIG_DMADEVICES_VDEBUG is not set
CONFIG_PM_ADVANCED_DEBUG=y
CONFIG_CEPH_LIB_PRETTYDEBUG=y
CONFIG_QUOTA_DEBUG=y
# CONFIG_CEPH_LIB_PRETTYDEBUG is not set
# CONFIG_QUOTA_DEBUG is not set
CONFIG_KGDB_KDB=y
@ -105,19 +105,19 @@ CONFIG_KDB_DEFAULT_ENABLE=0x0
CONFIG_KDB_KEYBOARD=y
CONFIG_KDB_CONTINUE_CATASTROPHIC=0
CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER=y
# CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER is not set
# CONFIG_PERCPU_TEST is not set
CONFIG_TEST_LIST_SORT=y
# CONFIG_TEST_LIST_SORT is not set
# CONFIG_TEST_STRING_HELPERS is not set
CONFIG_DETECT_HUNG_TASK=y
# CONFIG_DETECT_HUNG_TASK is not set
CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120
# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
CONFIG_WQ_WATCHDOG=y
# CONFIG_WQ_WATCHDOG is not set
CONFIG_X86_BOOTPARAM_MEMORY_CORRUPTION_CHECK=y
# CONFIG_X86_BOOTPARAM_MEMORY_CORRUPTION_CHECK is not set
CONFIG_DEBUG_KMEMLEAK=y
# CONFIG_DEBUG_KMEMLEAK is not set
CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE=1024
# CONFIG_DEBUG_KMEMLEAK_TEST is not set
CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y
@ -128,4 +128,4 @@ CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y
# CONFIG_SPI_DEBUG is not set
CONFIG_DEBUG_VM_PGFLAGS=y
# CONFIG_DEBUG_VM_PGFLAGS is not set

View File

@ -120,6 +120,7 @@ CONFIG_GPIO_CRYSTAL_COVE=y
CONFIG_AXP288_ADC=y
CONFIG_AXP288_FUEL_GAUGE=y
# CONFIG_PWM_CRC is not set
CONFIG_SURFACE3_POWER=y
CONFIG_X86_INTEL_PSTATE=y
@ -249,6 +250,7 @@ CONFIG_PANASONIC_LAPTOP=m
CONFIG_SAMSUNG_LAPTOP=m
CONFIG_SONY_LAPTOP=m
CONFIG_TOPSTAR_LAPTOP=m
CONFIG_SURFACE3_WMI=m
CONFIG_ACPI_WMI=m
CONFIG_ACER_WMI=m
@ -381,7 +383,7 @@ CONFIG_SP5100_TCO=m
# CONFIG_MEMTEST is not set
# CONFIG_DEBUG_TLBFLUSH is not set
CONFIG_MAXSMP=y
# CONFIG_MAXSMP is not set
CONFIG_HP_ILO=m

View File

@ -0,0 +1,111 @@
From 5781fc29dbbd3ee5e11c1bf4fa6696ae89d19840 Mon Sep 17 00:00:00 2001
From: Shengzhen Li <szli@marvell.com>
Date: Fri, 1 Jul 2016 18:26:52 +0530
Subject: mwifiex: fix interrupt processing corner case in MSI mode
As interrupt is read in interrupt handler as well as interrupt processing
thread, we observed a corner case issue for MSI in which interrupt gets
processed twice.
This patch moves interrupt reading code for MSI mode from
mwifiex_interrupt_status() to mwifiex_pcie_process_int() to avoid the
issue.
Signed-off-by: Shengzhen Li <szli@marvell.com>
Signed-off-by: Amitkumar Karwar <akarwar@marvell.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
---
drivers/net/wireless/marvell/mwifiex/pcie.c | 50 ++++++++++++++++++++++++++---
1 file changed, 46 insertions(+), 4 deletions(-)
diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c
index c7f5df8..22fe993 100644
--- a/drivers/net/wireless/marvell/mwifiex/pcie.c
+++ b/drivers/net/wireless/marvell/mwifiex/pcie.c
@@ -2091,6 +2091,13 @@ static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter,
unsigned long flags;
struct pcie_service_card *card = adapter->card;
+ if (card->msi_enable) {
+ spin_lock_irqsave(&adapter->int_lock, flags);
+ adapter->int_status = 1;
+ spin_unlock_irqrestore(&adapter->int_lock, flags);
+ return;
+ }
+
if (!mwifiex_pcie_ok_to_access_hw(adapter))
return;
@@ -2192,15 +2199,44 @@ exit:
static int mwifiex_process_pcie_int(struct mwifiex_adapter *adapter)
{
int ret;
- u32 pcie_ireg;
+ u32 pcie_ireg = 0;
unsigned long flags;
+ struct pcie_service_card *card = adapter->card;
spin_lock_irqsave(&adapter->int_lock, flags);
- /* Clear out unused interrupts */
- pcie_ireg = adapter->int_status;
+ if (!card->msi_enable) {
+ /* Clear out unused interrupts */
+ pcie_ireg = adapter->int_status;
+ }
adapter->int_status = 0;
spin_unlock_irqrestore(&adapter->int_lock, flags);
+ if (card->msi_enable) {
+ if (mwifiex_pcie_ok_to_access_hw(adapter)) {
+ if (mwifiex_read_reg(adapter, PCIE_HOST_INT_STATUS,
+ &pcie_ireg)) {
+ mwifiex_dbg(adapter, ERROR,
+ "Read register failed\n");
+ return -1;
+ }
+
+ if ((pcie_ireg != 0xFFFFFFFF) && (pcie_ireg)) {
+ if (mwifiex_write_reg(adapter,
+ PCIE_HOST_INT_STATUS,
+ ~pcie_ireg)) {
+ mwifiex_dbg(adapter, ERROR,
+ "Write register failed\n");
+ return -1;
+ }
+ if (!adapter->pps_uapsd_mode &&
+ adapter->ps_state == PS_STATE_SLEEP) {
+ adapter->ps_state = PS_STATE_AWAKE;
+ adapter->pm_wakeup_fw_try = false;
+ del_timer(&adapter->wakeup_timer);
+ }
+ }
+ }
+ }
while (pcie_ireg & HOST_INTR_MASK) {
if (pcie_ireg & HOST_INTR_DNLD_DONE) {
pcie_ireg &= ~HOST_INTR_DNLD_DONE;
@@ -2240,6 +2276,12 @@ static int mwifiex_process_pcie_int(struct mwifiex_adapter *adapter)
return ret;
}
+ if (card->msi_enable) {
+ spin_lock_irqsave(&adapter->int_lock, flags);
+ adapter->int_status = 0;
+ spin_unlock_irqrestore(&adapter->int_lock, flags);
+ }
+
if (mwifiex_pcie_ok_to_access_hw(adapter)) {
if (mwifiex_read_reg(adapter, PCIE_HOST_INT_STATUS,
&pcie_ireg)) {
@@ -2263,7 +2305,7 @@ static int mwifiex_process_pcie_int(struct mwifiex_adapter *adapter)
mwifiex_dbg(adapter, INTR,
"info: cmd_sent=%d data_sent=%d\n",
adapter->cmd_sent, adapter->data_sent);
- if (adapter->ps_state != PS_STATE_SLEEP)
+ if (!card->msi_enable && adapter->ps_state != PS_STATE_SLEEP)
mwifiex_pcie_enable_host_int(adapter);
return 0;
--
cgit v0.12

View File

@ -0,0 +1,93 @@
From 5c87a55adbd5eb3536893c40086253e15ea53cd5 Mon Sep 17 00:00:00 2001
From: Mathias Krause <minipli@googlemail.com>
Date: Sat, 21 May 2016 15:43:31 +0200
Subject: mwifiex: remove misleading GFP_DMA flag in buffer allocations
The GFP_DMA flag is obviously misunderstood in the mwifiex driver. It's
meant for legacy ISA DMA memory mappings only -- the lower 16MB on x86.
That doesn't apply to PCIe or SDIO devices, I guess.
Remove the GFP_DMA flag to reduce the need to place the socket buffer
allocation into the low mem DMA area, which might already be in use by
other drivers.
This misuse was flagged by the PaX USERCOPY feature by chance, as it
detected the user copy operation from a DMA buffer in the recvfrom()
syscall path.
Signed-off-by: Mathias Krause <minipli@googlemail.com>
Tested-by: Dennis Wassenberg <dennis.wassenberg@secunet.com>
Cc: Amitkumar Karwar <akarwar@marvell.com>
Cc: Nishant Sarmukadam <nishants@marvell.com>
Cc: Xinming Hu <huxm@marvell.com>
Cc: Kalle Valo <kvalo@codeaurora.org>
Cc: Brad Spengler <spender@grsecurity.net>
Cc: PaX Team <pageexec@freemail.hu>
Acked-by: Amitkumar Karwar <akarwar@marvell.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
---
drivers/net/wireless/marvell/mwifiex/11n_aggr.c | 2 +-
drivers/net/wireless/marvell/mwifiex/pcie.c | 4 ++--
drivers/net/wireless/marvell/mwifiex/sdio.c | 4 ++--
3 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/drivers/net/wireless/marvell/mwifiex/11n_aggr.c b/drivers/net/wireless/marvell/mwifiex/11n_aggr.c
index 1efef3b..dc49c3d 100644
--- a/drivers/net/wireless/marvell/mwifiex/11n_aggr.c
+++ b/drivers/net/wireless/marvell/mwifiex/11n_aggr.c
@@ -184,7 +184,7 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv,
tx_info_src = MWIFIEX_SKB_TXCB(skb_src);
skb_aggr = mwifiex_alloc_dma_align_buf(adapter->tx_buf_size,
- GFP_ATOMIC | GFP_DMA);
+ GFP_ATOMIC);
if (!skb_aggr) {
spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
ra_list_flags);
diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c
index a35db02..1b1e266 100644
--- a/drivers/net/wireless/marvell/mwifiex/pcie.c
+++ b/drivers/net/wireless/marvell/mwifiex/pcie.c
@@ -507,7 +507,7 @@ static int mwifiex_init_rxq_ring(struct mwifiex_adapter *adapter)
for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) {
/* Allocate skb here so that firmware can DMA data from it */
skb = mwifiex_alloc_dma_align_buf(MWIFIEX_RX_DATA_BUF_SIZE,
- GFP_KERNEL | GFP_DMA);
+ GFP_KERNEL);
if (!skb) {
mwifiex_dbg(adapter, ERROR,
"Unable to allocate skb for RX ring.\n");
@@ -1319,7 +1319,7 @@ static int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter)
}
skb_tmp = mwifiex_alloc_dma_align_buf(MWIFIEX_RX_DATA_BUF_SIZE,
- GFP_KERNEL | GFP_DMA);
+ GFP_KERNEL);
if (!skb_tmp) {
mwifiex_dbg(adapter, ERROR,
"Unable to allocate skb.\n");
diff --git a/drivers/net/wireless/marvell/mwifiex/sdio.c b/drivers/net/wireless/marvell/mwifiex/sdio.c
index bdc51ff..674465e 100644
--- a/drivers/net/wireless/marvell/mwifiex/sdio.c
+++ b/drivers/net/wireless/marvell/mwifiex/sdio.c
@@ -1492,7 +1492,7 @@ rx_curr_single:
mwifiex_dbg(adapter, INFO, "info: RX: port: %d, rx_len: %d\n",
port, rx_len);
- skb = mwifiex_alloc_dma_align_buf(rx_len, GFP_KERNEL | GFP_DMA);
+ skb = mwifiex_alloc_dma_align_buf(rx_len, GFP_KERNEL);
if (!skb) {
mwifiex_dbg(adapter, ERROR,
"single skb allocated fail,\t"
@@ -1597,7 +1597,7 @@ static int mwifiex_process_int_status(struct mwifiex_adapter *adapter)
rx_len = (u16) (rx_blocks * MWIFIEX_SDIO_BLOCK_SIZE);
mwifiex_dbg(adapter, INFO, "info: rx_len = %d\n", rx_len);
- skb = mwifiex_alloc_dma_align_buf(rx_len, GFP_KERNEL | GFP_DMA);
+ skb = mwifiex_alloc_dma_align_buf(rx_len, GFP_KERNEL);
if (!skb)
return -1;
--
cgit v0.12

View File

@ -0,0 +1,41 @@
From 2af86f9d954ee86e9b1c492e025de37a1b6d2db8 Mon Sep 17 00:00:00 2001
From: Karthik D A <karthida@marvell.com>
Date: Fri, 15 Jul 2016 18:18:39 +0530
Subject: mwifiex: Fix request_irq() failure handling
It's been observed that request_irq() failure leads to a system crash
due to a bug in mwifiex driver.
When this failure happens, mwifiex_add_card() already takes care of
clearing and freeing adapter->card pointer. This patch removes the
redundant cleanup code causing crash.
Signed-off-by: Karthik D A <karthida@marvell.com>
Signed-off-by: Amitkumar Karwar <akarwar@marvell.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
---
drivers/net/wireless/marvell/mwifiex/pcie.c | 2 --
1 file changed, 2 deletions(-)
diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c
index 22fe993..0faf4a2 100644
--- a/drivers/net/wireless/marvell/mwifiex/pcie.c
+++ b/drivers/net/wireless/marvell/mwifiex/pcie.c
@@ -202,7 +202,6 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev,
if (mwifiex_add_card(card, &add_remove_card_sem, &pcie_ops,
MWIFIEX_PCIE)) {
pr_err("%s failed\n", __func__);
- kfree(card);
return -1;
}
@@ -2843,7 +2842,6 @@ static int mwifiex_pcie_request_irq(struct mwifiex_adapter *adapter)
"MRVL_PCIE", &card->share_irq_ctx);
if (ret) {
pr_err("request_irq failed: ret=%d\n", ret);
- adapter->card = NULL;
return -1;
}
--
cgit v0.12

View File

@ -42,7 +42,7 @@ Summary: The Linux kernel
# For non-released -rc kernels, this will be appended after the rcX and
# gitX tags, so a 3 here would become part of release "0.rcX.gitX.3"
#
%global baserelease 1
%global baserelease 4.surface3
%global fedora_build %{baserelease}
# base_sublevel is the kernel version we're starting with and patching
@ -630,6 +630,44 @@ Patch833: drm-nouveau-disp-sor-gf119-select-correct-sor-when.patch
#rhbz 1346753
Patch834: qla2xxx-Fix-NULL-pointer-deref-in-QLA-interrupt.patch
# Surface 3 patches
Patch900: 0001-Input-add-new-driver-for-the-Surface-3.patch
Patch901: 0001-Input-surface3_spi-Prepare-to-add-support-for-Surfac.patch
Patch902: 0001-Input-surface3_spi-add-surface-pen-support-for-Surfa.patch
Patch903: 0001-HID-input-rework-HID_QUIRK_MULTI_INPUT.patch
Patch904: 0002-HID-multitouch-enable-the-Surface-3-Type-Cover-to-re.patch
Patch905: 0003-HID-multitouch-set-correct-class-for-Surface-Type-Co.patch
Patch906: 0001-Input-soc_button_array-use-gpio_is_valid.patch
Patch907: 0002-Input-soc_button_array-bail-out-earlier-if-gpiod_cou.patch
Patch908: 0003-Input-soc_button_array-make-sure-one-GPIO-is-not-ass.patch
Patch909: 0004-Input-soc_button_array-allow-to-specify-active_low.patch
Patch910: 0005-Input-soc_button_array-export-part-of-the-internals.patch
Patch911: 0006-Input-surface3_button_array-Introduce-button-support.patch
Patch912: 0001-power-MSHW0011-rev-eng-implementation.patch
Patch913: 0002-power-surface3_power-Improve-battery-capacity-report.patch
Patch914: 0001-gpiolib-acpi-make-sure-we-trigger-the-events-at-leas.patch
Patch915: 0001-WIP-acpi-button-remove-pointer-to-old-lid_sysfs-on-u.patch
Patch916: 0001-WIP-i2c-hid-enabled-S0-S3.patch
Patch917: 0002-WIP-add-custom-surface3-platform-device-for-controll.patch
Patch918: ASoC_Intel_Add_support_for_surface3_tablet.patch
Patch919: 07d5c17b80f67d1b2cc2c8243590e2abed4bd7ae..5d554ea4f287665b839975ecb11bd29d49a5c9b5.patch
Patch920: 5d554ea4f287665b839975ecb11bd29d49a5c9b5..24dad509ed5528bbbe31ff17f9fb39c0473ec8f4.patch
Patch921: 6b3c33e985f20e7de07fc4b9b1a96dc452e37cb4..141bcf099076df1a74317a5b14dcd56c933b9de8.patch
Patch922: ee6e7aa383944ce62860f35c86f1ac7da7dd27b6..5c87a55adbd5eb3536893c40086253e15ea53cd5.patch
Patch923: c18b104dd2495da60ec92f40e14559591644cc3a..473dfbfa09934cea0d08cc9023c749a5fce10cb0.patch
Patch924: 473dfbfa09934cea0d08cc9023c749a5fce10cb0..d41376ca8ba74e954ba931c69271d0b29546a202.patch
Patch925: d41376ca8ba74e954ba931c69271d0b29546a202..5781fc29dbbd3ee5e11c1bf4fa6696ae89d19840.patch
Patch926: fd3ed33f51c2a586412d35b4f64803f019ab589f..2af86f9d954ee86e9b1c492e025de37a1b6d2db8.patch
Patch927: 1-2-mwifiex-fix-PCIe-legacy-interrupt-problem.patch
Patch928: 2-2-mwifiex-update-command-response-skb-length-correctly.patch
# END OF PATCH DEFINITIONS
%endif
@ -2155,6 +2193,15 @@ fi
#
#
%changelog
* Wed Jul 20 2016 Bastien Nocera <bnocera@redhat.com> - 4.7.0-0.rc6.git1.4.surface3
- Disable debugging options.
* Tue Jul 19 2016 Bastien Nocera <bnocera@redhat.com> - 4.7.0-0.rc6.git1.3.surface3
- Disable debugging options.
* Tue Jul 19 2016 Bastien Nocera <bnocera@redhat.com> - 4.7.0-0.rc6.git1.2.surface3
- Add Surface 3 patches
* Thu Jul 07 2016 Laura Abbott <labbott@redhat.com> - 4.7.0-0.rc6.git1.1
- Linux v4.7-rc6-74-g076501f
- Reenable debugging options.