* Re: [PATCH] HID: roccat: Mark expected switch fall-through
From: Jiri Kosina @ 2019-02-20 8:40 UTC (permalink / raw)
To: Stefan Achatz
Cc: Gustavo A. R. Silva, Stefan Achatz, Benjamin Tissoires,
linux-input, linux-kernel, Kees Cook
In-Reply-To: <1550650517.5256.2.camel@web.de>
On Wed, 20 Feb 2019, Stefan Achatz wrote:
> I already confirmed this 7 months ago but as I see only in a reply to
> you.
I guess that fell in between cracks somewhere.
> Yes, this patch is correct.
Applied, thanks.
--
Jiri Kosina
SUSE Labs
^ permalink raw reply
* [PATCH 1/2] Input: synaptics-rmi4 - clear irqs before set irqs
From: Aaron Ma @ 2019-02-20 16:41 UTC (permalink / raw)
To: dmitry.torokhov, linux-input, linux-kernel, Cheiny, aduggan,
benjamin.tissoires, aaron.ma
rmi4 got spam data after S3 resume on some ThinkPads.
Then TrackPoint lost when be detected by psmouse.
Clear irqs status before set irqs will make TrackPoint back.
BugLink: https://bugs.launchpad.net/bugs/1791427
Cc: <stable@vger.kernel.org>
Signed-off-by: Aaron Ma <aaron.ma@canonical.com>
---
drivers/input/rmi4/rmi_driver.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/drivers/input/rmi4/rmi_driver.c b/drivers/input/rmi4/rmi_driver.c
index fc3ab93b7aea..20631b272f43 100644
--- a/drivers/input/rmi4/rmi_driver.c
+++ b/drivers/input/rmi4/rmi_driver.c
@@ -374,6 +374,17 @@ static int rmi_driver_set_irq_bits(struct rmi_device *rmi_dev,
struct device *dev = &rmi_dev->dev;
mutex_lock(&data->irq_mutex);
+
+ /* Dummy read in order to clear irqs */
+ error = rmi_read_block(rmi_dev,
+ data->f01_container->fd.data_base_addr + 1,
+ data->irq_status, data->num_of_irq_regs);
+ if (error < 0) {
+ dev_err(dev, "%s: Failed to read interrupt status!",
+ __func__);
+ goto error_unlock;
+ }
+
bitmap_or(data->new_irq_mask,
data->current_irq_mask, mask, data->irq_count);
--
2.17.1
^ permalink raw reply related
* [PATCH 2/2] Input: synaptics-rmi4 - export nosleep of f01 via sysfs
From: Aaron Ma @ 2019-02-20 16:42 UTC (permalink / raw)
To: dmitry.torokhov, linux-input, linux-kernel, Cheiny, aduggan,
benjamin.tissoires, aaron.ma
In-Reply-To: <20190220164200.31044-1-aaron.ma@canonical.com>
Some of ThinkPad X1C6 touchpads didn't wakeup after resume.
Forcing enable nosleep make touchpad back.
Add nosleep via sysfs, so user can control it to workaround issue.
/sys/devices/rmi4-00/nosleep can be written non-zero will enable
nosleep mode.
BugLink: https://bugs.launchpad.net/bugs/1791427
Cc: <stable@vger.kernel.org>
Signed-off-by: Aaron Ma <aaron.ma@canonical.com>
---
drivers/input/rmi4/rmi_f01.c | 45 ++++++++++++++++++++++++++++++++++++
1 file changed, 45 insertions(+)
diff --git a/drivers/input/rmi4/rmi_f01.c b/drivers/input/rmi4/rmi_f01.c
index 4edaa14fe878..e41d1ec625d9 100644
--- a/drivers/input/rmi4/rmi_f01.c
+++ b/drivers/input/rmi4/rmi_f01.c
@@ -325,12 +325,57 @@ static ssize_t rmi_driver_package_id_show(struct device *dev,
static DEVICE_ATTR(package_id, 0444, rmi_driver_package_id_show, NULL);
+static ssize_t rmi_driver_nosleep_show(struct device *dev,
+ struct device_attribute *dattr,
+ char *buf)
+{
+ struct rmi_driver_data *data = dev_get_drvdata(dev);
+ struct f01_data *f01 = dev_get_drvdata(&data->f01_container->dev);
+ int f01_nosleep;
+
+ f01_nosleep = ((f01->device_control.ctrl0 & RMI_F01_CTRL0_NOSLEEP_BIT)
+ ? 1 : 0);
+
+ return scnprintf(buf, PAGE_SIZE, "%d\n", f01_nosleep);
+}
+
+static ssize_t rmi_driver_nosleep_store(struct device *dev,
+ struct device_attribute *dattr,
+ const char *buf, size_t count)
+{
+ struct rmi_driver_data *data = dev_get_drvdata(dev);
+ struct f01_data *f01 = dev_get_drvdata(&data->f01_container->dev);
+ int error;
+
+ if (count <= 0)
+ return count;
+
+ if ('0' == *buf) {
+ f01->device_control.ctrl0 &= ~RMI_F01_CTRL0_NOSLEEP_BIT;
+ } else {
+ f01->device_control.ctrl0 |= RMI_F01_CTRL0_NOSLEEP_BIT;
+ }
+
+ error = rmi_write(data->rmi_dev,
+ data->f01_container->fd.control_base_addr,
+ f01->device_control.ctrl0);
+ if (error) {
+ dev_err(dev, "Failed to write nosleep mode: %d.\n", error);
+ }
+
+ return count;
+}
+
+static DEVICE_ATTR(nosleep, 0644,
+ rmi_driver_nosleep_show, rmi_driver_nosleep_store);
+
static struct attribute *rmi_f01_attrs[] = {
&dev_attr_manufacturer_id.attr,
&dev_attr_date_of_manufacture.attr,
&dev_attr_product_id.attr,
&dev_attr_firmware_id.attr,
&dev_attr_package_id.attr,
+ &dev_attr_nosleep.attr,
NULL
};
--
2.17.1
^ permalink raw reply related
* [PATCH v2 0/2] Add Apple SPI keyboard and trackpad driver
From: Ronald Tschalär @ 2019-02-21 10:56 UTC (permalink / raw)
To: Dmitry Torokhov, Henrik Rydberg
Cc: Lukas Wunner, Federico Lorenzi, Andy Shevchenko, linux-input,
linux-kernel
This changeset adds a driver for the SPI keyboard and trackpad on recent
MacBook's and MacBook Pro's. The driver has seen a fair amount of use
over the last 2 years (basically anybody running linux on these
machines), with only relatively small changes in the last year or so.
For those interested, the driver development has been hosted at
https://github.com/cb22/macbook12-spi-driver/ (as well as my clone at
https://github.com/roadrunner2/macbook12-spi-driver/).
The first patch is just a placeholder for now and is provided in case
somebody wants to compile the driver while it's being reviewed here; the
real patch has been submitted to dri-devel and is being discussed there,
with the intent/hope that I can get an Ack and permission to merge it
through the input subsystem tree here as part of this patch series.
Changes in v2:
Applied all feedback from review by Andy Shevchenko, including:
- reworked logging to use dev_xxx() everywhere
- split 16-bit model_id field into 2 8-bit fields
- factored out several pieces of code into separate functions
- many code style improvements and cleanups
- Kconfig dependency fixes
The full set of changes (except for the Kconfig) can be viewed at
https://github.com/roadrunner2/macbook12-spi-driver/ as individual
commits a651bb9..f832caa in the upstreaming-review branch.
Ronald Tschalär (2):
drm/bridge: sil_sii8620: depend on INPUT instead of selecting it.
Input: add Apple SPI keyboard and trackpad driver.
drivers/gpu/drm/bridge/Kconfig | 2 +-
drivers/input/keyboard/Kconfig | 14 +
drivers/input/keyboard/Makefile | 1 +
drivers/input/keyboard/applespi.c | 2003 +++++++++++++++++++++++++++++
4 files changed, 2019 insertions(+), 1 deletion(-)
create mode 100644 drivers/input/keyboard/applespi.c
--
2.20.1
^ permalink raw reply
* [PATCH v2 1/2] drm/bridge: sil_sii8620: depend on INPUT instead of selecting it.
From: Ronald Tschalär @ 2019-02-21 10:56 UTC (permalink / raw)
To: Dmitry Torokhov, Henrik Rydberg
Cc: Lukas Wunner, Federico Lorenzi, Andy Shevchenko, linux-input,
linux-kernel, Inki Dae, Andrzej Hajda
In-Reply-To: <20190221105609.5710-1-ronald@innovation.ch>
commit d6abe6df706c66d803e6dd4fe98c1b6b7f125a56 (drm/bridge:
sil_sii8620: do not have a dependency of RC_CORE) added a dependency on
INPUT. However, this causes problems with other drivers, in particular
an input driver that depends on MFD_INTEL_LPSS_PCI (to be added in a
future commit):
drivers/clk/Kconfig:9:error: recursive dependency detected!
drivers/clk/Kconfig:9: symbol COMMON_CLK is selected by MFD_INTEL_LPSS
drivers/mfd/Kconfig:566: symbol MFD_INTEL_LPSS is selected by MFD_INTEL_LPSS_PCI
drivers/mfd/Kconfig:580: symbol MFD_INTEL_LPSS_PCI is implied by KEYBOARD_APPLESPI
drivers/input/keyboard/Kconfig:73: symbol KEYBOARD_APPLESPI depends on INPUT
drivers/input/Kconfig:8: symbol INPUT is selected by DRM_SIL_SII8620
drivers/gpu/drm/bridge/Kconfig:83: symbol DRM_SIL_SII8620 depends on DRM_BRIDGE
drivers/gpu/drm/bridge/Kconfig:1: symbol DRM_BRIDGE is selected by DRM_PL111
drivers/gpu/drm/pl111/Kconfig:1: symbol DRM_PL111 depends on COMMON_CLK
According to the docs, select should only be used for non-visible
symbols. Furthermore almost all other references to INPUT throughout the
kernel config are depends, not selects. Hence this change.
CC: Inki Dae <inki.dae@samsung.com>
CC: Andrzej Hajda <a.hajda@samsung.com>
Signed-off-by: Ronald Tschalär <ronald@innovation.ch>
---
drivers/gpu/drm/bridge/Kconfig | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
index 9eeb8ef0b174..bc838e7bb7c8 100644
--- a/drivers/gpu/drm/bridge/Kconfig
+++ b/drivers/gpu/drm/bridge/Kconfig
@@ -83,9 +83,9 @@ config DRM_PARADE_PS8622
config DRM_SIL_SII8620
tristate "Silicon Image SII8620 HDMI/MHL bridge"
depends on OF
+ depends on INPUT
select DRM_KMS_HELPER
imply EXTCON
- select INPUT
select RC_CORE
help
Silicon Image SII8620 HDMI/MHL bridge chip driver.
--
2.20.1
^ permalink raw reply related
* [PATCH v2 2/2] Input: add Apple SPI keyboard and trackpad driver.
From: Ronald Tschalär @ 2019-02-21 10:56 UTC (permalink / raw)
To: Dmitry Torokhov, Henrik Rydberg
Cc: Lukas Wunner, Federico Lorenzi, Andy Shevchenko, linux-input,
linux-kernel
In-Reply-To: <20190221105609.5710-1-ronald@innovation.ch>
The keyboard and trackpad on recent MacBook's (since 8,1) and
MacBookPro's (13,* and 14,*) are attached to an SPI controller instead
of USB, as previously. The higher level protocol is not publicly
documented and hence has been reverse engineered. As a consequence there
are still a number of unknown fields and commands. However, the known
parts have been working well and received extensive testing and use.
In order for this driver to work, the proper SPI drivers need to be
loaded too; for MB8,1 these are spi_pxa2xx_platform and spi_pxa2xx_pci;
for all others they are spi_pxa2xx_platform and intel_lpss_pci. For this
reason enabling this driver in the config implies enabling the above
drivers.
CC: Federico Lorenzi <federico@travelground.com>
CC: Lukas Wunner <lukas@wunner.de>
CC: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Link: https://bugzilla.kernel.org/show_bug.cgi?id=99891
Link: https://bugzilla.kernel.org/show_bug.cgi?id=108331
Signed-off-by: Ronald Tschalär <ronald@innovation.ch>
---
drivers/input/keyboard/Kconfig | 14 +
drivers/input/keyboard/Makefile | 1 +
drivers/input/keyboard/applespi.c | 2003 +++++++++++++++++++++++++++++
3 files changed, 2018 insertions(+)
create mode 100644 drivers/input/keyboard/applespi.c
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index 4713957b0cbb..395e5ce0bc2d 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -70,6 +70,20 @@ config KEYBOARD_AMIGA
config ATARI_KBD_CORE
bool
+config KEYBOARD_APPLESPI
+ tristate "Apple SPI keyboard and trackpad"
+ depends on ACPI && SPI && EFI
+ depends on X86 || COMPILE_TEST
+ imply SPI_PXA2XX
+ imply SPI_PXA2XX_PCI
+ imply MFD_INTEL_LPSS_PCI
+ help
+ Say Y here if you are running Linux on any Apple MacBook8,1 or later,
+ or any MacBookPro13,* or MacBookPro14,*.
+
+ To compile this driver as a module, choose M here: the
+ module will be called applespi.
+
config KEYBOARD_ATARI
tristate "Atari keyboard"
depends on ATARI
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
index 182e92985dbf..9283fee2505a 100644
--- a/drivers/input/keyboard/Makefile
+++ b/drivers/input/keyboard/Makefile
@@ -10,6 +10,7 @@ obj-$(CONFIG_KEYBOARD_ADP5520) += adp5520-keys.o
obj-$(CONFIG_KEYBOARD_ADP5588) += adp5588-keys.o
obj-$(CONFIG_KEYBOARD_ADP5589) += adp5589-keys.o
obj-$(CONFIG_KEYBOARD_AMIGA) += amikbd.o
+obj-$(CONFIG_KEYBOARD_APPLESPI) += applespi.o
obj-$(CONFIG_KEYBOARD_ATARI) += atakbd.o
obj-$(CONFIG_KEYBOARD_ATKBD) += atkbd.o
obj-$(CONFIG_KEYBOARD_BCM) += bcm-keypad.o
diff --git a/drivers/input/keyboard/applespi.c b/drivers/input/keyboard/applespi.c
new file mode 100644
index 000000000000..2a8d1786011d
--- /dev/null
+++ b/drivers/input/keyboard/applespi.c
@@ -0,0 +1,2003 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * MacBook (Pro) SPI keyboard and touchpad driver
+ *
+ * Copyright (c) 2015-2018 Federico Lorenzi
+ * Copyright (c) 2017-2018 Ronald Tschalär
+ */
+
+/*
+ * The keyboard and touchpad controller on the MacBookAir6, MacBookPro12,
+ * MacBook8 and newer can be driven either by USB or SPI. However the USB
+ * pins are only connected on the MacBookAir6 and 7 and the MacBookPro12.
+ * All others need this driver. The interface is selected using ACPI methods:
+ *
+ * * UIEN ("USB Interface Enable"): If invoked with argument 1, disables SPI
+ * and enables USB. If invoked with argument 0, disables USB.
+ * * UIST ("USB Interface Status"): Returns 1 if USB is enabled, 0 otherwise.
+ * * SIEN ("SPI Interface Enable"): If invoked with argument 1, disables USB
+ * and enables SPI. If invoked with argument 0, disables SPI.
+ * * SIST ("SPI Interface Status"): Returns 1 if SPI is enabled, 0 otherwise.
+ * * ISOL: Resets the four GPIO pins used for SPI. Intended to be invoked with
+ * argument 1, then once more with argument 0.
+ *
+ * UIEN and UIST are only provided on models where the USB pins are connected.
+ *
+ * SPI-based Protocol
+ * ------------------
+ *
+ * The device and driver exchange messages (struct message); each message is
+ * encapsulated in one or more packets (struct spi_packet). There are two types
+ * of exchanges: reads, and writes. A read is signaled by a GPE, upon which one
+ * message can be read from the device. A write exchange consists of writing a
+ * command message, immediately reading a short status packet, and then, upon
+ * receiving a GPE, reading the response message. Write exchanges cannot be
+ * interleaved, i.e. a new write exchange must not be started till the previous
+ * write exchange is complete. Whether a received message is part of a read or
+ * write exchange is indicated in the encapsulating packet's flags field.
+ *
+ * A single message may be too large to fit in a single packet (which has a
+ * fixed, 256-byte size). In that case it will be split over multiple,
+ * consecutive packets.
+ */
+
+#include <linux/acpi.h>
+#include <linux/crc16.h>
+#include <linux/delay.h>
+#include <linux/efi.h>
+#include <linux/input.h>
+#include <linux/input/mt.h>
+#include <linux/ktime.h>
+#include <linux/leds.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/spi/spi.h>
+#include <linux/wait.h>
+#include <linux/workqueue.h>
+
+#include <asm/barrier.h>
+#include <asm-generic/unaligned.h>
+
+#define APPLESPI_PACKET_SIZE 256
+#define APPLESPI_STATUS_SIZE 4
+
+#define PACKET_TYPE_READ 0x20
+#define PACKET_TYPE_WRITE 0x40
+#define PACKET_DEV_KEYB 0x01
+#define PACKET_DEV_TPAD 0x02
+#define PACKET_DEV_INFO 0xd0
+
+#define MAX_ROLLOVER 6
+#define MAX_MODIFIERS 8
+
+#define MAX_FINGERS 11
+#define MAX_FINGER_ORIENTATION 16384
+#define MAX_PKTS_PER_MSG 2
+
+#define KBD_BL_LEVEL_MIN 32U
+#define KBD_BL_LEVEL_MAX 255U
+#define KBD_BL_LEVEL_SCALE 1000000U
+#define KBD_BL_LEVEL_ADJ \
+ ((KBD_BL_LEVEL_MAX - KBD_BL_LEVEL_MIN) * KBD_BL_LEVEL_SCALE / 255U)
+
+#define EFI_BL_LEVEL_NAME L"KeyboardBacklightLevel"
+#define EFI_BL_LEVEL_GUID EFI_GUID(0xa076d2af, 0x9678, 0x4386, 0x8b, 0x58, 0x1f, 0xc8, 0xef, 0x04, 0x16, 0x19)
+
+#define DBG_CMD_TP_INI BIT(0)
+#define DBG_CMD_BL BIT(1)
+#define DBG_CMD_CL BIT(2)
+#define DBG_RD_KEYB BIT(8)
+#define DBG_RD_TPAD BIT(9)
+#define DBG_RD_UNKN BIT(10)
+#define DBG_RD_IRQ BIT(11)
+#define DBG_RD_CRC BIT(12)
+#define DBG_TP_DIM BIT(16)
+
+#define DEV(applespi) (&(applespi)->spi->dev)
+
+#define debug_print(mask, applespi, fmt, ...) \
+ do { \
+ if (debug & (mask)) \
+ dev_printk(KERN_DEBUG, DEV(applespi), fmt, \
+ ##__VA_ARGS__); \
+ } while (0)
+
+#define debug_print_header(mask, applespi) \
+ debug_print(mask, applespi, "--- %s ---------------------------\n", \
+ applespi_debug_facility(mask))
+
+#define debug_print_buffer(mask, applespi, fmt, buf, len) \
+ do { \
+ if (debug & (mask)) \
+ dev_print_hex_dump(KERN_DEBUG, DEV(applespi), fmt, \
+ 32, 1, buf, len, false); \
+ } while (0)
+
+#define APPLE_FLAG_FKEY 0x01
+
+#define SPI_RW_CHG_DELAY_US 100 /* from experimentation, in µs */
+
+#define SYNAPTICS_VENDOR_ID 0x06cb
+
+static unsigned int fnmode = 1;
+module_param(fnmode, uint, 0644);
+MODULE_PARM_DESC(fnmode, "Mode of Fn key on Apple keyboards (0 = disabled, [1] = fkeyslast, 2 = fkeysfirst)");
+
+static unsigned int fnremap;
+module_param(fnremap, uint, 0644);
+MODULE_PARM_DESC(fnremap, "Remap Fn key ([0] = no-remap; 1 = left-ctrl, 2 = left-shift, 3 = left-alt, 4 = left-meta, 6 = right-shift, 7 = right-alt, 8 = right-meta)");
+
+static bool iso_layout;
+module_param(iso_layout, bool, 0644);
+MODULE_PARM_DESC(iso_layout, "Enable/Disable hardcoded ISO-layout of the keyboard. ([0] = disabled, 1 = enabled)");
+
+static unsigned int debug;
+module_param(debug, uint, 0644);
+MODULE_PARM_DESC(debug, "Enable/Disable debug logging. This is a bitmask.");
+
+static char touchpad_dimensions[40];
+module_param_string(touchpad_dimensions, touchpad_dimensions,
+ sizeof(touchpad_dimensions), 0444);
+MODULE_PARM_DESC(touchpad_dimensions, "The pixel dimensions of the touchpad, as XxY+W+H .");
+
+/**
+ * struct keyboard_protocol - keyboard message.
+ * message.type = 0x0110, message.length = 0x000a
+ *
+ * @unknown1: unknown
+ * @modifiers: bit-set of modifier/control keys pressed
+ * @unknown2: unknown
+ * @keys_pressed: the (non-modifier) keys currently pressed
+ * @fn_pressed: whether the fn key is currently pressed
+ * @crc16: crc over the whole message struct (message header +
+ * this struct) minus this @crc16 field
+ */
+struct keyboard_protocol {
+ __u8 unknown1;
+ __u8 modifiers;
+ __u8 unknown2;
+ __u8 keys_pressed[MAX_ROLLOVER];
+ __u8 fn_pressed;
+ __le16 crc16;
+};
+
+/**
+ * struct tp_finger - single trackpad finger structure, le16-aligned
+ *
+ * @origin: zero when switching track finger
+ * @abs_x: absolute x coodinate
+ * @abs_y: absolute y coodinate
+ * @rel_x: relative x coodinate
+ * @rel_y: relative y coodinate
+ * @tool_major: tool area, major axis
+ * @tool_minor: tool area, minor axis
+ * @orientation: 16384 when point, else 15 bit angle
+ * @touch_major: touch area, major axis
+ * @touch_minor: touch area, minor axis
+ * @unused: zeros
+ * @pressure: pressure on forcetouch touchpad
+ * @multi: one finger: varies, more fingers: constant
+ * @crc16: on last finger: crc over the whole message struct
+ * (i.e. message header + this struct) minus the last
+ * @crc16 field; unknown on all other fingers.
+ */
+struct tp_finger {
+ __le16 origin;
+ __le16 abs_x;
+ __le16 abs_y;
+ __le16 rel_x;
+ __le16 rel_y;
+ __le16 tool_major;
+ __le16 tool_minor;
+ __le16 orientation;
+ __le16 touch_major;
+ __le16 touch_minor;
+ __le16 unused[2];
+ __le16 pressure;
+ __le16 multi;
+ __le16 crc16;
+};
+
+/**
+ * struct touchpad_protocol - touchpad message.
+ * message.type = 0x0210
+ *
+ * @unknown1: unknown
+ * @clicked: 1 if a button-click was detected, 0 otherwise
+ * @unknown2: unknown
+ * @number_of_fingers: the number of fingers being reported in @fingers
+ * @clicked2: same as @clicked
+ * @unknown3: unknown
+ * @fingers: the data for each finger
+ */
+struct touchpad_protocol {
+ __u8 unknown1[1];
+ __u8 clicked;
+ __u8 unknown2[28];
+ __u8 number_of_fingers;
+ __u8 clicked2;
+ __u8 unknown3[16];
+ struct tp_finger fingers[0];
+};
+
+/**
+ * struct command_protocol_tp_info - get touchpad info.
+ * message.type = 0x1020, message.length = 0x0000
+ *
+ * @crc16: crc over the whole message struct (message header +
+ * this struct) minus this @crc16 field
+ */
+struct command_protocol_tp_info {
+ __le16 crc16;
+};
+
+/**
+ * struct touchpad_info - touchpad info response.
+ * message.type = 0x1020, message.length = 0x006e
+ *
+ * @unknown1: unknown
+ * @model_flags: flags (vary by model number, but significance otherwise
+ * unknown)
+ * @model_no: the touchpad model number
+ * @unknown2: unknown
+ * @crc16: crc over the whole message struct (message header +
+ * this struct) minus this @crc16 field
+ */
+struct touchpad_info_protocol {
+ __u8 unknown1[105];
+ __u8 model_flags;
+ __u8 model_no;
+ __u8 unknown2[3];
+ __le16 crc16;
+};
+
+/**
+ * struct command_protocol_mt_init - initialize multitouch.
+ * message.type = 0x0252, message.length = 0x0002
+ *
+ * @cmd: value: 0x0102
+ * @crc16: crc over the whole message struct (message header +
+ * this struct) minus this @crc16 field
+ */
+struct command_protocol_mt_init {
+ __le16 cmd;
+ __le16 crc16;
+};
+
+/**
+ * struct command_protocol_capsl - toggle caps-lock led
+ * message.type = 0x0151, message.length = 0x0002
+ *
+ * @unknown: value: 0x01 (length?)
+ * @led: 0 off, 2 on
+ * @crc16: crc over the whole message struct (message header +
+ * this struct) minus this @crc16 field
+ */
+struct command_protocol_capsl {
+ __u8 unknown;
+ __u8 led;
+ __le16 crc16;
+};
+
+/**
+ * struct command_protocol_bl - set keyboard backlight brightness
+ * message.type = 0xB051, message.length = 0x0006
+ *
+ * @const1: value: 0x01B0
+ * @level: the brightness level to set
+ * @const2: value: 0x0001 (backlight off), 0x01F4 (backlight on)
+ * @crc16: crc over the whole message struct (message header +
+ * this struct) minus this @crc16 field
+ */
+struct command_protocol_bl {
+ __le16 const1;
+ __le16 level;
+ __le16 const2;
+ __le16 crc16;
+};
+
+/**
+ * struct message - a complete spi message.
+ *
+ * Each message begins with fixed header, followed by a message-type specific
+ * payload, and ends with a 16-bit crc. Because of the varying lengths of the
+ * payload, the crc is defined at the end of each payload struct, rather than
+ * in this struct.
+ *
+ * @type: the message type
+ * @zero: always 0
+ * @counter: incremented on each message, rolls over after 255; there is a
+ * separate counter for each message type.
+ * @rsp_buf_len:response buffer length (the exact nature of this field is quite
+ * speculative). On a request/write this is often the same as
+ * @length, though in some cases it has been seen to be much larger
+ * (e.g. 0x400); on a response/read this the same as on the
+ * request; for reads that are not responses it is 0.
+ * @length: length of the remainder of the data in the whole message
+ * structure (after re-assembly in case of being split over
+ * multiple spi-packets), minus the trailing crc. The total size
+ * of the message struct is therefore @length + 10.
+ */
+struct message {
+ __le16 type;
+ __u8 zero;
+ __u8 counter;
+ __le16 rsp_buf_len;
+ __le16 length;
+ union {
+ struct keyboard_protocol keyboard;
+ struct touchpad_protocol touchpad;
+ struct touchpad_info_protocol tp_info;
+ struct command_protocol_tp_info tp_info_command;
+ struct command_protocol_mt_init init_mt_command;
+ struct command_protocol_capsl capsl_command;
+ struct command_protocol_bl bl_command;
+ __u8 data[0];
+ };
+};
+
+/* type + zero + counter + rsp_buf_len + length */
+#define MSG_HEADER_SIZE 8
+
+/**
+ * struct spi_packet - a complete spi packet; always 256 bytes. This carries
+ * the (parts of the) message in the data. But note that this does not
+ * necessarily contain a complete message, as in some cases (e.g. many
+ * fingers pressed) the message is split over multiple packets (see the
+ * @offset, @remaining, and @length fields). In general the data parts in
+ * spi_packet's are concatenated until @remaining is 0, and the result is an
+ * message.
+ *
+ * @flags: 0x40 = write (to device), 0x20 = read (from device); note that
+ * the response to a write still has 0x40.
+ * @device: 1 = keyboard, 2 = touchpad
+ * @offset: specifies the offset of this packet's data in the complete
+ * message; i.e. > 0 indicates this is a continuation packet (in
+ * the second packet for a message split over multiple packets
+ * this would then be the same as the @length in the first packet)
+ * @remaining: number of message bytes remaining in subsequents packets (in
+ * the first packet of a message split over two packets this would
+ * then be the same as the @length in the second packet)
+ * @length: length of the valid data in the @data in this packet
+ * @data: all or part of a message
+ * @crc16: crc over this whole structure minus this @crc16 field. This
+ * covers just this packet, even on multi-packet messages (in
+ * contrast to the crc in the message).
+ */
+struct spi_packet {
+ __u8 flags;
+ __u8 device;
+ __le16 offset;
+ __le16 remaining;
+ __le16 length;
+ __u8 data[246];
+ __le16 crc16;
+};
+
+struct spi_settings {
+ u64 spi_cs_delay; /* cs-to-clk delay in us */
+ u64 reset_a2r_usec; /* active-to-receive delay? */
+ u64 reset_rec_usec; /* ? (cur val: 10) */
+};
+
+struct applespi_tp_info {
+ int x_min;
+ int y_min;
+ int x_max;
+ int y_max;
+};
+
+struct applespi_data {
+ struct spi_device *spi;
+ struct spi_settings spi_settings;
+ struct input_dev *keyboard_input_dev;
+ struct input_dev *touchpad_input_dev;
+
+ u8 *tx_buffer;
+ u8 *tx_status;
+ u8 *rx_buffer;
+
+ u8 *msg_buf;
+ unsigned int saved_msg_len;
+
+ struct applespi_tp_info tp_info;
+
+ u8 last_keys_pressed[MAX_ROLLOVER];
+ u8 last_keys_fn_pressed[MAX_ROLLOVER];
+ u8 last_fn_pressed;
+ struct input_mt_pos pos[MAX_FINGERS];
+ int slots[MAX_FINGERS];
+ acpi_handle handle;
+ int gpe;
+ acpi_handle sien;
+ acpi_handle sist;
+
+ struct spi_transfer dl_t;
+ struct spi_transfer rd_t;
+ struct spi_message rd_m;
+
+ struct spi_transfer ww_t;
+ struct spi_transfer wd_t;
+ struct spi_transfer wr_t;
+ struct spi_transfer st_t;
+ struct spi_message wr_m;
+
+ bool want_tp_info_cmd;
+ bool want_mt_init_cmd;
+ bool want_cl_led_on;
+ bool have_cl_led_on;
+ unsigned int want_bl_level;
+ unsigned int have_bl_level;
+ unsigned int cmd_msg_cntr;
+ /* lock to protect the above parameters and flags below */
+ spinlock_t cmd_msg_lock;
+ bool cmd_msg_queued;
+ unsigned int cmd_log_mask;
+
+ struct led_classdev backlight_info;
+
+ bool suspended;
+ bool drain;
+ wait_queue_head_t drain_complete;
+ bool read_active;
+ bool write_active;
+
+ struct work_struct work;
+ struct touchpad_info_protocol rcvd_tp_info;
+};
+
+static const unsigned char applespi_scancodes[] = {
+ 0, 0, 0, 0,
+ KEY_A, KEY_B, KEY_C, KEY_D, KEY_E, KEY_F, KEY_G, KEY_H, KEY_I, KEY_J,
+ KEY_K, KEY_L, KEY_M, KEY_N, KEY_O, KEY_P, KEY_Q, KEY_R, KEY_S, KEY_T,
+ KEY_U, KEY_V, KEY_W, KEY_X, KEY_Y, KEY_Z,
+ KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8, KEY_9, KEY_0,
+ KEY_ENTER, KEY_ESC, KEY_BACKSPACE, KEY_TAB, KEY_SPACE, KEY_MINUS,
+ KEY_EQUAL, KEY_LEFTBRACE, KEY_RIGHTBRACE, KEY_BACKSLASH, 0,
+ KEY_SEMICOLON, KEY_APOSTROPHE, KEY_GRAVE, KEY_COMMA, KEY_DOT, KEY_SLASH,
+ KEY_CAPSLOCK,
+ KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6, KEY_F7, KEY_F8, KEY_F9,
+ KEY_F10, KEY_F11, KEY_F12, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ KEY_RIGHT, KEY_LEFT, KEY_DOWN, KEY_UP,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KEY_102ND,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KEY_RO, 0, KEY_YEN, 0, 0, 0, 0, 0,
+ 0, KEY_KATAKANAHIRAGANA, KEY_MUHENKAN
+};
+
+static const unsigned char applespi_controlcodes[] = {
+ KEY_LEFTCTRL,
+ KEY_LEFTSHIFT,
+ KEY_LEFTALT,
+ KEY_LEFTMETA,
+ 0,
+ KEY_RIGHTSHIFT,
+ KEY_RIGHTALT,
+ KEY_RIGHTMETA
+};
+
+struct applespi_key_translation {
+ u16 from;
+ u16 to;
+ u8 flags;
+};
+
+static const struct applespi_key_translation applespi_fn_codes[] = {
+ { KEY_BACKSPACE, KEY_DELETE },
+ { KEY_ENTER, KEY_INSERT },
+ { KEY_F1, KEY_BRIGHTNESSDOWN, APPLE_FLAG_FKEY },
+ { KEY_F2, KEY_BRIGHTNESSUP, APPLE_FLAG_FKEY },
+ { KEY_F3, KEY_SCALE, APPLE_FLAG_FKEY },
+ { KEY_F4, KEY_DASHBOARD, APPLE_FLAG_FKEY },
+ { KEY_F5, KEY_KBDILLUMDOWN, APPLE_FLAG_FKEY },
+ { KEY_F6, KEY_KBDILLUMUP, APPLE_FLAG_FKEY },
+ { KEY_F7, KEY_PREVIOUSSONG, APPLE_FLAG_FKEY },
+ { KEY_F8, KEY_PLAYPAUSE, APPLE_FLAG_FKEY },
+ { KEY_F9, KEY_NEXTSONG, APPLE_FLAG_FKEY },
+ { KEY_F10, KEY_MUTE, APPLE_FLAG_FKEY },
+ { KEY_F11, KEY_VOLUMEDOWN, APPLE_FLAG_FKEY },
+ { KEY_F12, KEY_VOLUMEUP, APPLE_FLAG_FKEY },
+ { KEY_RIGHT, KEY_END },
+ { KEY_LEFT, KEY_HOME },
+ { KEY_DOWN, KEY_PAGEDOWN },
+ { KEY_UP, KEY_PAGEUP },
+ { }
+};
+
+static const struct applespi_key_translation apple_iso_keyboard[] = {
+ { KEY_GRAVE, KEY_102ND },
+ { KEY_102ND, KEY_GRAVE },
+ { }
+};
+
+struct applespi_tp_model_info {
+ u16 model;
+ struct applespi_tp_info tp_info;
+};
+
+static const struct applespi_tp_model_info applespi_tp_models[] = {
+ {
+ .model = 0x04, /* MB8 MB9 MB10 */
+ .tp_info = { -5087, -182, 5579, 6089 },
+ },
+ {
+ .model = 0x05, /* MBP13,1 MBP13,2 MBP14,1 MBP14,2 */
+ .tp_info = { -6243, -170, 6749, 7685 },
+ },
+ {
+ .model = 0x06, /* MBP13,3 MBP14,3 */
+ .tp_info = { -7456, -163, 7976, 9283 },
+ },
+ {}
+};
+
+/**
+ * This is a reduced version of print_hex_dump() that uses dev_printk().
+ */
+static void dev_print_hex_dump(const char *level, const struct device *dev,
+ const char *prefix_str,
+ int rowsize, int groupsize,
+ const void *buf, size_t len, bool ascii)
+{
+ const u8 *ptr = buf;
+ int i, linelen, remaining = len;
+ unsigned char linebuf[32 * 3 + 2 + 32 + 1];
+
+ if (rowsize != 16 && rowsize != 32)
+ rowsize = 16;
+
+ for (i = 0; i < len; i += rowsize) {
+ linelen = min(remaining, rowsize);
+ remaining -= rowsize;
+
+ hex_dump_to_buffer(ptr + i, linelen, rowsize, groupsize,
+ linebuf, sizeof(linebuf), ascii);
+
+ dev_printk(level, dev, "%s%s\n", prefix_str, linebuf);
+ }
+}
+
+static const char *applespi_debug_facility(unsigned int log_mask)
+{
+ switch (log_mask) {
+ case DBG_CMD_TP_INI:
+ return "Touchpad Initialization";
+ case DBG_CMD_BL:
+ return "Backlight Command";
+ case DBG_CMD_CL:
+ return "Caps-Lock Command";
+ case DBG_RD_KEYB:
+ return "Keyboard Event";
+ case DBG_RD_TPAD:
+ return "Touchpad Event";
+ case DBG_RD_UNKN:
+ return "Unknown Event";
+ case DBG_RD_IRQ:
+ return "Interrupt Request";
+ case DBG_RD_CRC:
+ return "Corrupted packet";
+ case DBG_TP_DIM:
+ return "Touchpad Dimensions";
+ default:
+ return "-Unrecognized log mask-";
+ }
+}
+
+static void applespi_setup_read_txfrs(struct applespi_data *applespi)
+{
+ struct spi_message *msg = &applespi->rd_m;
+ struct spi_transfer *dl_t = &applespi->dl_t;
+ struct spi_transfer *rd_t = &applespi->rd_t;
+
+ memset(dl_t, 0, sizeof(*dl_t));
+ memset(rd_t, 0, sizeof(*rd_t));
+
+ dl_t->delay_usecs = applespi->spi_settings.spi_cs_delay;
+
+ rd_t->rx_buf = applespi->rx_buffer;
+ rd_t->len = APPLESPI_PACKET_SIZE;
+
+ spi_message_init(msg);
+ spi_message_add_tail(dl_t, msg);
+ spi_message_add_tail(rd_t, msg);
+}
+
+static void applespi_setup_write_txfrs(struct applespi_data *applespi)
+{
+ struct spi_message *msg = &applespi->wr_m;
+ struct spi_transfer *wt_t = &applespi->ww_t;
+ struct spi_transfer *dl_t = &applespi->wd_t;
+ struct spi_transfer *wr_t = &applespi->wr_t;
+ struct spi_transfer *st_t = &applespi->st_t;
+
+ memset(wt_t, 0, sizeof(*wt_t));
+ memset(dl_t, 0, sizeof(*dl_t));
+ memset(wr_t, 0, sizeof(*wr_t));
+ memset(st_t, 0, sizeof(*st_t));
+
+ /*
+ * All we need here is a delay at the beginning of the message before
+ * asserting cs. But the current spi API doesn't support this, so we
+ * end up with an extra unnecessary (but harmless) cs assertion and
+ * deassertion.
+ */
+ wt_t->delay_usecs = SPI_RW_CHG_DELAY_US;
+ wt_t->cs_change = 1;
+
+ dl_t->delay_usecs = applespi->spi_settings.spi_cs_delay;
+
+ wr_t->tx_buf = applespi->tx_buffer;
+ wr_t->len = APPLESPI_PACKET_SIZE;
+ wr_t->delay_usecs = SPI_RW_CHG_DELAY_US;
+
+ st_t->rx_buf = applespi->tx_status;
+ st_t->len = APPLESPI_STATUS_SIZE;
+
+ spi_message_init(msg);
+ spi_message_add_tail(wt_t, msg);
+ spi_message_add_tail(dl_t, msg);
+ spi_message_add_tail(wr_t, msg);
+ spi_message_add_tail(st_t, msg);
+}
+
+static int applespi_async(struct applespi_data *applespi,
+ struct spi_message *message, void (*complete)(void *))
+{
+ message->complete = complete;
+ message->context = applespi;
+
+ return spi_async(applespi->spi, message);
+}
+
+static inline bool applespi_check_write_status(struct applespi_data *applespi,
+ int sts)
+{
+ static u8 status_ok[] = { 0xac, 0x27, 0x68, 0xd5 };
+
+ if (sts < 0) {
+ dev_warn(DEV(applespi), "Error writing to device: %d\n", sts);
+ return false;
+ }
+
+ if (memcmp(applespi->tx_status, status_ok, APPLESPI_STATUS_SIZE)) {
+ dev_warn(DEV(applespi), "Error writing to device: %*ph\n",
+ APPLESPI_STATUS_SIZE, applespi->tx_status);
+ return false;
+ }
+
+ return true;
+}
+
+static int applespi_get_spi_settings(struct applespi_data *applespi)
+{
+ struct acpi_device *adev = ACPI_COMPANION(DEV(applespi));
+ const union acpi_object *o;
+ struct spi_settings *settings = &applespi->spi_settings;
+
+ if (!acpi_dev_get_property(adev, "spiCSDelay", ACPI_TYPE_BUFFER, &o))
+ settings->spi_cs_delay = *(u64 *)o->buffer.pointer;
+ else
+ dev_warn(DEV(applespi), "Property spiCSDelay not found\n");
+
+ if (!acpi_dev_get_property(adev, "resetA2RUsec", ACPI_TYPE_BUFFER, &o))
+ settings->reset_a2r_usec = *(u64 *)o->buffer.pointer;
+ else
+ dev_warn(DEV(applespi), "Property resetA2RUsec not found\n");
+
+ if (!acpi_dev_get_property(adev, "resetRecUsec", ACPI_TYPE_BUFFER, &o))
+ settings->reset_rec_usec = *(u64 *)o->buffer.pointer;
+ else
+ dev_warn(DEV(applespi), "Property resetRecUsec not found\n");
+
+ dev_dbg(DEV(applespi),
+ "SPI settings: spi_cs_delay=%llu reset_a2r_usec=%llu reset_rec_usec=%llu\n",
+ settings->spi_cs_delay, settings->reset_a2r_usec,
+ settings->reset_rec_usec);
+
+ return 0;
+}
+
+static int applespi_setup_spi(struct applespi_data *applespi)
+{
+ int sts;
+
+ sts = applespi_get_spi_settings(applespi);
+ if (sts)
+ return sts;
+
+ spin_lock_init(&applespi->cmd_msg_lock);
+ init_waitqueue_head(&applespi->drain_complete);
+
+ return 0;
+}
+
+static int applespi_enable_spi(struct applespi_data *applespi)
+{
+ acpi_status acpi_sts;
+ unsigned long long spi_status;
+
+ /* check if SPI is already enabled, so we can skip the delay below */
+ acpi_sts = acpi_evaluate_integer(applespi->sist, NULL, NULL,
+ &spi_status);
+ if (ACPI_SUCCESS(acpi_sts) && spi_status)
+ return 0;
+
+ /* SIEN(1) will enable SPI communication */
+ acpi_sts = acpi_execute_simple_method(applespi->sien, NULL, 1);
+ if (ACPI_FAILURE(acpi_sts)) {
+ dev_err(DEV(applespi), "SIEN failed: %s\n",
+ acpi_format_exception(acpi_sts));
+ return -ENODEV;
+ }
+
+ /*
+ * Allow the SPI interface to come up before returning. Without this
+ * delay, the SPI commands to enable multitouch mode may not reach
+ * the trackpad controller, causing pointer movement to break upon
+ * resume from sleep.
+ */
+ msleep(50);
+
+ return 0;
+}
+
+static int applespi_send_cmd_msg(struct applespi_data *applespi);
+
+static void applespi_msg_complete(struct applespi_data *applespi,
+ bool is_write_msg, bool is_read_compl)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&applespi->cmd_msg_lock, flags);
+
+ if (is_read_compl)
+ applespi->read_active = false;
+ if (is_write_msg)
+ applespi->write_active = false;
+
+ if (applespi->drain && !applespi->write_active)
+ wake_up_all(&applespi->drain_complete);
+
+ if (is_write_msg) {
+ applespi->cmd_msg_queued = false;
+ applespi_send_cmd_msg(applespi);
+ }
+
+ spin_unlock_irqrestore(&applespi->cmd_msg_lock, flags);
+}
+
+static void applespi_async_write_complete(void *context)
+{
+ struct applespi_data *applespi = context;
+
+ debug_print_header(applespi->cmd_log_mask, applespi);
+ debug_print_buffer(applespi->cmd_log_mask, applespi, "write ",
+ applespi->tx_buffer, APPLESPI_PACKET_SIZE);
+ debug_print_buffer(applespi->cmd_log_mask, applespi, "status ",
+ applespi->tx_status, APPLESPI_STATUS_SIZE);
+
+ if (!applespi_check_write_status(applespi, applespi->wr_m.status)) {
+ /*
+ * If we got an error, we presumably won't get the expected
+ * response message either.
+ */
+ applespi_msg_complete(applespi, true, false);
+ }
+}
+
+static int applespi_send_cmd_msg(struct applespi_data *applespi)
+{
+ u16 crc;
+ int sts;
+ struct spi_packet *packet = (struct spi_packet *)applespi->tx_buffer;
+ struct message *message = (struct message *)packet->data;
+ u16 msg_len;
+ u8 device;
+
+ /* check if draining */
+ if (applespi->drain)
+ return 0;
+
+ /* check whether send is in progress */
+ if (applespi->cmd_msg_queued)
+ return 0;
+
+ /* set up packet */
+ memset(packet, 0, APPLESPI_PACKET_SIZE);
+
+ /* are we processing init commands? */
+ if (applespi->want_tp_info_cmd) {
+ applespi->want_tp_info_cmd = false;
+ applespi->want_mt_init_cmd = true;
+ applespi->cmd_log_mask = DBG_CMD_TP_INI;
+
+ /* build init command */
+ device = PACKET_DEV_INFO;
+
+ message->type = cpu_to_le16(0x1020);
+ msg_len = sizeof(message->tp_info_command);
+
+ message->zero = 0x02;
+ message->rsp_buf_len = cpu_to_le16(0x0200);
+
+ } else if (applespi->want_mt_init_cmd) {
+ applespi->want_mt_init_cmd = false;
+ applespi->cmd_log_mask = DBG_CMD_TP_INI;
+
+ /* build init command */
+ device = PACKET_DEV_TPAD;
+
+ message->type = cpu_to_le16(0x0252);
+ msg_len = sizeof(message->init_mt_command);
+
+ message->init_mt_command.cmd = cpu_to_le16(0x0102);
+
+ /* do we need caps-lock command? */
+ } else if (applespi->want_cl_led_on != applespi->have_cl_led_on) {
+ applespi->have_cl_led_on = applespi->want_cl_led_on;
+ applespi->cmd_log_mask = DBG_CMD_CL;
+
+ /* build led command */
+ device = PACKET_DEV_KEYB;
+
+ message->type = cpu_to_le16(0x0151);
+ msg_len = sizeof(message->capsl_command);
+
+ message->capsl_command.unknown = 0x01;
+ message->capsl_command.led = applespi->have_cl_led_on ? 2 : 0;
+
+ /* do we need backlight command? */
+ } else if (applespi->want_bl_level != applespi->have_bl_level) {
+ applespi->have_bl_level = applespi->want_bl_level;
+ applespi->cmd_log_mask = DBG_CMD_BL;
+
+ /* build command buffer */
+ device = PACKET_DEV_KEYB;
+
+ message->type = cpu_to_le16(0xB051);
+ msg_len = sizeof(message->bl_command);
+
+ message->bl_command.const1 = cpu_to_le16(0x01B0);
+ message->bl_command.level =
+ cpu_to_le16(applespi->have_bl_level);
+
+ if (applespi->have_bl_level > 0)
+ message->bl_command.const2 = cpu_to_le16(0x01F4);
+ else
+ message->bl_command.const2 = cpu_to_le16(0x0001);
+
+ /* everything's up-to-date */
+ } else {
+ return 0;
+ }
+
+ /* finalize packet */
+ packet->flags = PACKET_TYPE_WRITE;
+ packet->device = device;
+ packet->length = cpu_to_le16(MSG_HEADER_SIZE + msg_len);
+
+ message->counter = applespi->cmd_msg_cntr++ % (U8_MAX + 1);
+
+ message->length = cpu_to_le16(msg_len - 2);
+ if (!message->rsp_buf_len)
+ message->rsp_buf_len = message->length;
+
+ crc = crc16(0, (u8 *)message, le16_to_cpu(packet->length) - 2);
+ put_unaligned_le16(crc, &message->data[msg_len - 2]);
+
+ crc = crc16(0, (u8 *)packet, sizeof(*packet) - 2);
+ packet->crc16 = cpu_to_le16(crc);
+
+ /* send command */
+ sts = applespi_async(applespi, &applespi->wr_m,
+ applespi_async_write_complete);
+ if (sts) {
+ dev_warn(DEV(applespi),
+ "Error queueing async write to device: %d\n", sts);
+ return sts;
+ }
+
+ applespi->cmd_msg_queued = true;
+ applespi->write_active = true;
+
+ return 0;
+}
+
+static void applespi_init(struct applespi_data *applespi, bool is_resume)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&applespi->cmd_msg_lock, flags);
+
+ if (is_resume)
+ applespi->want_mt_init_cmd = true;
+ else
+ applespi->want_tp_info_cmd = true;
+ applespi_send_cmd_msg(applespi);
+
+ spin_unlock_irqrestore(&applespi->cmd_msg_lock, flags);
+}
+
+static int applespi_set_capsl_led(struct applespi_data *applespi,
+ bool capslock_on)
+{
+ unsigned long flags;
+ int sts;
+
+ spin_lock_irqsave(&applespi->cmd_msg_lock, flags);
+
+ applespi->want_cl_led_on = capslock_on;
+ sts = applespi_send_cmd_msg(applespi);
+
+ spin_unlock_irqrestore(&applespi->cmd_msg_lock, flags);
+
+ return sts;
+}
+
+static void applespi_set_bl_level(struct led_classdev *led_cdev,
+ enum led_brightness value)
+{
+ struct applespi_data *applespi =
+ container_of(led_cdev, struct applespi_data, backlight_info);
+ unsigned long flags;
+ int sts;
+
+ spin_lock_irqsave(&applespi->cmd_msg_lock, flags);
+
+ if (value == 0)
+ applespi->want_bl_level = value;
+ else
+ /*
+ * The backlight does not turn on till level 32, so we scale
+ * the range here so that from a user's perspective it turns
+ * on at 1.
+ */
+ applespi->want_bl_level =
+ ((value * KBD_BL_LEVEL_ADJ) / KBD_BL_LEVEL_SCALE +
+ KBD_BL_LEVEL_MIN);
+
+ sts = applespi_send_cmd_msg(applespi);
+
+ spin_unlock_irqrestore(&applespi->cmd_msg_lock, flags);
+}
+
+static int applespi_event(struct input_dev *dev, unsigned int type,
+ unsigned int code, int value)
+{
+ struct applespi_data *applespi = input_get_drvdata(dev);
+
+ switch (type) {
+ case EV_LED:
+ applespi_set_capsl_led(applespi, !!test_bit(LED_CAPSL, dev->led));
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+/* lifted from the BCM5974 driver and renamed from raw2int */
+/* convert 16-bit little endian to signed integer */
+static inline int le16_to_int(__le16 x)
+{
+ return (signed short)le16_to_cpu(x);
+}
+
+static int applespi_dbg_dim_min_x;
+static int applespi_dbg_dim_max_x;
+static int applespi_dbg_dim_min_y;
+static int applespi_dbg_dim_max_y;
+static bool applespi_dbg_dim_updated;
+
+static void applespi_debug_update_dimensions(const struct tp_finger *f)
+{
+ #define UPDATE_DIMENSIONS(val, op, last) \
+ do { \
+ if (le16_to_int(val) op last) { \
+ last = le16_to_int(val); \
+ applespi_dbg_dim_updated = true; \
+ } \
+ } while (0)
+
+ UPDATE_DIMENSIONS(f->abs_x, <, applespi_dbg_dim_min_x);
+ UPDATE_DIMENSIONS(f->abs_x, >, applespi_dbg_dim_max_x);
+ UPDATE_DIMENSIONS(f->abs_y, <, applespi_dbg_dim_min_y);
+ UPDATE_DIMENSIONS(f->abs_y, >, applespi_dbg_dim_max_y);
+
+ #undef UPDATE_DIMENSIONS
+}
+
+static void applespi_debug_print_dimensions(struct applespi_data *applespi)
+{
+ static ktime_t last_print;
+
+ if (applespi_dbg_dim_updated &&
+ ktime_ms_delta(ktime_get(), last_print) > 1000) {
+ debug_print(DBG_TP_DIM, applespi,
+ "New touchpad dimensions: %dx%d+%u+%u\n",
+ applespi_dbg_dim_min_x, applespi_dbg_dim_min_y,
+ applespi_dbg_dim_max_x - applespi_dbg_dim_min_x,
+ applespi_dbg_dim_max_y - applespi_dbg_dim_min_y);
+ applespi_dbg_dim_updated = false;
+ last_print = ktime_get();
+ }
+}
+
+static void report_finger_data(struct input_dev *input, int slot,
+ const struct input_mt_pos *pos,
+ const struct tp_finger *f)
+{
+ input_mt_slot(input, slot);
+ input_mt_report_slot_state(input, MT_TOOL_FINGER, true);
+
+ input_report_abs(input, ABS_MT_TOUCH_MAJOR,
+ le16_to_int(f->touch_major) << 1);
+ input_report_abs(input, ABS_MT_TOUCH_MINOR,
+ le16_to_int(f->touch_minor) << 1);
+ input_report_abs(input, ABS_MT_WIDTH_MAJOR,
+ le16_to_int(f->tool_major) << 1);
+ input_report_abs(input, ABS_MT_WIDTH_MINOR,
+ le16_to_int(f->tool_minor) << 1);
+ input_report_abs(input, ABS_MT_ORIENTATION,
+ MAX_FINGER_ORIENTATION - le16_to_int(f->orientation));
+ input_report_abs(input, ABS_MT_POSITION_X, pos->x);
+ input_report_abs(input, ABS_MT_POSITION_Y, pos->y);
+}
+
+static void report_tp_state(struct applespi_data *applespi,
+ struct touchpad_protocol *t)
+{
+ const struct tp_finger *f;
+ struct input_dev *input;
+ const struct applespi_tp_info *tp_info = &applespi->tp_info;
+ int i, n;
+
+ /* touchpad_input_dev is set async in worker */
+ input = smp_load_acquire(&applespi->touchpad_input_dev);
+ if (!input)
+ return; /* touchpad isn't initialized yet */
+
+ n = 0;
+
+ for (i = 0; i < t->number_of_fingers; i++) {
+ f = &t->fingers[i];
+ if (le16_to_int(f->touch_major) == 0)
+ continue;
+ applespi->pos[n].x = le16_to_int(f->abs_x);
+ applespi->pos[n].y = tp_info->y_min + tp_info->y_max -
+ le16_to_int(f->abs_y);
+ n++;
+
+ if (debug & DBG_TP_DIM)
+ applespi_debug_update_dimensions(f);
+ }
+
+ if (debug & DBG_TP_DIM)
+ applespi_debug_print_dimensions(applespi);
+
+ input_mt_assign_slots(input, applespi->slots, applespi->pos, n, 0);
+
+ for (i = 0; i < n; i++)
+ report_finger_data(input, applespi->slots[i],
+ &applespi->pos[i], &t->fingers[i]);
+
+ input_mt_sync_frame(input);
+ input_report_key(input, BTN_LEFT, t->clicked);
+
+ input_sync(input);
+}
+
+static const struct applespi_key_translation *
+applespi_find_translation(const struct applespi_key_translation *table, u16 key)
+{
+ const struct applespi_key_translation *trans;
+
+ for (trans = table; trans->from; trans++)
+ if (trans->from == key)
+ return trans;
+
+ return NULL;
+}
+
+static unsigned int applespi_translate_fn_key(unsigned int key, int fn_pressed)
+{
+ const struct applespi_key_translation *trans;
+ int do_translate;
+
+ trans = applespi_find_translation(applespi_fn_codes, key);
+ if (trans) {
+ if (trans->flags & APPLE_FLAG_FKEY)
+ do_translate = (fnmode == 2 && fn_pressed) ||
+ (fnmode == 1 && !fn_pressed);
+ else
+ do_translate = fn_pressed;
+
+ if (do_translate)
+ key = trans->to;
+ }
+
+ return key;
+}
+
+static unsigned int applespi_translate_iso_layout(unsigned int key)
+{
+ const struct applespi_key_translation *trans;
+
+ trans = applespi_find_translation(apple_iso_keyboard, key);
+ if (trans)
+ key = trans->to;
+
+ return key;
+}
+
+static unsigned int applespi_code_to_key(u8 code, int fn_pressed)
+{
+ unsigned int key = applespi_scancodes[code];
+
+ if (fnmode)
+ key = applespi_translate_fn_key(key, fn_pressed);
+ if (iso_layout)
+ key = applespi_translate_iso_layout(key);
+ return key;
+}
+
+static void
+applespi_remap_fn_key(struct keyboard_protocol *keyboard_protocol)
+{
+ unsigned char tmp;
+ unsigned long *modifiers =
+ (unsigned long *)&keyboard_protocol->modifiers;
+
+ if (!fnremap || fnremap > ARRAY_SIZE(applespi_controlcodes) ||
+ !applespi_controlcodes[fnremap - 1])
+ return;
+
+ tmp = keyboard_protocol->fn_pressed;
+ keyboard_protocol->fn_pressed = test_bit(fnremap - 1, modifiers);
+ if (tmp)
+ __set_bit(fnremap - 1, modifiers);
+ else
+ __clear_bit(fnremap - 1, modifiers);
+}
+
+static void
+applespi_handle_keyboard_event(struct applespi_data *applespi,
+ struct keyboard_protocol *keyboard_protocol)
+{
+ int i, j;
+ unsigned int key;
+ bool still_pressed;
+ bool is_overflow;
+
+ /* check for rollover overflow, which is signalled by all keys == 1 */
+ is_overflow = true;
+
+ for (i = 0; i < MAX_ROLLOVER; i++) {
+ if (keyboard_protocol->keys_pressed[i] != 1) {
+ is_overflow = false;
+ break;
+ }
+ }
+
+ if (is_overflow)
+ return;
+
+ /* remap fn key if desired */
+ applespi_remap_fn_key(keyboard_protocol);
+
+ /* check released keys */
+ for (i = 0; i < MAX_ROLLOVER; i++) {
+ still_pressed = false;
+ for (j = 0; j < MAX_ROLLOVER; j++) {
+ if (applespi->last_keys_pressed[i] ==
+ keyboard_protocol->keys_pressed[j]) {
+ still_pressed = true;
+ break;
+ }
+ }
+
+ if (still_pressed)
+ continue;
+
+ key = applespi_code_to_key(applespi->last_keys_pressed[i],
+ applespi->last_keys_fn_pressed[i]);
+ input_report_key(applespi->keyboard_input_dev, key, 0);
+ applespi->last_keys_fn_pressed[i] = 0;
+ }
+
+ /* check pressed keys */
+ for (i = 0; i < MAX_ROLLOVER; i++) {
+ if (keyboard_protocol->keys_pressed[i] <
+ ARRAY_SIZE(applespi_scancodes) &&
+ keyboard_protocol->keys_pressed[i] > 0) {
+ key = applespi_code_to_key(
+ keyboard_protocol->keys_pressed[i],
+ keyboard_protocol->fn_pressed);
+ input_report_key(applespi->keyboard_input_dev, key, 1);
+ applespi->last_keys_fn_pressed[i] =
+ keyboard_protocol->fn_pressed;
+ }
+ }
+
+ /* check control keys */
+ for (i = 0; i < MAX_MODIFIERS; i++) {
+ u8 *modifiers = &keyboard_protocol->modifiers;
+
+ if (test_bit(i, (unsigned long *)modifiers))
+ input_report_key(applespi->keyboard_input_dev,
+ applespi_controlcodes[i], 1);
+ else
+ input_report_key(applespi->keyboard_input_dev,
+ applespi_controlcodes[i], 0);
+ }
+
+ /* check function key */
+ if (keyboard_protocol->fn_pressed && !applespi->last_fn_pressed)
+ input_report_key(applespi->keyboard_input_dev, KEY_FN, 1);
+ else if (!keyboard_protocol->fn_pressed && applespi->last_fn_pressed)
+ input_report_key(applespi->keyboard_input_dev, KEY_FN, 0);
+ applespi->last_fn_pressed = keyboard_protocol->fn_pressed;
+
+ /* done */
+ input_sync(applespi->keyboard_input_dev);
+ memcpy(&applespi->last_keys_pressed, keyboard_protocol->keys_pressed,
+ sizeof(applespi->last_keys_pressed));
+}
+
+static const struct applespi_tp_info *applespi_find_touchpad_info(__u8 model)
+{
+ const struct applespi_tp_model_info *info;
+
+ for (info = applespi_tp_models; info->model; info++) {
+ if (info->model == model)
+ return &info->tp_info;
+ }
+
+ return NULL;
+}
+
+static int
+applespi_register_touchpad_device(struct applespi_data *applespi,
+ struct touchpad_info_protocol *rcvd_tp_info)
+{
+ const struct applespi_tp_info *tp_info;
+ struct input_dev *touchpad_input_dev;
+ int sts;
+
+ /* set up touchpad dimensions */
+ tp_info = applespi_find_touchpad_info(rcvd_tp_info->model_no);
+ if (!tp_info) {
+ dev_warn(DEV(applespi),
+ "Unknown touchpad model %x - falling back to MB8 touchpad\n",
+ rcvd_tp_info->model_no);
+ tp_info = &applespi_tp_models[0].tp_info;
+ }
+
+ applespi->tp_info = *tp_info;
+
+ if (touchpad_dimensions[0]) {
+ int x, y, w, h;
+
+ if (sscanf(touchpad_dimensions, "%dx%d+%u+%u", &x, &y, &w, &h)
+ == 4) {
+ dev_info(DEV(applespi),
+ "Overriding touchpad dimensions from module param\n");
+ applespi->tp_info.x_min = x;
+ applespi->tp_info.y_min = y;
+ applespi->tp_info.x_max = x + w;
+ applespi->tp_info.y_max = y + h;
+ } else {
+ dev_warn(DEV(applespi),
+ "Invalid touchpad dimensions '%s': must be in the form XxY+W+H\n",
+ touchpad_dimensions);
+ touchpad_dimensions[0] = '\0';
+ }
+ }
+ if (!touchpad_dimensions[0]) {
+ snprintf(touchpad_dimensions, sizeof(touchpad_dimensions),
+ "%dx%d+%u+%u",
+ applespi->tp_info.x_min,
+ applespi->tp_info.y_min,
+ applespi->tp_info.x_max - applespi->tp_info.x_min,
+ applespi->tp_info.y_max - applespi->tp_info.y_min);
+ }
+
+ /* create touchpad input device */
+ touchpad_input_dev = devm_input_allocate_device(DEV(applespi));
+ if (!touchpad_input_dev) {
+ dev_err(DEV(applespi),
+ "Failed to allocate touchpad input device\n");
+ return -ENOMEM;
+ }
+
+ touchpad_input_dev->name = "Apple SPI Touchpad";
+ touchpad_input_dev->phys = "applespi/input1";
+ touchpad_input_dev->dev.parent = DEV(applespi);
+ touchpad_input_dev->id.bustype = BUS_SPI;
+ touchpad_input_dev->id.vendor = SYNAPTICS_VENDOR_ID;
+ touchpad_input_dev->id.product =
+ rcvd_tp_info->model_no << 8 | rcvd_tp_info->model_flags;
+
+ /* basic properties */
+ input_set_capability(touchpad_input_dev, EV_REL, REL_X);
+ input_set_capability(touchpad_input_dev, EV_REL, REL_Y);
+
+ __set_bit(INPUT_PROP_POINTER, touchpad_input_dev->propbit);
+ __set_bit(INPUT_PROP_BUTTONPAD, touchpad_input_dev->propbit);
+
+ /* finger touch area */
+ input_set_abs_params(touchpad_input_dev, ABS_MT_TOUCH_MAJOR,
+ 0, 5000, 0, 0);
+ input_set_abs_params(touchpad_input_dev, ABS_MT_TOUCH_MINOR,
+ 0, 5000, 0, 0);
+
+ /* finger approach area */
+ input_set_abs_params(touchpad_input_dev, ABS_MT_WIDTH_MAJOR,
+ 0, 5000, 0, 0);
+ input_set_abs_params(touchpad_input_dev, ABS_MT_WIDTH_MINOR,
+ 0, 5000, 0, 0);
+
+ /* finger orientation */
+ input_set_abs_params(touchpad_input_dev, ABS_MT_ORIENTATION,
+ -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION,
+ 0, 0);
+
+ /* finger position */
+ input_set_abs_params(touchpad_input_dev, ABS_MT_POSITION_X,
+ applespi->tp_info.x_min, applespi->tp_info.x_max,
+ 0, 0);
+ input_set_abs_params(touchpad_input_dev, ABS_MT_POSITION_Y,
+ applespi->tp_info.y_min, applespi->tp_info.y_max,
+ 0, 0);
+
+ /* touchpad button */
+ input_set_capability(touchpad_input_dev, EV_KEY, BTN_LEFT);
+
+ /* multitouch */
+ input_mt_init_slots(touchpad_input_dev, MAX_FINGERS,
+ INPUT_MT_POINTER | INPUT_MT_DROP_UNUSED |
+ INPUT_MT_TRACK);
+
+ /* register input device */
+ sts = input_register_device(touchpad_input_dev);
+ if (sts) {
+ dev_err(DEV(applespi),
+ "Unable to register touchpad input device (%d)\n", sts);
+ return sts;
+ }
+
+ /* touchpad_input_dev is read async in spi callback */
+ smp_store_release(&applespi->touchpad_input_dev, touchpad_input_dev);
+
+ return 0;
+}
+
+static void applespi_worker(struct work_struct *work)
+{
+ struct applespi_data *applespi =
+ container_of(work, struct applespi_data, work);
+
+ applespi_register_touchpad_device(applespi, &applespi->rcvd_tp_info);
+}
+
+static void applespi_handle_cmd_response(struct applespi_data *applespi,
+ struct spi_packet *packet,
+ struct message *message)
+{
+ if (packet->device == PACKET_DEV_INFO &&
+ le16_to_cpu(message->type) == 0x1020) {
+ /*
+ * We're not allowed to sleep here, but registering an input
+ * device can sleep.
+ */
+ applespi->rcvd_tp_info = message->tp_info;
+ schedule_work(&applespi->work);
+ return;
+ }
+
+ if (le16_to_cpu(message->length) != 0x0000) {
+ dev_warn_ratelimited(DEV(applespi),
+ "Received unexpected write response: length=%x\n",
+ le16_to_cpu(message->length));
+ return;
+ }
+
+ if (packet->device == PACKET_DEV_TPAD &&
+ le16_to_cpu(message->type) == 0x0252 &&
+ le16_to_cpu(message->rsp_buf_len) == 0x0002)
+ dev_info(DEV(applespi), "modeswitch done.\n");
+}
+
+static bool applespi_verify_crc(struct applespi_data *applespi, u8 *buffer,
+ size_t buflen)
+{
+ u16 crc;
+
+ crc = crc16(0, buffer, buflen);
+ if (crc) {
+ dev_warn_ratelimited(DEV(applespi),
+ "Received corrupted packet (crc mismatch)\n");
+ debug_print_header(DBG_RD_CRC, applespi);
+ debug_print_buffer(DBG_RD_CRC, applespi, "read ", buffer,
+ buflen);
+
+ return false;
+ }
+
+ return true;
+}
+
+static void applespi_debug_print_read_packet(struct applespi_data *applespi,
+ struct spi_packet *packet)
+{
+ unsigned int dbg_mask;
+
+ if (packet->flags == PACKET_TYPE_READ &&
+ packet->device == PACKET_DEV_KEYB)
+ dbg_mask = DBG_RD_KEYB;
+ else if (packet->flags == PACKET_TYPE_READ &&
+ packet->device == PACKET_DEV_TPAD)
+ dbg_mask = DBG_RD_TPAD;
+ else if (packet->flags == PACKET_TYPE_WRITE)
+ dbg_mask = applespi->cmd_log_mask;
+ else
+ dbg_mask = DBG_RD_UNKN;
+
+ debug_print_header(dbg_mask, applespi);
+ debug_print_buffer(dbg_mask, applespi, "read ", applespi->rx_buffer,
+ APPLESPI_PACKET_SIZE);
+}
+
+static void applespi_got_data(struct applespi_data *applespi)
+{
+ struct spi_packet *packet;
+ struct message *message;
+ unsigned int msg_len;
+ unsigned int off;
+ unsigned int rem;
+ unsigned int len;
+
+ /* process packet header */
+ if (!applespi_verify_crc(applespi, applespi->rx_buffer,
+ APPLESPI_PACKET_SIZE)) {
+ unsigned long flags;
+
+ spin_lock_irqsave(&applespi->cmd_msg_lock, flags);
+
+ if (applespi->drain) {
+ applespi->read_active = false;
+ applespi->write_active = false;
+
+ wake_up_all(&applespi->drain_complete);
+ }
+
+ spin_unlock_irqrestore(&applespi->cmd_msg_lock, flags);
+
+ return;
+ }
+
+ packet = (struct spi_packet *)applespi->rx_buffer;
+
+ applespi_debug_print_read_packet(applespi, packet);
+
+ off = le16_to_cpu(packet->offset);
+ rem = le16_to_cpu(packet->remaining);
+ len = le16_to_cpu(packet->length);
+
+ if (len > sizeof(packet->data)) {
+ dev_warn_ratelimited(DEV(applespi),
+ "Received corrupted packet (invalid packet length %u)\n",
+ len);
+ goto msg_complete;
+ }
+
+ /* handle multi-packet messages */
+ if (rem > 0 || off > 0) {
+ if (off != applespi->saved_msg_len) {
+ dev_warn_ratelimited(DEV(applespi),
+ "Received unexpected offset (got %u, expected %u)\n",
+ off, applespi->saved_msg_len);
+ goto msg_complete;
+ }
+
+ if (off + rem > MAX_PKTS_PER_MSG * APPLESPI_PACKET_SIZE) {
+ dev_warn_ratelimited(DEV(applespi),
+ "Received message too large (size %u)\n",
+ off + rem);
+ goto msg_complete;
+ }
+
+ if (off + len > MAX_PKTS_PER_MSG * APPLESPI_PACKET_SIZE) {
+ dev_warn_ratelimited(DEV(applespi),
+ "Received message too large (size %u)\n",
+ off + len);
+ goto msg_complete;
+ }
+
+ memcpy(applespi->msg_buf + off, &packet->data, len);
+ applespi->saved_msg_len += len;
+
+ if (rem > 0)
+ return;
+
+ message = (struct message *)applespi->msg_buf;
+ msg_len = applespi->saved_msg_len;
+ } else {
+ message = (struct message *)&packet->data;
+ msg_len = len;
+ }
+
+ /* got complete message - verify */
+ if (!applespi_verify_crc(applespi, (u8 *)message, msg_len))
+ goto msg_complete;
+
+ if (le16_to_cpu(message->length) != msg_len - MSG_HEADER_SIZE - 2) {
+ dev_warn_ratelimited(DEV(applespi),
+ "Received corrupted packet (invalid message length %u - expected %u)\n",
+ le16_to_cpu(message->length),
+ msg_len - MSG_HEADER_SIZE - 2);
+ goto msg_complete;
+ }
+
+ /* handle message */
+ if (packet->flags == PACKET_TYPE_READ &&
+ packet->device == PACKET_DEV_KEYB) {
+ applespi_handle_keyboard_event(applespi, &message->keyboard);
+
+ } else if (packet->flags == PACKET_TYPE_READ &&
+ packet->device == PACKET_DEV_TPAD) {
+ struct touchpad_protocol *tp;
+ size_t tp_len;
+
+ tp = &message->touchpad;
+ tp_len = sizeof(*tp) +
+ tp->number_of_fingers * sizeof(tp->fingers[0]);
+
+ if (le16_to_cpu(message->length) + 2 != tp_len) {
+ dev_warn_ratelimited(DEV(applespi),
+ "Received corrupted packet (invalid message length %u - num-fingers %u, tp-len %zu)\n",
+ le16_to_cpu(message->length),
+ tp->number_of_fingers, tp_len);
+ goto msg_complete;
+ }
+
+ if (tp->number_of_fingers > MAX_FINGERS) {
+ dev_warn_ratelimited(DEV(applespi),
+ "Number of reported fingers (%u) exceeds max (%u))\n",
+ tp->number_of_fingers,
+ MAX_FINGERS);
+ tp->number_of_fingers = MAX_FINGERS;
+ }
+
+ report_tp_state(applespi, tp);
+
+ } else if (packet->flags == PACKET_TYPE_WRITE) {
+ applespi_handle_cmd_response(applespi, packet, message);
+ }
+
+msg_complete:
+ applespi->saved_msg_len = 0;
+
+ applespi_msg_complete(applespi, packet->flags == PACKET_TYPE_WRITE,
+ true);
+}
+
+static void applespi_async_read_complete(void *context)
+{
+ struct applespi_data *applespi = context;
+
+ if (applespi->rd_m.status < 0) {
+ dev_warn(DEV(applespi), "Error reading from device: %d\n",
+ applespi->rd_m.status);
+ /*
+ * We don't actually know if this was a pure read, or a response
+ * to a write. But this is a rare error condition that should
+ * never occur, so clearing both flags to avoid deadlock.
+ */
+ applespi_msg_complete(applespi, true, true);
+ } else {
+ applespi_got_data(applespi);
+ }
+
+ acpi_finish_gpe(NULL, applespi->gpe);
+}
+
+static u32 applespi_notify(acpi_handle gpe_device, u32 gpe, void *context)
+{
+ struct applespi_data *applespi = context;
+ int sts;
+ unsigned long flags;
+
+ debug_print_header(DBG_RD_IRQ, applespi);
+
+ spin_lock_irqsave(&applespi->cmd_msg_lock, flags);
+
+ if (!applespi->suspended) {
+ sts = applespi_async(applespi, &applespi->rd_m,
+ applespi_async_read_complete);
+ if (sts)
+ dev_warn(DEV(applespi),
+ "Error queueing async read to device: %d\n",
+ sts);
+ else
+ applespi->read_active = true;
+ }
+
+ spin_unlock_irqrestore(&applespi->cmd_msg_lock, flags);
+
+ return ACPI_INTERRUPT_HANDLED;
+}
+
+static int applespi_get_saved_bl_level(struct applespi_data *applespi)
+{
+ struct efivar_entry *efivar_entry;
+ u16 efi_data = 0;
+ unsigned long efi_data_len;
+ int sts;
+
+ efivar_entry = kmalloc(sizeof(*efivar_entry), GFP_KERNEL);
+ if (!efivar_entry)
+ return -ENOMEM;
+
+ memcpy(efivar_entry->var.VariableName, EFI_BL_LEVEL_NAME,
+ sizeof(EFI_BL_LEVEL_NAME));
+ efivar_entry->var.VendorGuid = EFI_BL_LEVEL_GUID;
+ efi_data_len = sizeof(efi_data);
+
+ sts = efivar_entry_get(efivar_entry, NULL, &efi_data_len, &efi_data);
+ if (sts && sts != -ENOENT)
+ dev_warn(DEV(applespi),
+ "Error getting backlight level from EFI vars: %d\n",
+ sts);
+
+ kfree(efivar_entry);
+
+ return sts ? sts : efi_data;
+}
+
+static void applespi_save_bl_level(struct applespi_data *applespi,
+ unsigned int level)
+{
+ efi_guid_t efi_guid;
+ u32 efi_attr;
+ unsigned long efi_data_len;
+ u16 efi_data;
+ int sts;
+
+ /* Save keyboard backlight level */
+ efi_guid = EFI_BL_LEVEL_GUID;
+ efi_data = (u16)level;
+ efi_data_len = sizeof(efi_data);
+ efi_attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_RUNTIME_ACCESS;
+
+ sts = efivar_entry_set_safe(EFI_BL_LEVEL_NAME, efi_guid, efi_attr, true,
+ efi_data_len, &efi_data);
+ if (sts)
+ dev_warn(DEV(applespi),
+ "Error saving backlight level to EFI vars: %d\n", sts);
+}
+
+static int applespi_probe(struct spi_device *spi)
+{
+ struct applespi_data *applespi;
+ acpi_status acpi_sts;
+ int sts, i;
+ unsigned long long gpe, usb_status;
+
+ /* check if the USB interface is present and enabled already */
+ acpi_sts = acpi_evaluate_integer(ACPI_HANDLE(&spi->dev), "UIST", NULL,
+ &usb_status);
+ if (ACPI_SUCCESS(acpi_sts) && usb_status) {
+ /* let the USB driver take over instead */
+ dev_info(&spi->dev, "USB interface already enabled\n");
+ return -ENODEV;
+ }
+
+ /* allocate driver data */
+ applespi = devm_kzalloc(&spi->dev, sizeof(*applespi), GFP_KERNEL);
+ if (!applespi)
+ return -ENOMEM;
+
+ applespi->spi = spi;
+ applespi->handle = ACPI_HANDLE(&spi->dev);
+
+ INIT_WORK(&applespi->work, applespi_worker);
+
+ /* store the driver data */
+ spi_set_drvdata(spi, applespi);
+
+ /* create our buffers */
+ applespi->tx_buffer = devm_kmalloc(&spi->dev, APPLESPI_PACKET_SIZE,
+ GFP_KERNEL);
+ applespi->tx_status = devm_kmalloc(&spi->dev, APPLESPI_STATUS_SIZE,
+ GFP_KERNEL);
+ applespi->rx_buffer = devm_kmalloc(&spi->dev, APPLESPI_PACKET_SIZE,
+ GFP_KERNEL);
+ applespi->msg_buf = devm_kmalloc_array(&spi->dev, MAX_PKTS_PER_MSG,
+ APPLESPI_PACKET_SIZE,
+ GFP_KERNEL);
+
+ if (!applespi->tx_buffer || !applespi->tx_status ||
+ !applespi->rx_buffer || !applespi->msg_buf)
+ return -ENOMEM;
+
+ /* set up our spi messages */
+ applespi_setup_read_txfrs(applespi);
+ applespi_setup_write_txfrs(applespi);
+
+ /* cache ACPI method handles */
+ if (ACPI_FAILURE(acpi_get_handle(applespi->handle, "SIEN",
+ &applespi->sien)) ||
+ ACPI_FAILURE(acpi_get_handle(applespi->handle, "SIST",
+ &applespi->sist))) {
+ dev_err(DEV(applespi),
+ "Failed to get required ACPI method handles\n");
+ return -ENODEV;
+ }
+
+ /* switch on the SPI interface */
+ sts = applespi_setup_spi(applespi);
+ if (sts)
+ return sts;
+
+ sts = applespi_enable_spi(applespi);
+ if (sts)
+ return sts;
+
+ /* setup the keyboard input dev */
+ applespi->keyboard_input_dev = devm_input_allocate_device(&spi->dev);
+
+ if (!applespi->keyboard_input_dev)
+ return -ENOMEM;
+
+ applespi->keyboard_input_dev->name = "Apple SPI Keyboard";
+ applespi->keyboard_input_dev->phys = "applespi/input0";
+ applespi->keyboard_input_dev->dev.parent = &spi->dev;
+ applespi->keyboard_input_dev->id.bustype = BUS_SPI;
+
+ applespi->keyboard_input_dev->evbit[0] =
+ BIT_MASK(EV_KEY) | BIT_MASK(EV_LED) | BIT_MASK(EV_REP);
+ applespi->keyboard_input_dev->ledbit[0] = BIT_MASK(LED_CAPSL);
+
+ input_set_drvdata(applespi->keyboard_input_dev, applespi);
+ applespi->keyboard_input_dev->event = applespi_event;
+
+ for (i = 0; i < ARRAY_SIZE(applespi_scancodes); i++)
+ if (applespi_scancodes[i])
+ input_set_capability(applespi->keyboard_input_dev,
+ EV_KEY, applespi_scancodes[i]);
+
+ for (i = 0; i < ARRAY_SIZE(applespi_controlcodes); i++)
+ if (applespi_controlcodes[i])
+ input_set_capability(applespi->keyboard_input_dev,
+ EV_KEY, applespi_controlcodes[i]);
+
+ for (i = 0; i < ARRAY_SIZE(applespi_fn_codes); i++)
+ if (applespi_fn_codes[i].to)
+ input_set_capability(applespi->keyboard_input_dev,
+ EV_KEY, applespi_fn_codes[i].to);
+
+ input_set_capability(applespi->keyboard_input_dev, EV_KEY, KEY_FN);
+
+ sts = input_register_device(applespi->keyboard_input_dev);
+ if (sts) {
+ dev_err(DEV(applespi),
+ "Unable to register keyboard input device (%d)\n", sts);
+ return -ENODEV;
+ }
+
+ /*
+ * The applespi device doesn't send interrupts normally (as is described
+ * in its DSDT), but rather seems to use ACPI GPEs.
+ */
+ acpi_sts = acpi_evaluate_integer(applespi->handle, "_GPE", NULL, &gpe);
+ if (ACPI_FAILURE(acpi_sts)) {
+ dev_err(DEV(applespi),
+ "Failed to obtain GPE for SPI slave device: %s\n",
+ acpi_format_exception(acpi_sts));
+ return -ENODEV;
+ }
+ applespi->gpe = (int)gpe;
+
+ acpi_sts = acpi_install_gpe_handler(NULL, applespi->gpe,
+ ACPI_GPE_LEVEL_TRIGGERED,
+ applespi_notify, applespi);
+ if (ACPI_FAILURE(acpi_sts)) {
+ dev_err(DEV(applespi),
+ "Failed to install GPE handler for GPE %d: %s\n",
+ applespi->gpe, acpi_format_exception(acpi_sts));
+ return -ENODEV;
+ }
+
+ applespi->suspended = false;
+
+ acpi_sts = acpi_enable_gpe(NULL, applespi->gpe);
+ if (ACPI_FAILURE(acpi_sts)) {
+ dev_err(DEV(applespi),
+ "Failed to enable GPE handler for GPE %d: %s\n",
+ applespi->gpe, acpi_format_exception(acpi_sts));
+ acpi_remove_gpe_handler(NULL, applespi->gpe, applespi_notify);
+ return -ENODEV;
+ }
+
+ /* trigger touchpad setup */
+ applespi_init(applespi, false);
+
+ /*
+ * By default this device is not enabled for wakeup; but USB keyboards
+ * generally are, so the expectation is that by default the keyboard
+ * will wake the system.
+ */
+ device_wakeup_enable(&spi->dev);
+
+ /* set up keyboard-backlight */
+ sts = applespi_get_saved_bl_level(applespi);
+ if (sts >= 0)
+ applespi_set_bl_level(&applespi->backlight_info, sts);
+
+ applespi->backlight_info.name = "spi::kbd_backlight";
+ applespi->backlight_info.default_trigger = "kbd-backlight";
+ applespi->backlight_info.brightness_set = applespi_set_bl_level;
+
+ sts = devm_led_classdev_register(&spi->dev, &applespi->backlight_info);
+ if (sts)
+ dev_warn(DEV(applespi),
+ "Unable to register keyboard backlight class dev (%d)\n",
+ sts);
+
+ return 0;
+}
+
+static void applespi_drain_writes(struct applespi_data *applespi)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&applespi->cmd_msg_lock, flags);
+
+ applespi->drain = true;
+ wait_event_lock_irq(applespi->drain_complete, !applespi->write_active,
+ applespi->cmd_msg_lock);
+
+ spin_unlock_irqrestore(&applespi->cmd_msg_lock, flags);
+}
+
+static void applespi_drain_reads(struct applespi_data *applespi)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&applespi->cmd_msg_lock, flags);
+
+ wait_event_lock_irq(applespi->drain_complete, !applespi->read_active,
+ applespi->cmd_msg_lock);
+
+ applespi->suspended = true;
+
+ spin_unlock_irqrestore(&applespi->cmd_msg_lock, flags);
+}
+
+static int applespi_remove(struct spi_device *spi)
+{
+ struct applespi_data *applespi = spi_get_drvdata(spi);
+
+ applespi_drain_writes(applespi);
+
+ acpi_disable_gpe(NULL, applespi->gpe);
+ acpi_remove_gpe_handler(NULL, applespi->gpe, applespi_notify);
+ device_wakeup_disable(&spi->dev);
+
+ applespi_drain_reads(applespi);
+
+ return 0;
+}
+
+static void applespi_shutdown(struct spi_device *spi)
+{
+ struct applespi_data *applespi = spi_get_drvdata(spi);
+
+ applespi_save_bl_level(applespi, applespi->have_bl_level);
+}
+
+static int applespi_poweroff_late(struct device *dev)
+{
+ struct spi_device *spi = to_spi_device(dev);
+ struct applespi_data *applespi = spi_get_drvdata(spi);
+
+ applespi_save_bl_level(applespi, applespi->have_bl_level);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int applespi_suspend(struct device *dev)
+{
+ struct spi_device *spi = to_spi_device(dev);
+ struct applespi_data *applespi = spi_get_drvdata(spi);
+ acpi_status acpi_sts;
+ int sts;
+
+ /* turn off caps-lock - it'll stay on otherwise */
+ sts = applespi_set_capsl_led(applespi, false);
+ if (sts)
+ dev_warn(DEV(applespi),
+ "Failed to turn off caps-lock led (%d)\n", sts);
+
+ applespi_drain_writes(applespi);
+
+ /* disable the interrupt */
+ acpi_sts = acpi_disable_gpe(NULL, applespi->gpe);
+ if (ACPI_FAILURE(acpi_sts))
+ dev_err(DEV(applespi),
+ "Failed to disable GPE handler for GPE %d: %s\n",
+ applespi->gpe, acpi_format_exception(acpi_sts));
+
+ applespi_drain_reads(applespi);
+
+ return 0;
+}
+
+static int applespi_resume(struct device *dev)
+{
+ struct spi_device *spi = to_spi_device(dev);
+ struct applespi_data *applespi = spi_get_drvdata(spi);
+ acpi_status acpi_sts;
+ unsigned long flags;
+
+ /* ensure our flags and state reflect a newly resumed device */
+ spin_lock_irqsave(&applespi->cmd_msg_lock, flags);
+
+ applespi->drain = false;
+ applespi->have_cl_led_on = false;
+ applespi->have_bl_level = 0;
+ applespi->cmd_msg_queued = false;
+ applespi->read_active = false;
+ applespi->write_active = false;
+
+ applespi->suspended = false;
+
+ spin_unlock_irqrestore(&applespi->cmd_msg_lock, flags);
+
+ /* switch on the SPI interface */
+ applespi_enable_spi(applespi);
+
+ /* re-enable the interrupt */
+ acpi_sts = acpi_enable_gpe(NULL, applespi->gpe);
+ if (ACPI_FAILURE(acpi_sts))
+ dev_err(DEV(applespi),
+ "Failed to re-enable GPE handler for GPE %d: %s\n",
+ applespi->gpe, acpi_format_exception(acpi_sts));
+
+ /* switch the touchpad into multitouch mode */
+ applespi_init(applespi, true);
+
+ return 0;
+}
+#endif
+
+static const struct acpi_device_id applespi_acpi_match[] = {
+ { "APP000D", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(acpi, applespi_acpi_match);
+
+const struct dev_pm_ops applespi_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(applespi_suspend, applespi_resume)
+ .poweroff_late = applespi_poweroff_late,
+};
+
+static struct spi_driver applespi_driver = {
+ .driver = {
+ .name = "applespi",
+ .acpi_match_table = applespi_acpi_match,
+ .pm = &applespi_pm_ops,
+ },
+ .probe = applespi_probe,
+ .remove = applespi_remove,
+ .shutdown = applespi_shutdown,
+};
+
+module_spi_driver(applespi_driver)
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("MacBook(Pro) SPI Keyboard/Touchpad driver");
+MODULE_AUTHOR("Federico Lorenzi");
+MODULE_AUTHOR("Ronald Tschalär");
--
2.20.1
^ permalink raw reply related
* Re: [PATCH] Input: uinput - Allow uinput_request to be interrupted
From: Marcos Paulo de Souza @ 2019-02-21 11:11 UTC (permalink / raw)
To: Dmitry Torokhov, Rodrigo Rivas Costa
Cc: linux-kernel, Peter Hutterer, Paul E. McKenney, Martin Kepplinger,
open list:INPUT (KEYBOARD, MOUSE, JOYSTICK, TOUCHSCREEN)
In-Reply-To: <20190218201544.GA192977@dtor-ws>
Hi Dmitry,
On 2/18/19 5:15 PM, Dmitry Torokhov wrote:
> On Mon, Feb 18, 2019 at 03:21:10PM +0100, Rodrigo Rivas Costa wrote:
>> On Sun, Feb 17, 2019 at 09:42:52PM -0300, Marcos Paulo de Souza wrote:
>>> - if (!wait_for_completion_timeout(&request->done, 30 * HZ)) {
>>> + if (!wait_for_completion_interruptible_timeout(&request->done,
>>> + 30 * HZ)) {
>>> retval = -ETIMEDOUT;
>>> goto out;
>>> }
>> Now this function can succeed or fail because of ETIMEDOUT or an
>> interrupt. I think you should return -EINTR or maybe -ESYSRESTART if
>> interrupted.
> Rodrigo, you are right. Marcos, could you please send updated patch that
> returns different error code for timeout vs interrupt condition?
Sure. But now I found another issue: If we start fftest and press
Ctrl-C, it works (as Rodrigo and we all tested), but if we press -1
(Stopping effects), it gets stuck in the same old way. Now I'm running
lockdep and trying to fix this missing case (lockdep added bellow).
This lockdep warning is shown before the fftest can even allow the user
to choose between his available options or press -1.
>
> I dropped the patch for now.
>
> Thanks.
[ 11.528465] WARNING: possible circular locking dependency detected
[37/7926]
[ 11.530419] 5.0.0-rc7+ #5 Not tainted
[ 11.531368] ------------------------------------------------------
[ 11.533295] fftest/200 is trying to acquire lock:
[ 11.534713] 000000006528ddcb (&newdev->mutex){+.+.}, at:
uinput_request_submit+0x10a/0x320 [uinput]
[ 11.536939]
[ 11.536939] but task is already holding lock:
[ 11.538338] 000000004113875e (&ff->mutex){+.+.}, at:
input_ff_upload+0xa6/0x250
[ 11.540114]
[ 11.540114] which lock already depends on the new lock.
[ 11.540114]
[ 11.541966]
[ 11.541966] the existing dependency chain (in reverse order) is:
[ 11.543765]
[ 11.543765] -> #3 (&ff->mutex){+.+.}:
[ 11.544982] input_ff_flush+0x23/0x60
[ 11.545933] input_flush_device+0x3b/0x60
[ 11.546985] evdev_flush+0x54/0x60
[ 11.547974] filp_close+0x25/0x70
[ 11.548849] __x64_sys_close+0x19/0x40
[ 11.549838] do_syscall_64+0x4b/0x180
[ 11.550853] entry_SYSCALL_64_after_hwframe+0x49/0xbe
[ 11.552584]
[ 11.552584] -> #2 (&dev->mutex#2){+.+.}:
[ 11.554077] input_register_handle+0x25/0xc0
[ 11.555228] kbd_connect+0x44/0x90
[ 11.556141] input_attach_handler+0x73/0xb0
[ 11.557222] input_register_device+0x438/0x4b0
[ 11.558383] acpi_button_add+0x179/0x470
[ 11.559392] acpi_device_probe+0x43/0x110
[ 11.560432] really_probe+0x1c4/0x2d0
[ 11.561334] driver_probe_device+0x4a/0xe0
[ 11.562286] __driver_attach+0xb0/0xc0
[ 11.563165] bus_for_each_dev+0x74/0xc0
[ 11.564159] bus_add_driver+0x194/0x210
[ 11.565142] driver_register+0x56/0xe0
[ 11.566157] do_one_initcall+0x58/0x2ae
[ 11.567095] kernel_init_freeable+0x1ca/0x256
[ 11.568176] kernel_init+0x5/0x100
[ 11.569032] ret_from_fork+0x3a/0x50
[ 11.569898]
[ 11.569898] -> #1 (input_mutex){+.+.}:
[ 11.571027] input_register_device+0x3e6/0x4b0
[ 11.572116] uinput_ioctl_handler.isra.9+0x557/0x980 [uinput]
[ 11.573509] do_vfs_ioctl+0xa0/0x6e0
[ 11.574395] ksys_ioctl+0x6b/0x80
[ 11.575234] __x64_sys_ioctl+0x11/0x20
[ 11.576161] do_syscall_64+0x4b/0x180
[ 11.577085] entry_SYSCALL_64_after_hwframe+0x49/0xbe
[ 11.578281]
[ 11.578281] -> #0 (&newdev->mutex){+.+.}:
[ 11.579436] __mutex_lock+0x7d/0x9a0
[ 11.580381] uinput_request_submit+0x10a/0x320 [uinput]
[ 11.581590] uinput_dev_upload_effect+0x76/0xb0 [uinput]
[ 11.582893] input_ff_upload+0x1c0/0x250
[ 11.583853] evdev_ioctl_handler+0x388/0xbd0
[ 11.584926] do_vfs_ioctl+0xa0/0x6e0
[ 11.586208] ksys_ioctl+0x6b/0x80
[ 11.587292] __x64_sys_ioctl+0x11/0x20
[ 11.588254] do_syscall_64+0x4b/0x180
[ 11.589221] entry_SYSCALL_64_after_hwframe+0x49/0xbe
[ 11.590424]
[ 11.590424] other info that might help us debug this:
[ 11.590424]
[ 11.592162] Chain exists of:
[ 11.592162] &newdev->mutex --> &dev->mutex#2 --> &ff->mutex
[ 11.592162]
[ 11.594156] Possible unsafe locking scenario:
[ 11.594156]
[ 11.595456] CPU0 CPU1
[ 11.596452] ---- ----
[ 11.597377] lock(&ff->mutex);
[ 11.598004] lock(&dev->mutex#2);
[ 11.599163] lock(&ff->mutex);
[ 11.600282] lock(&newdev->mutex);
[ 11.600982]
[ 11.600982] *** DEADLOCK ***
[ 11.600982]
[ 11.602144] 2 locks held by fftest/200:
[ 11.602915] #0: 000000006ae3e58b (&evdev->mutex){+.+.}, at:
evdev_ioctl_handler+0x48/0xbd0
[ 11.604581] #1: 000000004113875e (&ff->mutex){+.+.}, at:
input_ff_upload+0xa6/0x250
[ 11.606110]
[ 11.606110] stack backtrace:
[ 11.606982] CPU: 0 PID: 200 Comm: fftest Not tainted 5.0.0-rc7+ #5
[ 11.608140] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996),
BIOS rel-1.11.0-0-g63451fc-prebuilt.qemu-project.org 04/01/2014
[ 11.610344] Call Trace:
[ 11.610827] dump_stack+0x67/0x9b
[ 11.611470] print_circular_bug.isra.35+0x1ce/0x1db
[ 11.612392] __lock_acquire+0x15e4/0x1650
[ 11.613188] ? _raw_spin_unlock_irq+0x24/0x30
[ 11.614045] ? lock_acquire+0xa7/0x1b0
[ 11.614793] lock_acquire+0xa7/0x1b0
[ 11.615489] ? uinput_request_submit+0x10a/0x320 [uinput]
[ 11.616526] ? uinput_request_submit+0x10a/0x320 [uinput]
[ 11.617562] __mutex_lock+0x7d/0x9a0
[ 11.618243] ? uinput_request_submit+0x10a/0x320 [uinput]
[ 11.619234] ? vprintk_emit+0xec/0x260
[ 11.620271] ? printk+0x4d/0x69
[ 11.621158] ? uinput_request_submit+0x10a/0x320 [uinput]
[ 11.622464] uinput_request_submit+0x10a/0x320 [uinput]
[ 11.623587] uinput_dev_upload_effect+0x76/0xb0 [uinput]
[ 11.624788] ? find_held_lock+0x2d/0x90
[ 11.625633] input_ff_upload+0x1c0/0x250
[ 11.626524] evdev_ioctl_handler+0x388/0xbd0
[ 11.627439] do_vfs_ioctl+0xa0/0x6e0
[ 11.628215] ksys_ioctl+0x6b/0x80
[ 11.628967] __x64_sys_ioctl+0x11/0x20
[ 11.629734] do_syscall_64+0x4b/0x180
[ 11.630483] entry_SYSCALL_64_after_hwframe+0x49/0xbe
[ 11.631508] RIP: 0033:0x7f2d99a76467
[ 11.632220] Code: b3 66 90 48 8b 05 31 4a 2c 00 64 c7 00 26 00 00 00
48 c7 c0 ff ff ff ff c3 66 2e 0f 1f 84 00 00 00 00 00 b8 10 00 00 00 0f
05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d 01 4a 2c 00 f7 d8 64 89 01 48
[ 11.635876] RSP: 002b:00007ffe1ab6fbd8 EFLAGS: 00000246 ORIG_RAX:
0000000000000010
[ 11.637355] RAX: ffffffffffffffda RBX: 00007ffe1ab6fc50 RCX:
00007f2d99a76467
[ 11.638766] RDX: 00007ffe1ab6fd10 RSI: 0000000040304580 RDI:
0000000000000003
[ 11.640177] RBP: 0000000000000003 R08: 00007f2d99d3d880 R09:
00007f2d99f47500
[ 11.641679] R10: 000055c75edf2140 R11: 0000000000000246 R12:
000055c75edf1a80
[ 11.643211] R13: 00007ffe1ab6feb0 R14: 0000000000000000 R15:
0000000000000000
>
^ permalink raw reply
* [PATCH] Input: evdev - use struct_size() in kzalloc() and vzalloc()
From: Gustavo A. R. Silva @ 2019-02-21 15:37 UTC (permalink / raw)
To: Dmitry Torokhov; +Cc: linux-input, linux-kernel, Gustavo A. R. Silva
One of the more common cases of allocation size calculations is finding
the size of a structure that has a zero-sized array at the end, along
with memory for some number of elements for that array. For example:
struct foo {
int stuff;
struct boo entry[];
};
size = sizeof(struct foo) + count * sizeof(struct boo);
instance = kzalloc(size, GFP_KERNEL);
Instead of leaving these open-coded and prone to type mistakes, we can
now use the new struct_size() helper:
instance = kzalloc(struct_size(instance, entry, count), GFP_KERNEL);
Notice that, in this case, variable size is not necessary, hence
it is removed.
This code was detected with the help of Coccinelle.
Signed-off-by: Gustavo A. R. Silva <gustavo@embeddedor.com>
---
drivers/input/evdev.c | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index f48369d6f3a0..ee8dd8b1b09e 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -503,14 +503,13 @@ static int evdev_open(struct inode *inode, struct file *file)
{
struct evdev *evdev = container_of(inode->i_cdev, struct evdev, cdev);
unsigned int bufsize = evdev_compute_buffer_size(evdev->handle.dev);
- unsigned int size = sizeof(struct evdev_client) +
- bufsize * sizeof(struct input_event);
struct evdev_client *client;
int error;
- client = kzalloc(size, GFP_KERNEL | __GFP_NOWARN);
+ client = kzalloc(struct_size(client, buffer, bufsize),
+ GFP_KERNEL | __GFP_NOWARN);
if (!client)
- client = vzalloc(size);
+ client = vzalloc(struct_size(client, buffer, bufsize));
if (!client)
return -ENOMEM;
--
2.20.1
^ permalink raw reply related
* Synaptics RMI4 - accessing /dev/v4l-touch0 breaks everything
From: Mantas Mikulėnas @ 2019-02-22 6:07 UTC (permalink / raw)
To: linux-input, linux-kernel
Hello,
I have a laptop with a Synaptics touchpad via RMI4/i2c-hid. I noticed
that it is also exposed as a "/dev/v4l-touch0" device
(/sys/devices/rmi4-00/rmi4-00.fn54/video4linux/v4l-touch0).
Because it has "v4l" in its name, I was stupid enough to run the `mpv`
video player on it. Now I have a dmesg full of errors, and don't have a
touchpad anymore (until rebooting).
Of course, I didn't really expect it to do anything useful, but somewhat
more concerning is that I got this kind of kernel messages instead:
"BUG: unable to handle kernel NULL pointer dereference"
"kernel tried to execute NX-protected page - exploit attempt? (uid: 0)"
"BUG: unable to handle kernel paging request"
"Fixing recursive fault but reboot is needed"
The full dmesg output generated by `mpv /dev/v4l-touch0` is:
---
[ 36.018308] BUG: unable to handle kernel NULL pointer dereference at
0000000000000000
[ 36.018313] PGD 0 P4D 0
[ 36.018316] Oops: 0010 [#1] PREEMPT SMP PTI
[ 36.018318] CPU: 2 PID: 509 Comm: irq/51-i2c_hid Not tainted
4.20.11-arch1-1-ARCH #1
[ 36.018319] Hardware name: Dell Inc. Inspiron 5547/06X5CY, BIOS A10
08/25/2016
[ 36.018321] RIP: 0010: (null)
[ 36.018324] Code: Bad RIP value.
[ 36.018325] RSP: 0000:ffffb9bd414dfe28 EFLAGS: 00010286
[ 36.018327] RAX: 0000000000000000 RBX: ffffffff86421e00 RCX:
0000000000000000
[ 36.018328] RDX: 0000000000000000 RSI: 0000000000000000 RDI:
0000000000000000
[ 36.018329] RBP: 0000000000000000 R08: ffff9a8d56802238 R09:
ffff9a8d56802260
[ 36.018330] R10: 0000000000000000 R11: ffffffff864507a8 R12:
ffff9a8d56d17c00
[ 36.018331] R13: ffff9a8d56d17ce4 R14: ffff9a8d51f69ee4 R15:
ffff9a8d43edbc80
[ 36.018332] FS: 0000000000000000(0000) GS:ffff9a8d57080000(0000)
knlGS:0000000000000000
[ 36.018333] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 36.018334] CR2: ffffffffffffffd6 CR3: 0000000205bb8004 CR4:
00000000001606e0
[ 36.018335] Call Trace:
[ 36.018340] ? handle_nested_irq+0xb3/0x110
[ 36.018347] ? rmi_process_interrupt_requests+0x7d/0x110 [rmi_core]
[ 36.018349] ? rmi_irq_fn+0x5f/0xe0 [rmi_core]
[ 36.018351] ? irq_forced_thread_fn+0x70/0x70
[ 36.018353] ? irq_thread_fn+0x1f/0x60
[ 36.018354] ? irq_thread+0xe7/0x160
[ 36.018355] ? wake_threads_waitq+0x30/0x30
[ 36.018357] ? irq_thread_dtor+0x80/0x80
[ 36.018359] ? kthread+0x112/0x130
[ 36.018361] ? kthread_park+0x80/0x80
[ 36.018364] ? ret_from_fork+0x1f/0x40
[ 36.018367] Modules linked in: fuse rfcomm nft_reject_inet
nf_reject_ipv4 nf_reject_ipv6 nft_reject nft_ct bnep btusb btrtl btbcm
btintel bluetooth rtsx_usb_ms nf_tables_set ecdh_generic nf_tables
joydev mousedev amdgpu arc4 hid_rmi rmi_core videobuf2_vmalloc
videobuf2_memops videobuf2_v4l2 videobuf2_common videodev
intel_spi_platform intel_spi spi_nor iTCO_wdt mtd iTCO_vendor_support
wmi_bmof dell_wmi iwlmvm sparse_keymap media mac80211
snd_hda_codec_realtek snd_hda_codec_hdmi snd_hda_codec_generic
dell_laptop intel_rapl snd_hda_intel dell_smbios x86_pkg_temp_thermal
intel_powerclamp iwlwifi coretemp snd_hda_codec dell_wmi_descriptor
kvm_intel dcdbas dell_smm_hwmon snd_hda_core intel_cstate input_leds
snd_hwdep intel_uncore snd_pcm chash amd_iommu_v2 psmouse
intel_rapl_perf cfg80211 pcspkr gpu_sched ttm snd_timer r8169 mei_me
realtek snd mei soundcore lpc_ich i2c_i801 wmi battery ac gpio_lynxpoint
i2c_hid dell_rbtn evdev rfkill mac_hid pcc_cpufreq tcp_lp cdc_acm pl2303
[ 36.018393] nf_conntrack_netlink nfnetlink nf_conntrack
nf_defrag_ipv6 nf_defrag_ipv4 libcrc32c rndis_host cdc_ether
ax88179_178a asix usbnet mii libphy tun sit tunnel4 ip_tunnel 8021q garp
mrp stp llc cifs ccm dns_resolver fscache nls_utf8 nls_iso8859_1
nls_cp437 vfat fat udf crc_itu_t isofs mspro_block ms_block memstick
mmc_block ums_cypress sr_mod cdrom uas usb_storage loop msr sg
crypto_user ip_tables x_tables ext4 crc32c_generic crc16 mbcache jbd2
fscrypto algif_skcipher af_alg rtsx_usb_sdmmc mmc_core rtsx_usb
hid_generic usbhid hid dm_crypt dm_mod sd_mod crct10dif_pclmul
crc32_pclmul crc32c_intel ghash_clmulni_intel serio_raw atkbd libps2
ahci libahci libata aesni_intel ehci_pci xhci_pci aes_x86_64 crypto_simd
cryptd glue_helper scsi_mod xhci_hcd ehci_hcd i8042 serio i915 kvmgt
vfio_mdev mdev vfio_iommu_type1 vfio kvm irqbypass intel_gtt
i2c_algo_bit drm_kms_helper syscopyarea sysfillrect sysimgblt
fb_sys_fops drm agpgart
[ 36.018433] CR2: 0000000000000000
[ 36.018435] ---[ end trace 5fe08f697d858ed0 ]---
[ 36.018436] RIP: 0010: (null)
[ 36.018438] Code: Bad RIP value.
[ 36.018439] RSP: 0000:ffffb9bd414dfe28 EFLAGS: 00010286
[ 36.018441] RAX: 0000000000000000 RBX: ffffffff86421e00 RCX:
0000000000000000
[ 36.018442] RDX: 0000000000000000 RSI: 0000000000000000 RDI:
0000000000000000
[ 36.018443] RBP: 0000000000000000 R08: ffff9a8d56802238 R09:
ffff9a8d56802260
[ 36.018444] R10: 0000000000000000 R11: ffffffff864507a8 R12:
ffff9a8d56d17c00
[ 36.018445] R13: ffff9a8d56d17ce4 R14: ffff9a8d51f69ee4 R15:
ffff9a8d43edbc80
[ 36.018446] FS: 0000000000000000(0000) GS:ffff9a8d57080000(0000)
knlGS:0000000000000000
[ 36.018447] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 36.018448] CR2: ffffffffffffffd6 CR3: 0000000205bb8004 CR4:
00000000001606e0
[ 36.018455] kernel tried to execute NX-protected page - exploit
attempt? (uid: 0)
[ 36.018456] BUG: unable to handle kernel paging request at
ffff9a8d43edbc01
[ 36.018457] PGD 22d801067 P4D 22d801067 PUD 22d805067 PMD 243f2d063
PTE 8000000243edb063
[ 36.018459] Oops: 0011 [#2] PREEMPT SMP PTI
[ 36.018461] CPU: 2 PID: 509 Comm: irq/51-i2c_hid Tainted: G D
4.20.11-arch1-1-ARCH #1
[ 36.018462] Hardware name: Dell Inc. Inspiron 5547/06X5CY, BIOS A10
08/25/2016
[ 36.018464] RIP: 0010:0xffff9a8d43edbc01
[ 36.018465] Code: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 <00> 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
[ 36.018466] RSP: 0000:ffffb9bd414dfea0 EFLAGS: 00010282
[ 36.018467] RAX: ffffb9bd414dfec8 RBX: ffff9a8d43edc400 RCX:
0000000000000000
[ 36.018468] RDX: ffff9a8d43edbc01 RSI: 0000000000000000 RDI:
ffffb9bd414dfec8
[ 36.018469] RBP: 0000000000000000 R08: 0000000000000000 R09:
0000000000000000
[ 36.018470] R10: ffffe28c8912ec00 R11: ffffffff86a50fcd R12:
ffff9a8d43edbc80
[ 36.018471] R13: ffffffff86a49f10 R14: 0000000000000000 R15:
ffff9a8d43edc434
[ 36.018472] FS: 0000000000000000(0000) GS:ffff9a8d57080000(0000)
knlGS:0000000000000000
[ 36.018473] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 36.018474] CR2: ffff9a8d43edbc01 CR3: 0000000205bb8004 CR4:
00000000001606e0
[ 36.018475] Call Trace:
[ 36.018477] ? task_work_run+0x8f/0xb0
[ 36.018481] ? do_exit+0x3a3/0xb60
[ 36.018483] ? irq_thread_dtor+0x80/0x80
[ 36.018485] ? kthread+0x112/0x130
[ 36.018488] ? rewind_stack_do_exit+0x17/0x20
[ 36.018490] Modules linked in: fuse rfcomm nft_reject_inet
nf_reject_ipv4 nf_reject_ipv6 nft_reject nft_ct bnep btusb btrtl btbcm
btintel bluetooth rtsx_usb_ms nf_tables_set ecdh_generic nf_tables
joydev mousedev amdgpu arc4 hid_rmi rmi_core videobuf2_vmalloc
videobuf2_memops videobuf2_v4l2 videobuf2_common videodev
intel_spi_platform intel_spi spi_nor iTCO_wdt mtd iTCO_vendor_support
wmi_bmof dell_wmi iwlmvm sparse_keymap media mac80211
snd_hda_codec_realtek snd_hda_codec_hdmi snd_hda_codec_generic
dell_laptop intel_rapl snd_hda_intel dell_smbios x86_pkg_temp_thermal
intel_powerclamp iwlwifi coretemp snd_hda_codec dell_wmi_descriptor
kvm_intel dcdbas dell_smm_hwmon snd_hda_core intel_cstate input_leds
snd_hwdep intel_uncore snd_pcm chash amd_iommu_v2 psmouse
intel_rapl_perf cfg80211 pcspkr gpu_sched ttm snd_timer r8169 mei_me
realtek snd mei soundcore lpc_ich i2c_i801 wmi battery ac gpio_lynxpoint
i2c_hid dell_rbtn evdev rfkill mac_hid pcc_cpufreq tcp_lp cdc_acm pl2303
[ 36.018508] nf_conntrack_netlink nfnetlink nf_conntrack
nf_defrag_ipv6 nf_defrag_ipv4 libcrc32c rndis_host cdc_ether
ax88179_178a asix usbnet mii libphy tun sit tunnel4 ip_tunnel 8021q garp
mrp stp llc cifs ccm dns_resolver fscache nls_utf8 nls_iso8859_1
nls_cp437 vfat fat udf crc_itu_t isofs mspro_block ms_block memstick
mmc_block ums_cypress sr_mod cdrom uas usb_storage loop msr sg
crypto_user ip_tables x_tables ext4 crc32c_generic crc16 mbcache jbd2
fscrypto algif_skcipher af_alg rtsx_usb_sdmmc mmc_core rtsx_usb
hid_generic usbhid hid dm_crypt dm_mod sd_mod crct10dif_pclmul
crc32_pclmul crc32c_intel ghash_clmulni_intel serio_raw atkbd libps2
ahci libahci libata aesni_intel ehci_pci xhci_pci aes_x86_64 crypto_simd
cryptd glue_helper scsi_mod xhci_hcd ehci_hcd i8042 serio i915 kvmgt
vfio_mdev mdev vfio_iommu_type1 vfio kvm irqbypass intel_gtt
i2c_algo_bit drm_kms_helper syscopyarea sysfillrect sysimgblt
fb_sys_fops drm agpgart
[ 36.018530] CR2: ffff9a8d43edbc01
[ 36.018531] ---[ end trace 5fe08f697d858ed1 ]---
[ 36.018532] RIP: 0010: (null)
[ 36.018534] Code: Bad RIP value.
[ 36.018535] RSP: 0000:ffffb9bd414dfe28 EFLAGS: 00010286
[ 36.018536] RAX: 0000000000000000 RBX: ffffffff86421e00 RCX:
0000000000000000
[ 36.018537] RDX: 0000000000000000 RSI: 0000000000000000 RDI:
0000000000000000
[ 36.018538] RBP: 0000000000000000 R08: ffff9a8d56802238 R09:
ffff9a8d56802260
[ 36.018539] R10: 0000000000000000 R11: ffffffff864507a8 R12:
ffff9a8d56d17c00
[ 36.018540] R13: ffff9a8d56d17ce4 R14: ffff9a8d51f69ee4 R15:
ffff9a8d43edbc80
[ 36.018541] FS: 0000000000000000(0000) GS:ffff9a8d57080000(0000)
knlGS:0000000000000000
[ 36.018542] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 36.018543] CR2: ffffffffffffffd6 CR3: 0000000205bb8004 CR4:
00000000001606e0
[ 36.018544] Fixing recursive fault but reboot is needed!
[ 37.015459] rmi4_f54 rmi4-00.fn54: Timed out
[ 37.042105] hid-rmi 0018:06CB:2934.0003: rmi_hid_read_block: timeout
elapsed
[ 38.058792] i2c_designware INT33C3:00: controller timed out
[ 38.085205] i2c_designware INT33C3:00: timeout in disabling adapter
[ 38.085216] i2c_hid i2c-DLL063E:00: failed to set a report to device.
[ 38.085221] hid-rmi 0018:06CB:2934.0003: failed to write hid report
(-110)
[ 38.085224] hid-rmi 0018:06CB:2934.0003: failed to write request
output report (-110)
[ 38.085229] rmi4_f54 rmi4-00.fn54: rmi_f54_work: read [722 bytes]
returned -110
---
--
Mantas Mikulėnas <grawity@gmail.com>
^ permalink raw reply
* Re: [PATCH v6 1/4] dt-bindings: input: touchscreen: goodix: Document regulator properties
From: Rob Herring @ 2019-02-22 16:43 UTC (permalink / raw)
Cc: Dmitry Torokhov, Bastien Nocera, Henrik Rydberg, linux-input,
linux-kernel, devicetree, Mark Rutland, linux-amarula,
Michael Trimarchi, Jagan Teki
In-Reply-To: <20190219101629.15977-2-jagan@amarulasolutions.com>
On Tue, 19 Feb 2019 15:46:26 +0530, Jagan Teki wrote:
> Goodix CTP controllers support analog, digital and gpio regulator
> supplies on relevant controller pin configurations.
>
> Out of which AVDD28 and VDDIO regulators are required in few goodix CTP
> chips during power-on sequence.
>
> AVDD22, DVDD12 regulators have no relevant functionality described from
> datasheet [1].
>
> So, document both AVDD28, VDDIO regulators into optional properties since
> few of the goodix chip do work without these regulator power-on sequence.
>
> [1] GT5663 Datasheet_English_20151106_Rev.01
>
> Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
> ---
> Documentation/devicetree/bindings/input/touchscreen/goodix.txt | 2 ++
> 1 file changed, 2 insertions(+)
>
Reviewed-by: Rob Herring <robh@kernel.org>
^ permalink raw reply
* Re: [PATCH 1/3] Input: lpc32xx-key - add clocks property and fix DT binding example
From: Rob Herring @ 2019-02-23 0:41 UTC (permalink / raw)
To: Vladimir Zapolskiy
Cc: linux-input, devicetree, Dmitry Torokhov, linux-arm-kernel,
Sylvain Lemieux
In-Reply-To: <20190126142921.16041-2-vz@mleia.com>
On Sat, 26 Jan 2019 16:29:19 +0200, Vladimir Zapolskiy wrote:
> The keypad controller on NXP LPC32xx requires its clock gate to be open,
> therefore add description of the requires 'clocks' property.
>
> In addition adjust the example by adding description of required 'clocks'
> property and by fixing 'interrupts' property.
>
> Signed-off-by: Vladimir Zapolskiy <vz@mleia.com>
> ---
> Documentation/devicetree/bindings/input/lpc32xx-key.txt | 5 ++++-
> 1 file changed, 4 insertions(+), 1 deletion(-)
>
Reviewed-by: Rob Herring <robh@kernel.org>
^ permalink raw reply
* Re: [PATCH 1/3] dt-bindings: input: sitronix-st1232: add compatible string for ST1633
From: Rob Herring @ 2019-02-23 0:43 UTC (permalink / raw)
To: Martin Kepplinger
Cc: devicetree, linux-input, dmitry.torokhov, robh+dt, mark.rutland,
linux-kernel, Martin Kepplinger
In-Reply-To: <20190128084449.16070-1-martink@posteo.de>
On Mon, 28 Jan 2019 09:44:47 +0100, Martin Kepplinger wrote:
> From: Martin Kepplinger <martin.kepplinger@ginzinger.com>
>
> The st1232 driver gains support for the ST1633 controller too; update
> the bindings doc accordingly.
>
> Signed-off-by: Martin Kepplinger <martin.kepplinger@ginzinger.com>
> ---
> .../bindings/input/touchscreen/sitronix-st1232.txt | 6 ++++--
> 1 file changed, 4 insertions(+), 2 deletions(-)
>
Reviewed-by: Rob Herring <robh@kernel.org>
^ permalink raw reply
* Re: [PATCH 1/3] Input: lpc32xx-key - add clocks property and fix DT binding example
From: Vladimir Zapolskiy @ 2019-02-23 11:38 UTC (permalink / raw)
To: Dmitry Torokhov
Cc: Rob Herring, devicetree, linux-input, linux-arm-kernel,
Sylvain Lemieux
In-Reply-To: <20190223004158.GA3951@bogus>
Hi Dmitry,
On 02/23/2019 02:41 AM, Rob Herring wrote:
> On Sat, 26 Jan 2019 16:29:19 +0200, Vladimir Zapolskiy wrote:
>> The keypad controller on NXP LPC32xx requires its clock gate to be open,
>> therefore add description of the requires 'clocks' property.
>>
>> In addition adjust the example by adding description of required 'clocks'
>> property and by fixing 'interrupts' property.
>>
>> Signed-off-by: Vladimir Zapolskiy <vz@mleia.com>
>> ---
>> Documentation/devicetree/bindings/input/lpc32xx-key.txt | 5 ++++-
>> 1 file changed, 4 insertions(+), 1 deletion(-)
>>
>
> Reviewed-by: Rob Herring <robh@kernel.org>
>
can you please pull this documentation change through Linux input branch?
The two other dts changes have been already included into arm-soc.
--
Best wishes,
Vladimir
^ permalink raw reply
* Re: [PATCH v2 2/2] Input: add Apple SPI keyboard and trackpad driver.
From: Life is hard, and then you die @ 2019-02-25 8:05 UTC (permalink / raw)
To: Dmitry Torokhov, Henrik Rydberg
Cc: Lukas Wunner, Federico Lorenzi, Andy Shevchenko, linux-input,
linux-kernel
In-Reply-To: <20190221105609.5710-3-ronald@innovation.ch>
On Thu, Feb 21, 2019 at 02:56:09AM -0800, Ronald Tschalär wrote:
> The keyboard and trackpad on recent MacBook's (since 8,1) and
> MacBookPro's (13,* and 14,*) are attached to an SPI controller instead
> of USB, as previously. The higher level protocol is not publicly
> documented and hence has been reverse engineered. As a consequence there
> are still a number of unknown fields and commands. However, the known
> parts have been working well and received extensive testing and use.
>
> In order for this driver to work, the proper SPI drivers need to be
> loaded too; for MB8,1 these are spi_pxa2xx_platform and spi_pxa2xx_pci;
> for all others they are spi_pxa2xx_platform and intel_lpss_pci. For this
> reason enabling this driver in the config implies enabling the above
> drivers.
>
> CC: Federico Lorenzi <federico@travelground.com>
> CC: Lukas Wunner <lukas@wunner.de>
> CC: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
> Link: https://bugzilla.kernel.org/show_bug.cgi?id=99891
> Link: https://bugzilla.kernel.org/show_bug.cgi?id=108331
> Signed-off-by: Ronald Tschalär <ronald@innovation.ch>
> ---
> drivers/input/keyboard/Kconfig | 14 +
> drivers/input/keyboard/Makefile | 1 +
> drivers/input/keyboard/applespi.c | 2003 +++++++++++++++++++++++++++++
> 3 files changed, 2018 insertions(+)
> create mode 100644 drivers/input/keyboard/applespi.c
[snip]
> diff --git a/drivers/input/keyboard/applespi.c b/drivers/input/keyboard/applespi.c
> new file mode 100644
> index 000000000000..2a8d1786011d
> --- /dev/null
> +++ b/drivers/input/keyboard/applespi.c
[snip]
> +/**
> + * This is a reduced version of print_hex_dump() that uses dev_printk().
> + */
> +static void dev_print_hex_dump(const char *level, const struct device *dev,
> + const char *prefix_str,
> + int rowsize, int groupsize,
> + const void *buf, size_t len, bool ascii)
> +{
> + const u8 *ptr = buf;
> + int i, linelen, remaining = len;
> + unsigned char linebuf[32 * 3 + 2 + 32 + 1];
> +
> + if (rowsize != 16 && rowsize != 32)
> + rowsize = 16;
> +
> + for (i = 0; i < len; i += rowsize) {
> + linelen = min(remaining, rowsize);
> + remaining -= rowsize;
> +
> + hex_dump_to_buffer(ptr + i, linelen, rowsize, groupsize,
> + linebuf, sizeof(linebuf), ascii);
> +
> + dev_printk(level, dev, "%s%s\n", prefix_str, linebuf);
> + }
> +}
Apologies, I should've have fixed this before posting v2: I'll
introduce an additional patch to add this function to the core to
avoid duplication and because I presume this may be useful for others
too.
Cheers,
Ronald
^ permalink raw reply
* Re: [PATCH 1/2] dt-bindings: input: sitronix-st1232: document optional reset-gpios property
From: Rob Herring @ 2019-02-25 14:43 UTC (permalink / raw)
To: Martin Kepplinger
Cc: devicetree, linux-input, dmitry.torokhov, mark.rutland,
linux-kernel, Martin Kepplinger
In-Reply-To: <20190129102347.27754-1-martink@posteo.de>
On Tue, Jan 29, 2019 at 11:23:46AM +0100, Martin Kepplinger wrote:
> From: Martin Kepplinger <martin.kepplinger@ginzinger.com>
>
> The st1232 driver reads this via gpiod.
What a driver does is not relevant to the binding. This breaks
compatibility so you need to mention that and why this is okay.
Either you need to keep 'gpios' as deprecated or you can drop it if
there aren't any dts files using it.
>
> Signed-off-by: Martin Kepplinger <martin.kepplinger@ginzinger.com>
> ---
> .../devicetree/bindings/input/touchscreen/sitronix-st1232.txt | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/input/touchscreen/sitronix-st1232.txt b/Documentation/devicetree/bindings/input/touchscreen/sitronix-st1232.txt
> index e73e826e0f2a..365b32d30d4b 100644
> --- a/Documentation/devicetree/bindings/input/touchscreen/sitronix-st1232.txt
> +++ b/Documentation/devicetree/bindings/input/touchscreen/sitronix-st1232.txt
> @@ -8,7 +8,7 @@ Required properties:
> - interrupts: interrupt to which the chip is connected
>
> Optional properties:
> -- gpios: a phandle to the reset GPIO
> +- reset-gpios: a phandle to the reset GPIO
>
> Example:
>
> @@ -19,7 +19,7 @@ Example:
> compatible = "sitronix,st1232";
> reg = <0x55>;
> interrupts = <2 0>;
> - gpios = <&gpio1 166 0>;
> + reset-gpios = <&gpio1 166 0>;
> };
>
> /* ... */
> --
> 2.20.1
>
^ permalink raw reply
* Re: [PATCH v6 0/4] input: touchscreen: Add goodix GT5553 CTP support
From: Jagan Teki @ 2019-02-26 6:13 UTC (permalink / raw)
To: Dmitry Torokhov, Bastien Nocera, Rob Herring
Cc: Henrik Rydberg, linux-input, linux-kernel, devicetree,
Mark Rutland, linux-amarula, Michael Trimarchi
In-Reply-To: <20190219101629.15977-1-jagan@amarulasolutions.com>
Hi Dmitry,
On Tue, Feb 19, 2019 at 3:46 PM Jagan Teki <jagan@amarulasolutions.com> wrote:
>
> This is v6 patchset for supporting goodix GT5553 CTP. Here is the
> previous version[1]
>
> Changes for v5:
> - document bindings for required regulators, which are need during
> power-on sequence
> - enable, disable required regulators as described in power-on sequence
> using normal regulator calls
> - update the proper commi messages
> Changes for v4:
> - document AVDD22, DVDD12, VDDIO as optional properties
> - use regulator bulk calls, for get, enable and disable functionalities
> Changes for v4:
> - devm_add_action_or_reset for disabling regulator
> Changes for v3:
> - add cover-letter
> - s/ADVV28/AVDD28 on commit head
> - fix few typo
> Changes for v2:
> - Rename vcc-supply with AVDD28-supply
> - disable regulator in remove
> - fix to setup regulator in probe code
> - add chipdata
> - drop example node in dt-bindings
>
> [1] https://patchwork.kernel.org/cover/10816901/
>
> Jagan Teki (4):
> dt-bindings: input: touchscreen: goodix: Document regulator properties
> Input: goodix - Add regulators suppot
> dt-bindings: input: touchscreen: goodix: Add GT5663 compatible
> Input: goodix - Add GT5663 CTP support
>
> .../bindings/input/touchscreen/goodix.txt | 3 +
> drivers/input/touchscreen/goodix.c | 60 +++++++++++++++++++
> 2 files changed, 63 insertions(+)
Let me know if you have any further comments on regulator patch, fyi
Rob reviewed it already.
^ permalink raw reply
* Re: [PATCH 1/2] dt-bindings: input: sitronix-st1232: document optional reset-gpios property
From: Martin Kepplinger @ 2019-02-26 6:18 UTC (permalink / raw)
To: Rob Herring, Martin Kepplinger, dmitry.torokhov
Cc: devicetree, linux-input, mark.rutland, linux-kernel
In-Reply-To: <20190225144328.GA13518@bogus>
[-- Attachment #1: Type: text/plain, Size: 613 bytes --]
On 25.02.19 15:43, Rob Herring wrote:
> On Tue, Jan 29, 2019 at 11:23:46AM +0100, Martin Kepplinger wrote:
>> From: Martin Kepplinger <martin.kepplinger@ginzinger.com>
>>
>> The st1232 driver reads this via gpiod.
>
> What a driver does is not relevant to the binding. This breaks
> compatibility so you need to mention that and why this is okay.
>
> Either you need to keep 'gpios' as deprecated or you can drop it if
> there aren't any dts files using it.
>
Hi Rob,
The patch is outdated. Dmity took the driver-changes without breaking
the current DT bindings.
martin
[-- Attachment #2: smime.p7s --]
[-- Type: application/x-pkcs7-signature, Size: 3616 bytes --]
^ permalink raw reply
* Re: [PATCH v2 2/2] Input: add Apple SPI keyboard and trackpad driver.
From: Andy Shevchenko @ 2019-02-26 8:51 UTC (permalink / raw)
To: Life is hard, and then you die
Cc: Dmitry Torokhov, Henrik Rydberg, Lukas Wunner, Federico Lorenzi,
linux-input, linux-kernel
In-Reply-To: <20190225080529.GA26142@innovation.ch>
On Mon, Feb 25, 2019 at 12:05:29AM -0800, Life is hard, and then you die wrote:
>
> On Thu, Feb 21, 2019 at 02:56:09AM -0800, Ronald Tschalär wrote:
> > The keyboard and trackpad on recent MacBook's (since 8,1) and
> > MacBookPro's (13,* and 14,*) are attached to an SPI controller instead
> > of USB, as previously. The higher level protocol is not publicly
> > documented and hence has been reverse engineered. As a consequence there
> > are still a number of unknown fields and commands. However, the known
> > parts have been working well and received extensive testing and use.
> >
> > In order for this driver to work, the proper SPI drivers need to be
> > loaded too; for MB8,1 these are spi_pxa2xx_platform and spi_pxa2xx_pci;
> > for all others they are spi_pxa2xx_platform and intel_lpss_pci. For this
> > reason enabling this driver in the config implies enabling the above
> > drivers.
> > +/**
> > + * This is a reduced version of print_hex_dump() that uses dev_printk().
> > + */
...and this should follow kernel doc as stated by comment style.
> > +static void dev_print_hex_dump(const char *level, const struct device *dev,
> > + const char *prefix_str,
> > + int rowsize, int groupsize,
> > + const void *buf, size_t len, bool ascii)
> > +{
> > + const u8 *ptr = buf;
> > + int i, linelen, remaining = len;
> > + unsigned char linebuf[32 * 3 + 2 + 32 + 1];
> > +
> > + if (rowsize != 16 && rowsize != 32)
> > + rowsize = 16;
> > +
> > + for (i = 0; i < len; i += rowsize) {
> > + linelen = min(remaining, rowsize);
> > + remaining -= rowsize;
> > +
> > + hex_dump_to_buffer(ptr + i, linelen, rowsize, groupsize,
> > + linebuf, sizeof(linebuf), ascii);
> > +
> > + dev_printk(level, dev, "%s%s\n", prefix_str, linebuf);
> > + }
> > +}
>
> Apologies, I should've have fixed this before posting v2: I'll
> introduce an additional patch to add this function to the core to
> avoid duplication and because I presume this may be useful for others
> too.
Yes, makes sense.
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply
* Re: [PATCH v2 2/2] Input: add Apple SPI keyboard and trackpad driver.
From: Andy Shevchenko @ 2019-02-26 9:20 UTC (permalink / raw)
To: Ronald Tschalär
Cc: Dmitry Torokhov, Henrik Rydberg, Lukas Wunner, Federico Lorenzi,
linux-input, linux-kernel
In-Reply-To: <20190221105609.5710-3-ronald@innovation.ch>
On Thu, Feb 21, 2019 at 02:56:09AM -0800, Ronald Tschalär wrote:
> The keyboard and trackpad on recent MacBook's (since 8,1) and
> MacBookPro's (13,* and 14,*) are attached to an SPI controller instead
> of USB, as previously. The higher level protocol is not publicly
> documented and hence has been reverse engineered. As a consequence there
> are still a number of unknown fields and commands. However, the known
> parts have been working well and received extensive testing and use.
>
> In order for this driver to work, the proper SPI drivers need to be
> loaded too; for MB8,1 these are spi_pxa2xx_platform and spi_pxa2xx_pci;
> for all others they are spi_pxa2xx_platform and intel_lpss_pci. For this
> reason enabling this driver in the config implies enabling the above
> drivers.
> +config KEYBOARD_APPLESPI
> + tristate "Apple SPI keyboard and trackpad"
> + depends on ACPI && SPI && EFI
I would rather want to see separate line for SPI...
> + depends on X86 || COMPILE_TEST
...like here
depends on SPI
> + imply SPI_PXA2XX
> + imply SPI_PXA2XX_PCI
> + imply MFD_INTEL_LPSS_PCI
> + help
> + Say Y here if you are running Linux on any Apple MacBook8,1 or later,
> + or any MacBookPro13,* or MacBookPro14,*.
> +
> + To compile this driver as a module, choose M here: the
> + module will be called applespi.
/* Perhaps a comment here that this mimics struct drm_rect */
> +struct applespi_tp_info {
> + int x_min;
> + int y_min;
> + int x_max;
> + int y_max;
> +};
...see above
> +static inline bool applespi_check_write_status(struct applespi_data *applespi,
> + int sts)
> +{
> + static u8 status_ok[] = { 0xac, 0x27, 0x68, 0xd5 };
> +
> + if (sts < 0) {
> + dev_warn(DEV(applespi), "Error writing to device: %d\n", sts);
> + return false;
> + }
> +
> + if (memcmp(applespi->tx_status, status_ok, APPLESPI_STATUS_SIZE)) {
> + dev_warn(DEV(applespi), "Error writing to device: %*ph\n",
Hmm... DEV() is too generic name for custom macro. And frankly I don't think
it's good to have in the first place.
> + APPLESPI_STATUS_SIZE, applespi->tx_status);
> + return false;
> + }
> +
> + return true;
> +}
> +static void applespi_set_bl_level(struct led_classdev *led_cdev,
> + enum led_brightness value)
> +{
> + struct applespi_data *applespi =
> + container_of(led_cdev, struct applespi_data, backlight_info);
> + unsigned long flags;
> + int sts;
> +
> + spin_lock_irqsave(&applespi->cmd_msg_lock, flags);
> +
> + if (value == 0)
> + applespi->want_bl_level = value;
> + else
> + /*
> + * The backlight does not turn on till level 32, so we scale
> + * the range here so that from a user's perspective it turns
> + * on at 1.
> + */
> + applespi->want_bl_level =
> + ((value * KBD_BL_LEVEL_ADJ) / KBD_BL_LEVEL_SCALE +
> + KBD_BL_LEVEL_MIN);
Fir multi-line conditionals the style is
if () {
} else {
}
> +
> + sts = applespi_send_cmd_msg(applespi);
> +
> + spin_unlock_irqrestore(&applespi->cmd_msg_lock, flags);
> +}
> +static void
> +applespi_remap_fn_key(struct keyboard_protocol *keyboard_protocol)
> +{
> + unsigned char tmp;
> + unsigned long *modifiers =
> + (unsigned long *)&keyboard_protocol->modifiers;
I would leave it on one online despite checkpatch warning (also, instead of
(unsigned long *) the (void *) might be used as a small trick).
> +
> + if (!fnremap || fnremap > ARRAY_SIZE(applespi_controlcodes) ||
> + !applespi_controlcodes[fnremap - 1])
> + return;
> +
> + tmp = keyboard_protocol->fn_pressed;
> + keyboard_protocol->fn_pressed = test_bit(fnremap - 1, modifiers);
> + if (tmp)
> + __set_bit(fnremap - 1, modifiers);
> + else
> + __clear_bit(fnremap - 1, modifiers);
Oh, this is not good. modifiers should be really unsigned long bounary,
otherwise it is potential overflow.
Best to fix is to define them as unsigned long in the first place.
> +}
> + applespi->last_keys_fn_pressed[i]);
> + input_report_key(applespi->keyboard_input_dev, key, 0);
> + applespi->last_keys_fn_pressed[i] = 0;
> + }
> + for (i = 0; i < MAX_MODIFIERS; i++) {
> + u8 *modifiers = &keyboard_protocol->modifiers;
> +
> + if (test_bit(i, (unsigned long *)modifiers))
Oh, this is not good idea, see above.
> + if (touchpad_dimensions[0]) {
> + int x, y, w, h;
> +
> + if (sscanf(touchpad_dimensions, "%dx%d+%u+%u", &x, &y, &w, &h)
> + == 4) {
I would leave this on one line. Or use temporary variable
int ret;
ret = sscanf();
if (ret ...) {
> + dev_info(DEV(applespi),
> + "Overriding touchpad dimensions from module param\n");
> + applespi->tp_info.x_min = x;
> + applespi->tp_info.y_min = y;
> + applespi->tp_info.x_max = x + w;
> + applespi->tp_info.y_max = y + h;
> + } else {
> + dev_warn(DEV(applespi),
> + "Invalid touchpad dimensions '%s': must be in the form XxY+W+H\n",
> + touchpad_dimensions);
> + touchpad_dimensions[0] = '\0';
> + }
> + }
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply
* [PATCH] HID: quirks: use correct format chars in dbg_hid
From: Louis Taylor @ 2019-02-26 23:48 UTC (permalink / raw)
To: jikos
Cc: benjamin.tissoires, linux-input, linux-kernel, clang-built-linux,
ndesaulniers, Louis Taylor
When building with -Wformat, clang warns:
drivers/hid/hid-quirks.c:1075:27: warning: format specifies type
'unsigned short' but the argument has type '__u32' (aka 'unsigned int')
[-Wformat]
bl_entry->driver_data, bl_entry->vendor,
^~~~~~~~~~~~~~~~
./include/linux/hid.h:1170:48: note: expanded from macro 'dbg_hid'
printk(KERN_DEBUG "%s: " format, __FILE__, ##arg); \
~~~~~~ ^~~
drivers/hid/hid-quirks.c:1076:4: warning: format specifies type
'unsigned short' but the argument has type '__u32' (aka 'unsigned int')
[-Wformat]
bl_entry->product);
^~~~~~~~~~~~~~~~~
./include/linux/hid.h:1170:48: note: expanded from macro 'dbg_hid'
printk(KERN_DEBUG "%s: " format, __FILE__, ##arg); \
~~~~~~ ^~~
drivers/hid/hid-quirks.c:1242:12: warning: format specifies type
'unsigned short' but the argument has type '__u32' (aka 'unsigned int')
[-Wformat]
quirks, hdev->vendor, hdev->product);
^~~~~~~~~~~~
./include/linux/hid.h:1170:48: note: expanded from macro 'dbg_hid'
printk(KERN_DEBUG "%s: " format, __FILE__, ##arg); \
~~~~~~ ^~~
drivers/hid/hid-quirks.c:1242:26: warning: format specifies type
'unsigned short' but the argument has type '__u32' (aka 'unsigned int')
[-Wformat]
quirks, hdev->vendor, hdev->product);
^~~~~~~~~~~~~
./include/linux/hid.h:1170:48: note: expanded from macro 'dbg_hid'
printk(KERN_DEBUG "%s: " format, __FILE__, ##arg); \
~~~~~~ ^~~
4 warnings generated.
This patch fixes the format strings to use the correct format type for unsigned
ints.
Link: https://github.com/ClangBuiltLinux/linux/issues/378
Signed-off-by: Louis Taylor <louis@kragniz.eu>
---
drivers/hid/hid-quirks.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c
index 94088c0ed68a..b4e49e1b6f4a 100644
--- a/drivers/hid/hid-quirks.c
+++ b/drivers/hid/hid-quirks.c
@@ -1071,7 +1071,7 @@ static struct hid_device_id *hid_exists_dquirk(const struct hid_device *hdev)
}
if (bl_entry != NULL)
- dbg_hid("Found dynamic quirk 0x%lx for HID device 0x%hx:0x%hx\n",
+ dbg_hid("Found dynamic quirk 0x%lx for HID device 0x%x:0x%x\n",
bl_entry->driver_data, bl_entry->vendor,
bl_entry->product);
@@ -1238,7 +1238,7 @@ static unsigned long hid_gets_squirk(const struct hid_device *hdev)
quirks |= bl_entry->driver_data;
if (quirks)
- dbg_hid("Found squirk 0x%lx for HID device 0x%hx:0x%hx\n",
+ dbg_hid("Found squirk 0x%lx for HID device 0x%x:0x%x\n",
quirks, hdev->vendor, hdev->product);
return quirks;
}
--
2.20.1
^ permalink raw reply related
* Re: [PATCH] HID: quirks: use correct format chars in dbg_hid
From: Nick Desaulniers @ 2019-02-27 0:27 UTC (permalink / raw)
To: Louis Taylor
Cc: Jiri Kosina, benjamin.tissoires, linux-input, LKML,
clang-built-linux, Jon Flatley, Matthias Männich
In-Reply-To: <20190226234853.20441-1-louis@kragniz.eu>
On Tue, Feb 26, 2019 at 3:50 PM Louis Taylor <louis@kragniz.eu> wrote:
>
> When building with -Wformat, clang warns:
>
> drivers/hid/hid-quirks.c:1075:27: warning: format specifies type
> 'unsigned short' but the argument has type '__u32' (aka 'unsigned int')
> [-Wformat]
> bl_entry->driver_data, bl_entry->vendor,
> ^~~~~~~~~~~~~~~~
> ./include/linux/hid.h:1170:48: note: expanded from macro 'dbg_hid'
> printk(KERN_DEBUG "%s: " format, __FILE__, ##arg); \
> ~~~~~~ ^~~
> drivers/hid/hid-quirks.c:1076:4: warning: format specifies type
> 'unsigned short' but the argument has type '__u32' (aka 'unsigned int')
> [-Wformat]
> bl_entry->product);
> ^~~~~~~~~~~~~~~~~
> ./include/linux/hid.h:1170:48: note: expanded from macro 'dbg_hid'
> printk(KERN_DEBUG "%s: " format, __FILE__, ##arg); \
> ~~~~~~ ^~~
> drivers/hid/hid-quirks.c:1242:12: warning: format specifies type
> 'unsigned short' but the argument has type '__u32' (aka 'unsigned int')
> [-Wformat]
> quirks, hdev->vendor, hdev->product);
> ^~~~~~~~~~~~
> ./include/linux/hid.h:1170:48: note: expanded from macro 'dbg_hid'
> printk(KERN_DEBUG "%s: " format, __FILE__, ##arg); \
> ~~~~~~ ^~~
> drivers/hid/hid-quirks.c:1242:26: warning: format specifies type
> 'unsigned short' but the argument has type '__u32' (aka 'unsigned int')
> [-Wformat]
> quirks, hdev->vendor, hdev->product);
> ^~~~~~~~~~~~~
> ./include/linux/hid.h:1170:48: note: expanded from macro 'dbg_hid'
> printk(KERN_DEBUG "%s: " format, __FILE__, ##arg); \
> ~~~~~~ ^~~
> 4 warnings generated.
>
> This patch fixes the format strings to use the correct format type for unsigned
> ints.
>
> Link: https://github.com/ClangBuiltLinux/linux/issues/378
> Signed-off-by: Louis Taylor <louis@kragniz.eu>
> ---
> drivers/hid/hid-quirks.c | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c
> index 94088c0ed68a..b4e49e1b6f4a 100644
> --- a/drivers/hid/hid-quirks.c
> +++ b/drivers/hid/hid-quirks.c
> @@ -1071,7 +1071,7 @@ static struct hid_device_id *hid_exists_dquirk(const struct hid_device *hdev)
> }
>
> if (bl_entry != NULL)
> - dbg_hid("Found dynamic quirk 0x%lx for HID device 0x%hx:0x%hx\n",
> + dbg_hid("Found dynamic quirk 0x%lx for HID device 0x%x:0x%x\n",
%h is for short ints, include/linux/mod_devicetable.h declares struct
hid_device_id (bl_entry is an instance of struct hid_device_id)
unconditionally as:
147 struct hid_device_id {
...
150 __u32 vendor;
151 __u32 product;
...
153 };
yep; LGTM
Reviewed-by: Nick Desaulniers <ndesaulniers@google.com>
Thank you for the patch! There's 3 more of these in
drivers/hid/i2c-hid/i2c-hid-core.c if your looking to clean up some
more!
> bl_entry->driver_data, bl_entry->vendor,
> bl_entry->product);
>
> @@ -1238,7 +1238,7 @@ static unsigned long hid_gets_squirk(const struct hid_device *hdev)
> quirks |= bl_entry->driver_data;
>
> if (quirks)
> - dbg_hid("Found squirk 0x%lx for HID device 0x%hx:0x%hx\n",
> + dbg_hid("Found squirk 0x%lx for HID device 0x%x:0x%x\n",
> quirks, hdev->vendor, hdev->product);
> return quirks;
> }
> --
> 2.20.1
>
--
Thanks,
~Nick Desaulniers
^ permalink raw reply
* Re: [PATCH v2 2/2] Input: add Apple SPI keyboard and trackpad driver.
From: Life is hard, and then you die @ 2019-02-27 7:29 UTC (permalink / raw)
To: Andy Shevchenko
Cc: Dmitry Torokhov, Henrik Rydberg, Lukas Wunner, Federico Lorenzi,
linux-input, linux-kernel
In-Reply-To: <20190226092059.GV9224@smile.fi.intel.com>
On Tue, Feb 26, 2019 at 11:20:59AM +0200, Andy Shevchenko wrote:
> On Thu, Feb 21, 2019 at 02:56:09AM -0800, Ronald Tschalär wrote:
> > The keyboard and trackpad on recent MacBook's (since 8,1) and
> > MacBookPro's (13,* and 14,*) are attached to an SPI controller instead
> > of USB, as previously. The higher level protocol is not publicly
> > documented and hence has been reverse engineered. As a consequence there
> > are still a number of unknown fields and commands. However, the known
> > parts have been working well and received extensive testing and use.
> >
> > In order for this driver to work, the proper SPI drivers need to be
> > loaded too; for MB8,1 these are spi_pxa2xx_platform and spi_pxa2xx_pci;
> > for all others they are spi_pxa2xx_platform and intel_lpss_pci. For this
> > reason enabling this driver in the config implies enabling the above
> > drivers.
>
> > +config KEYBOARD_APPLESPI
> > + tristate "Apple SPI keyboard and trackpad"
>
> > + depends on ACPI && SPI && EFI
>
> I would rather want to see separate line for SPI...
>
> > + depends on X86 || COMPILE_TEST
>
> ...like here
>
> depends on SPI
Sure. Generally, what is the criteria/rule here for splitting
conjunctions into separate 'depends'?
[snip]
> + #define DEV(applespi) (&(applespi)->spi->dev)
[snip]
> > + if (memcmp(applespi->tx_status, status_ok, APPLESPI_STATUS_SIZE)) {
>
> > + dev_warn(DEV(applespi), "Error writing to device: %*ph\n",
>
> Hmm... DEV() is too generic name for custom macro. And frankly I don't think
> it's good to have in the first place.
Yeah, I've been having trouble coming up with a better (but still
succinct) name - CORE_DEV()? RAW_DEV()? DEV_OF()? However, because
this expression is used in many places throughout the driver (mostly,
but not only, for logging statements) I feel like it's good to factor
it out. But I'll defer to your .
[snip]
> > +static void
> > +applespi_remap_fn_key(struct keyboard_protocol *keyboard_protocol)
> > +{
> > + unsigned char tmp;
>
> > + unsigned long *modifiers =
> > + (unsigned long *)&keyboard_protocol->modifiers;
>
> I would leave it on one online despite checkpatch warning (also, instead of
> (unsigned long *) the (void *) might be used as a small trick).
>
> > +
> > + if (!fnremap || fnremap > ARRAY_SIZE(applespi_controlcodes) ||
> > + !applespi_controlcodes[fnremap - 1])
> > + return;
> > +
> > + tmp = keyboard_protocol->fn_pressed;
> > + keyboard_protocol->fn_pressed = test_bit(fnremap - 1, modifiers);
> > + if (tmp)
>
> > + __set_bit(fnremap - 1, modifiers);
> > + else
> > + __clear_bit(fnremap - 1, modifiers);
>
> Oh, this is not good. modifiers should be really unsigned long bounary,
> otherwise it is potential overflow.
>
> Best to fix is to define them as unsigned long in the first place.
Can't do that directly, because keyboard_protocol->modifiers is a
field in the data received from the device, i.e. defined by that
protocol. Instead I could make a copy of the modifiers and pass that
around separately (i.e. in addition to the keyboard_protocol struct).
However, the implied size assertions here would basically still apply:
MAX_MODIFIERS == sizeof(keyboard_protocol->modifiers) * 8
ARRAY_SIZE(applespi_controlcodes) == sizeof(keyboard_protocol->modifiers) * 8
(hmm, MAX_MODIFIERS is really redundant - getting rid of it...)
Would using compiletime_assert()'s be an acceptable alternate approach
here? It would serve to both document the size constraint and to
protect against overflow due to an error in some future edit. E.g.
applespi_remap_fn_key(struct keyboard_protocol *keyboard_protocol)
{
unsigned char tmp;
unsigned long *modifiers = (void *)&keyboard_protocol->modifiers;
+
+ compiletime_assert(ARRAY_SIZE(applespi_controlcodes) ==
+ sizeof_field(struct keyboard_protocol, modifiers) * 8,
+ "applespi_controlcodes has wrong number of entries");
if (!fnremap || fnremap > ARRAY_SIZE(applespi_controlcodes) ||
!applespi_controlcodes[fnremap - 1])
return;
tmp = keyboard_protocol->fn_pressed;
keyboard_protocol->fn_pressed = test_bit(fnremap - 1, modifiers);
if (tmp)
__set_bit(fnremap - 1, modifiers);
else
__clear_bit(fnremap - 1, modifiers);
}
> > +}
>
> > + applespi->last_keys_fn_pressed[i]);
> > + input_report_key(applespi->keyboard_input_dev, key, 0);
> > + applespi->last_keys_fn_pressed[i] = 0;
> > + }
>
> > + for (i = 0; i < MAX_MODIFIERS; i++) {
>
> > + u8 *modifiers = &keyboard_protocol->modifiers;
> > +
> > + if (test_bit(i, (unsigned long *)modifiers))
>
> Oh, this is not good idea, see above.
See above. (I presume duplicating the compiletime_assert() here isn't
necessary, if going that route?)
Cheers,
Ronald
^ permalink raw reply
* Re: [PATCH] HID: quirks: use correct format chars in dbg_hid
From: Benjamin Tissoires @ 2019-02-27 9:57 UTC (permalink / raw)
To: Louis Taylor
Cc: Jiri Kosina, open list:HID CORE LAYER, lkml, clang-built-linux,
ndesaulniers
In-Reply-To: <20190226234853.20441-1-louis@kragniz.eu>
On Wed, Feb 27, 2019 at 12:50 AM Louis Taylor <louis@kragniz.eu> wrote:
>
> When building with -Wformat, clang warns:
>
> drivers/hid/hid-quirks.c:1075:27: warning: format specifies type
> 'unsigned short' but the argument has type '__u32' (aka 'unsigned int')
> [-Wformat]
> bl_entry->driver_data, bl_entry->vendor,
> ^~~~~~~~~~~~~~~~
> ./include/linux/hid.h:1170:48: note: expanded from macro 'dbg_hid'
> printk(KERN_DEBUG "%s: " format, __FILE__, ##arg); \
> ~~~~~~ ^~~
> drivers/hid/hid-quirks.c:1076:4: warning: format specifies type
> 'unsigned short' but the argument has type '__u32' (aka 'unsigned int')
> [-Wformat]
> bl_entry->product);
> ^~~~~~~~~~~~~~~~~
> ./include/linux/hid.h:1170:48: note: expanded from macro 'dbg_hid'
> printk(KERN_DEBUG "%s: " format, __FILE__, ##arg); \
> ~~~~~~ ^~~
> drivers/hid/hid-quirks.c:1242:12: warning: format specifies type
> 'unsigned short' but the argument has type '__u32' (aka 'unsigned int')
> [-Wformat]
> quirks, hdev->vendor, hdev->product);
> ^~~~~~~~~~~~
> ./include/linux/hid.h:1170:48: note: expanded from macro 'dbg_hid'
> printk(KERN_DEBUG "%s: " format, __FILE__, ##arg); \
> ~~~~~~ ^~~
> drivers/hid/hid-quirks.c:1242:26: warning: format specifies type
> 'unsigned short' but the argument has type '__u32' (aka 'unsigned int')
> [-Wformat]
> quirks, hdev->vendor, hdev->product);
> ^~~~~~~~~~~~~
> ./include/linux/hid.h:1170:48: note: expanded from macro 'dbg_hid'
> printk(KERN_DEBUG "%s: " format, __FILE__, ##arg); \
> ~~~~~~ ^~~
> 4 warnings generated.
>
> This patch fixes the format strings to use the correct format type for unsigned
> ints.
>
> Link: https://github.com/ClangBuiltLinux/linux/issues/378
> Signed-off-by: Louis Taylor <louis@kragniz.eu>
> ---
> drivers/hid/hid-quirks.c | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c
> index 94088c0ed68a..b4e49e1b6f4a 100644
> --- a/drivers/hid/hid-quirks.c
> +++ b/drivers/hid/hid-quirks.c
> @@ -1071,7 +1071,7 @@ static struct hid_device_id *hid_exists_dquirk(const struct hid_device *hdev)
> }
>
> if (bl_entry != NULL)
> - dbg_hid("Found dynamic quirk 0x%lx for HID device 0x%hx:0x%hx\n",
> + dbg_hid("Found dynamic quirk 0x%lx for HID device 0x%x:0x%x\n",
Can you make it %04x instead?
The VID/PID are usually 4 hex chars, and without the '04' format,
you'll end up having a varying length result, which is not that nice.
Cheers,
Benjamin
> bl_entry->driver_data, bl_entry->vendor,
> bl_entry->product);
>
> @@ -1238,7 +1238,7 @@ static unsigned long hid_gets_squirk(const struct hid_device *hdev)
> quirks |= bl_entry->driver_data;
>
> if (quirks)
> - dbg_hid("Found squirk 0x%lx for HID device 0x%hx:0x%hx\n",
> + dbg_hid("Found squirk 0x%lx for HID device 0x%x:0x%x\n",
> quirks, hdev->vendor, hdev->product);
> return quirks;
> }
> --
> 2.20.1
>
^ permalink raw reply
* [PATCH v2] HID: quirks: use correct format chars in dbg_hid
From: Louis Taylor @ 2019-02-27 11:07 UTC (permalink / raw)
To: jikos
Cc: benjamin.tissoires, linux-input, linux-kernel, clang-built-linux,
ndesaulniers, Louis Taylor
In-Reply-To: <20190226234853.20441-1-louis@kragniz.eu>
When building with -Wformat, clang warns:
drivers/hid/hid-quirks.c:1075:27: warning: format specifies type
'unsigned short' but the argument has type '__u32' (aka 'unsigned int')
[-Wformat]
bl_entry->driver_data, bl_entry->vendor,
^~~~~~~~~~~~~~~~
./include/linux/hid.h:1170:48: note: expanded from macro 'dbg_hid'
printk(KERN_DEBUG "%s: " format, __FILE__, ##arg); \
~~~~~~ ^~~
drivers/hid/hid-quirks.c:1076:4: warning: format specifies type
'unsigned short' but the argument has type '__u32' (aka 'unsigned int')
[-Wformat]
bl_entry->product);
^~~~~~~~~~~~~~~~~
./include/linux/hid.h:1170:48: note: expanded from macro 'dbg_hid'
printk(KERN_DEBUG "%s: " format, __FILE__, ##arg); \
~~~~~~ ^~~
drivers/hid/hid-quirks.c:1242:12: warning: format specifies type
'unsigned short' but the argument has type '__u32' (aka 'unsigned int')
[-Wformat]
quirks, hdev->vendor, hdev->product);
^~~~~~~~~~~~
./include/linux/hid.h:1170:48: note: expanded from macro 'dbg_hid'
printk(KERN_DEBUG "%s: " format, __FILE__, ##arg); \
~~~~~~ ^~~
drivers/hid/hid-quirks.c:1242:26: warning: format specifies type
'unsigned short' but the argument has type '__u32' (aka 'unsigned int')
[-Wformat]
quirks, hdev->vendor, hdev->product);
^~~~~~~~~~~~~
./include/linux/hid.h:1170:48: note: expanded from macro 'dbg_hid'
printk(KERN_DEBUG "%s: " format, __FILE__, ##arg); \
~~~~~~ ^~~
4 warnings generated.
This patch fixes the format strings to use the correct format type for unsigned
ints.
Link: https://github.com/ClangBuiltLinux/linux/issues/378
Signed-off-by: Louis Taylor <louis@kragniz.eu>
---
v2: change format string to use %04x instead of %x
drivers/hid/hid-quirks.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c
index 94088c0ed68a..b608a57b7908 100644
--- a/drivers/hid/hid-quirks.c
+++ b/drivers/hid/hid-quirks.c
@@ -1071,7 +1071,7 @@ static struct hid_device_id *hid_exists_dquirk(const struct hid_device *hdev)
}
if (bl_entry != NULL)
- dbg_hid("Found dynamic quirk 0x%lx for HID device 0x%hx:0x%hx\n",
+ dbg_hid("Found dynamic quirk 0x%lx for HID device 0x%04x:0x%04x\n",
bl_entry->driver_data, bl_entry->vendor,
bl_entry->product);
@@ -1238,7 +1238,7 @@ static unsigned long hid_gets_squirk(const struct hid_device *hdev)
quirks |= bl_entry->driver_data;
if (quirks)
- dbg_hid("Found squirk 0x%lx for HID device 0x%hx:0x%hx\n",
+ dbg_hid("Found squirk 0x%lx for HID device 0x%04x:0x%04x\n",
quirks, hdev->vendor, hdev->product);
return quirks;
}
--
2.20.1
^ permalink raw reply related
* Re: [PATCH v2] HID: quirks: use correct format chars in dbg_hid
From: Nick Desaulniers @ 2019-02-27 19:42 UTC (permalink / raw)
To: Louis Taylor
Cc: Jiri Kosina, benjamin.tissoires, linux-input, LKML,
clang-built-linux
In-Reply-To: <20190227110720.27329-1-louis@kragniz.eu>
On Wed, Feb 27, 2019 at 3:08 AM Louis Taylor <louis@kragniz.eu> wrote:
>
> When building with -Wformat, clang warns:
>
> drivers/hid/hid-quirks.c:1075:27: warning: format specifies type
> 'unsigned short' but the argument has type '__u32' (aka 'unsigned int')
> [-Wformat]
> bl_entry->driver_data, bl_entry->vendor,
> ^~~~~~~~~~~~~~~~
> ./include/linux/hid.h:1170:48: note: expanded from macro 'dbg_hid'
> printk(KERN_DEBUG "%s: " format, __FILE__, ##arg); \
> ~~~~~~ ^~~
> drivers/hid/hid-quirks.c:1076:4: warning: format specifies type
> 'unsigned short' but the argument has type '__u32' (aka 'unsigned int')
> [-Wformat]
> bl_entry->product);
> ^~~~~~~~~~~~~~~~~
> ./include/linux/hid.h:1170:48: note: expanded from macro 'dbg_hid'
> printk(KERN_DEBUG "%s: " format, __FILE__, ##arg); \
> ~~~~~~ ^~~
> drivers/hid/hid-quirks.c:1242:12: warning: format specifies type
> 'unsigned short' but the argument has type '__u32' (aka 'unsigned int')
> [-Wformat]
> quirks, hdev->vendor, hdev->product);
> ^~~~~~~~~~~~
> ./include/linux/hid.h:1170:48: note: expanded from macro 'dbg_hid'
> printk(KERN_DEBUG "%s: " format, __FILE__, ##arg); \
> ~~~~~~ ^~~
> drivers/hid/hid-quirks.c:1242:26: warning: format specifies type
> 'unsigned short' but the argument has type '__u32' (aka 'unsigned int')
> [-Wformat]
> quirks, hdev->vendor, hdev->product);
> ^~~~~~~~~~~~~
> ./include/linux/hid.h:1170:48: note: expanded from macro 'dbg_hid'
> printk(KERN_DEBUG "%s: " format, __FILE__, ##arg); \
> ~~~~~~ ^~~
> 4 warnings generated.
>
> This patch fixes the format strings to use the correct format type for unsigned
> ints.
>
> Link: https://github.com/ClangBuiltLinux/linux/issues/378
> Signed-off-by: Louis Taylor <louis@kragniz.eu>
Thanks for following up on the feedback.
Reviewed-by: Nick Desaulniers <ndesaulniers@google.com>
> ---
>
> v2: change format string to use %04x instead of %x
>
> drivers/hid/hid-quirks.c | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c
> index 94088c0ed68a..b608a57b7908 100644
> --- a/drivers/hid/hid-quirks.c
> +++ b/drivers/hid/hid-quirks.c
> @@ -1071,7 +1071,7 @@ static struct hid_device_id *hid_exists_dquirk(const struct hid_device *hdev)
> }
>
> if (bl_entry != NULL)
> - dbg_hid("Found dynamic quirk 0x%lx for HID device 0x%hx:0x%hx\n",
> + dbg_hid("Found dynamic quirk 0x%lx for HID device 0x%04x:0x%04x\n",
> bl_entry->driver_data, bl_entry->vendor,
> bl_entry->product);
>
> @@ -1238,7 +1238,7 @@ static unsigned long hid_gets_squirk(const struct hid_device *hdev)
> quirks |= bl_entry->driver_data;
>
> if (quirks)
> - dbg_hid("Found squirk 0x%lx for HID device 0x%hx:0x%hx\n",
> + dbg_hid("Found squirk 0x%lx for HID device 0x%04x:0x%04x\n",
> quirks, hdev->vendor, hdev->product);
> return quirks;
> }
> --
> 2.20.1
>
--
Thanks,
~Nick Desaulniers
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox