* 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 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 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: 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 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/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 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: 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 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
* 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
* [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
* 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 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
* [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 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 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 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
* 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
* Re: [PATCH] HID: roccat: Mark expected switch fall-through
From: Stefan Achatz @ 2019-02-20 8:15 UTC (permalink / raw)
To: Jiri Kosina, Gustavo A. R. Silva
Cc: Stefan Achatz, Benjamin Tissoires, linux-input, linux-kernel,
Kees Cook
In-Reply-To: <nycvar.YFH.7.76.1902191415550.11598@cbobk.fhfr.pm>
Am Dienstag, den 19.02.2019, 14:16 +0100 schrieb Jiri Kosina:
> On Mon, 11 Feb 2019, Gustavo A. R. Silva wrote:
>
> > In preparation to enabling -Wimplicit-fallthrough, mark switch
> > cases where we are expecting to fall through.
> >
> > This patch fixes the following warning:
> >
> > drivers/hid/hid-roccat-kone.c: In function
> > ‘kone_keep_values_up_to_date’:
> > drivers/hid/hid-roccat-kone.c:784:20: warning: this statement may
> > fall through [-Wimplicit-fallthrough=]
> > kone->actual_dpi = kone->profiles[event->value - 1].
> > ~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> > startup_dpi;
> > ~~~~~~~~~~~
> > drivers/hid/hid-roccat-kone.c:786:2: note: here
> > case kone_mouse_event_osd_profile:
> > ^~~~
> >
> > Warning level 3 was used: -Wimplicit-fallthrough=3
> >
> > This patch is part of the ongoing efforts to enable
> > -Wimplicit-fallthrough.
> >
> > Signed-off-by: Gustavo A. R. Silva <gustavo@embeddedor.com>
> > ---
> > drivers/hid/hid-roccat-kone.c | 1 +
> > 1 file changed, 1 insertion(+)
> >
> > diff --git a/drivers/hid/hid-roccat-kone.c b/drivers/hid/hid-
> > roccat-kone.c
> > index bf4675a27396..c4dd6162c1d6 100644
> > --- a/drivers/hid/hid-roccat-kone.c
> > +++ b/drivers/hid/hid-roccat-kone.c
> > @@ -783,6 +783,7 @@ static void kone_keep_values_up_to_date(struct
> > kone_device *kone,
> > case kone_mouse_event_switch_profile:
> > kone->actual_dpi = kone->profiles[event->value -
> > 1].
> > startup_dpi;
> > + /* fall through */
> > case kone_mouse_event_osd_profile:
> > kone->actual_profile = event->value;
> > break;
>
> Stefan, could you please confirm that this is intended behavior?
>
> Thanks,
I already confirmed this 7 months ago but as I see only in a reply to
you.
Yes, this patch is correct.
Stefan
^ permalink raw reply
* Re: [PATCH (resend)] Input: uinput - Set name/phys to NULL before kfree().
From: Dmitry Torokhov @ 2019-02-19 18:58 UTC (permalink / raw)
To: Tetsuo Handa; +Cc: rydberg, syzbot, linux-input, linux-kernel, syzkaller-bugs
In-Reply-To: <722c14a1-78cd-14b6-59ef-ba0d6fc82cb1@i-love.sakura.ne.jp>
On Mon, Feb 18, 2019 at 07:10:23PM +0900, Tetsuo Handa wrote:
> Thank you for responding.
>
> On 2019/02/18 6:07, Dmitry Torokhov wrote:
> > The commit tries to send final uevent for objects for which "add" uevent
> > has been sent, but not "remove" event. However in uinput (and general
> > input case) we always take care of sending uevent at unregister, and do
> > not expect to have uevent sent out at the final "put" time.
>
> Then, we want to keep dev->name and dev->phys when calling "unregister" time.
>
> >
> > I believe the real fix is to have kobj->state_remove_uevent_sent be set
> > to true as soon as we enter kobject_uevent(kobj, KOBJ_REMOVE) so that
> > it is being set even if memory allocation fails. Doing anything else may
> > violate expectations of subsystem owning the kobject.
>
> If we want to keep dev->name and dev->phys when calling "unregister" time,
> we could do something like below. Does calling kobject_uevent(KOBJ_REMOVE)
> without dev->name and dev->phys (to some degree) help (compared to not
> triggering kobject_uevent(KOBJ_REMOVE) at all) ?
We are talking about handling pretty bad failure (I am not sure if these
allocations can fail in real life) so not getting KOBJ_REMOVE uevent is
not a big deal.
Thanks.
--
Dmitry
^ permalink raw reply
* Re: [PATCH] input : avoid too late kobject_uevent(KOBJ_REMOVE) call
From: Dmitry Torokhov @ 2019-02-19 18:55 UTC (permalink / raw)
To: Tetsuo Handa
Cc: rydberg, linux-input, linux-kernel, syzkaller-bugs, Kay Sievers,
syzbot
In-Reply-To: <1550484563-13217-1-git-send-email-penguin-kernel@I-love.SAKURA.ne.jp>
Hi Tetsuo,
On Mon, Feb 18, 2019 at 07:09:23PM +0900, Tetsuo Handa wrote:
> syzbot is hitting use-after-free bug in uinput module [1]. This is because
> kobject_uevent(KOBJ_REMOVE) is called again due to commit 0f4dafc0563c6c49
> ("Kobject: auto-cleanup on final unref") after memory allocation fault
> injection made kobject_uevent(KOBJ_REMOVE) from device_del() from
> input_unregister_device() fail, while uinput_destroy_device() is expecting
> that kobject_uevent(KOBJ_REMOVE) is not called after device_del() from
> input_unregister_device() completed.
>
> Fix this problem by pretending as if kobject_uevent(KOBJ_REMOVE) from
> device_del() from input_unregister_device() did not fail.
>
> [1] https://syzkaller.appspot.com/bug?id=8b17c134fe938bbddd75a45afaa9e68af43a362d
>
> Reported-by: syzbot <syzbot+f648cfb7e0b52bf7ae32@syzkaller.appspotmail.com>
> Analyzed-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
> Cc: Kay Sievers <kay@vrfy.org>
> Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
> ---
> drivers/input/input.c | 13 +++++++++++++
> 1 file changed, 13 insertions(+)
>
> diff --git a/drivers/input/input.c b/drivers/input/input.c
> index 3304aaaffe87..6df3c33ef3aa 100644
> --- a/drivers/input/input.c
> +++ b/drivers/input/input.c
> @@ -2032,6 +2032,19 @@ static void __input_unregister_device(struct input_dev *dev)
> mutex_unlock(&input_mutex);
>
> device_del(&dev->dev);
> + /*
> + * Regarding input subsystem, we always take care of sending uevent at
> + * "unregister" time, and we do not expect to have uevent sent out at
> + * the final "put" time. Therefore, if we failed to send uevent at
> + * "unregister" time (due to e.g. fault injection), complain it and
> + * do not allow the final "put" time to send the remove uevent again.
> + */
> + if (dev->dev.kobj.state_add_uevent_sent &&
> + !dev->dev.kobj.state_remove_uevent_sent) {
> + dev->dev.kobj.state_remove_uevent_sent = 1;
> + pr_warn("Failed to send remove uevent for %s\n",
> + dev_name(&dev->dev));
Input has no business reaching into kobj internals. This should be
solved in lib/kobject_uevent.c, not anywhere else.
Thanks.
--
Dmitry
^ permalink raw reply
* Re: [PATCH v4 5/9] platform/chrome: Add sysfs attributes
From: Enric Balletbo Serra @ 2019-02-19 16:04 UTC (permalink / raw)
To: Nick Crews
Cc: linux-kernel, Simon Glass, Dmitry Torokhov, Sebastian Reichel,
linux-input, Guenter Roeck, dlaurie, Duncan Laurie, Nick Crews,
Enric Balletbo i Serra, Benson Leung
In-Reply-To: <20190123183325.92946-6-ncrews@chromium.org>
Hi Nick,
Missatge de Nick Crews <ncrews@chromium.org> del dia dc., 23 de gen.
2019 a les 19:38:
>
> From: Duncan Laurie <dlaurie@google.com>
>
> Add some sample sysfs attributes for the Wilco EC that show how
> the mailbox interface works. "Legacy" attributes are those that
> existed in the EC before it was adapted to ChromeOS.
>
> > cat /sys/bus/platform/devices/GOOG000C\:00/version
> Label : 99.99.99
> SVN Revision : 738ed.99
> Model Number : 08;8
> Build Date : 08/30/18
>
Note that example is not correct with the new attributes.
> Signed-off-by: Duncan Laurie <dlaurie@google.com>
> Signed-off-by: Nick Crews <ncrews@chromium.org>
> ---
>
> Changes in v4:
> - Move "Add RTC driver" before "Add sysfs attributes" so that
> it could get accepted earlier, since it is less contentious
>
> Changes in v3:
> - explicitly define toplevel_groups from the start,
> so adding telem later makes sense
> - Break version attribute into individual attributes
> - rm unused WILCO_EC_ATTR_RW macro
> - Moved some #defines from legacy.h to legacy.c
>
> Changes in v2:
> - Remove license boiler plate
> - Remove "wilco_ec_sysfs -" docstring prefix
> - Fix accidental Makefile deletion
> - Add documentation for sysfs entries
> - Change "enable ? 0 : 1" to "!enable"
> - No longer override error code from sysfs_init()
> - Put attributes in the legacy file to begin with, don't move later
> - Remove duplicate error messages when init()ing sysfs
>
> .../ABI/testing/sysfs-platform-wilco-ec | 42 +++++++
> drivers/platform/chrome/wilco_ec/Makefile | 2 +-
> drivers/platform/chrome/wilco_ec/core.c | 12 ++
> drivers/platform/chrome/wilco_ec/legacy.c | 103 ++++++++++++++++++
> drivers/platform/chrome/wilco_ec/legacy.h | 79 ++++++++++++++
> drivers/platform/chrome/wilco_ec/sysfs.c | 79 ++++++++++++++
> include/linux/platform_data/wilco-ec.h | 14 +++
> 7 files changed, 330 insertions(+), 1 deletion(-)
> create mode 100644 Documentation/ABI/testing/sysfs-platform-wilco-ec
> create mode 100644 drivers/platform/chrome/wilco_ec/legacy.c
> create mode 100644 drivers/platform/chrome/wilco_ec/legacy.h
> create mode 100644 drivers/platform/chrome/wilco_ec/sysfs.c
>
> diff --git a/Documentation/ABI/testing/sysfs-platform-wilco-ec b/Documentation/ABI/testing/sysfs-platform-wilco-ec
> new file mode 100644
> index 000000000000..fd2400844470
> --- /dev/null
> +++ b/Documentation/ABI/testing/sysfs-platform-wilco-ec
> @@ -0,0 +1,42 @@
> +What: /sys/bus/platform/devices/GOOG000C\:00/version_label
> +Date: January 2019
> +KernelVersion: 4.19
> +Description:
> + Display Wilco Embedded Controller firmware version label.
> + Output will a version string be similar to the example below:
> + 95.00.06
> +
> +What: /sys/bus/platform/devices/GOOG000C\:00/version_svn_revision
nit: don't know why but svn always reminds me to subversion ... I see
that you always add the prefix version_, I assume this is to maintain
in some way the old directory structure but we cleaned a lot the
number of sysfs attributes, so makes sense always add the prefix
version_? On some cases looks weird to me. Why not just 'revision'
it's short an clear.
> +Date: January 2019
> +KernelVersion: 4.19
> +Description:
> + Display Wilco Embedded Controller SVN revision.
> + Output will a version string be similar to the example below:
> + 5960a.06
> +
> +What: /sys/bus/platform/devices/GOOG000C\:00/version_model_number
nit: model_number?
> +Date: January 2019
> +KernelVersion: 4.19
> +Description:
> + Display Wilco Embedded Controller model number.
> + Output will a version string be similar to the example below:
> + 08;8
Which format is this? DD/MM?
> +
> +What: /sys/bus/platform/devices/GOOG000C\:00/version_build_date
nit: build_date?
> +Date: January 2019
> +KernelVersion: 4.19
> +Description:
> + Display Wilco Embedded Controller firmware build date.
> + Output will a MM/DD/YY string.
> +
Should match with the above example
> +What: /sys/bus/platform/devices/GOOG000C\:00/stealth_mode
I guess that this should go on a separate patch for now, please.
> +Date: January 2019
> +KernelVersion: 4.19
> +Description:
> + Turn stealth_mode on or off on EC. Stealth mode means that the
> + various LEDs, the LCD backlight, and onboard speakers are turned
> + off and remain off even if activated from the off state.
> + External monitors connected to the system are not affected.
> + In addition Wireless devices are turned off.
> +
I understand correctly that's a power management feature? What's the
use case from userspace point of view?
> + Input should be parseable by kstrtobool().
> diff --git a/drivers/platform/chrome/wilco_ec/Makefile b/drivers/platform/chrome/wilco_ec/Makefile
> index 063e7fb4ea17..b4dadf8b1a07 100644
> --- a/drivers/platform/chrome/wilco_ec/Makefile
> +++ b/drivers/platform/chrome/wilco_ec/Makefile
> @@ -1,6 +1,6 @@
> # SPDX-License-Identifier: GPL-2.0
>
> -wilco_ec-objs := core.o mailbox.o
> +wilco_ec-objs := core.o mailbox.o sysfs.o legacy.o
> obj-$(CONFIG_WILCO_EC) += wilco_ec.o
> wilco_ec_debugfs-objs := debugfs.o
> obj-$(CONFIG_WILCO_EC_DEBUGFS) += wilco_ec_debugfs.o
> diff --git a/drivers/platform/chrome/wilco_ec/core.c b/drivers/platform/chrome/wilco_ec/core.c
> index 7cfb047e2c89..1a1cd8e59f3f 100644
> --- a/drivers/platform/chrome/wilco_ec/core.c
> +++ b/drivers/platform/chrome/wilco_ec/core.c
> @@ -101,6 +101,13 @@ static int wilco_ec_probe(struct platform_device *pdev)
> goto destroy_mec;
> }
>
> + /* Create sysfs attributes for userspace interaction */
> + ret = wilco_ec_sysfs_init(ec);
> + if (ret) {
> + dev_err(dev, "Failed to create sysfs attributes\n");
> + goto destroy_mec;
> + }
> +
> return 0;
>
> destroy_mec:
> @@ -110,6 +117,11 @@ static int wilco_ec_probe(struct platform_device *pdev)
>
> static int wilco_ec_remove(struct platform_device *pdev)
> {
> + struct wilco_ec_device *ec = platform_get_drvdata(pdev);
> +
> + /* Remove sysfs attributes */
> + wilco_ec_sysfs_remove(ec);
> +
> /* Teardown cros_ec interface */
> cros_ec_lpc_mec_destroy();
>
> diff --git a/drivers/platform/chrome/wilco_ec/legacy.c b/drivers/platform/chrome/wilco_ec/legacy.c
> new file mode 100644
> index 000000000000..f284088e70f4
> --- /dev/null
> +++ b/drivers/platform/chrome/wilco_ec/legacy.c
> @@ -0,0 +1,103 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Legacy (non-Chrome-specific) sysfs attributes for Wilco EC
> + *
> + * Copyright 2018 Google LLC
> + */
> +
> +#include <linux/ctype.h>
> +#include <linux/device.h>
> +#include <linux/platform_data/wilco-ec.h>
> +
> +#include "legacy.h"
> +
> +#define EC_COMMAND_EC_INFO 0x38
> +#define EC_INFO_SIZE 9
> +#define EC_COMMAND_STEALTH_MODE 0xfc
> +
> +#define VERSION_INDEX_LABEL 0
> +#define VERSION_INDEX_SVN_REVISION 1
> +#define VERSION_INDEX_MODEL_NUMBER 2
> +#define VERSION_INDEX_BUILD_DATE 3
> +
> +static ssize_t get_info(struct device *dev, char *buf, u8 index)
> +{
> + struct wilco_ec_device *ec = dev_get_drvdata(dev);
> + char result[EC_INFO_SIZE];
> + struct wilco_ec_message msg = {
> + .type = WILCO_EC_MSG_LEGACY,
> + .command = EC_COMMAND_EC_INFO,
> + .request_data = &index,
> + .request_size = sizeof(index),
> + .response_data = result,
> + .response_size = EC_INFO_SIZE,
> + };
> + int ret;
> +
> + ret = wilco_ec_mailbox(ec, &msg);
> + if (ret < 0)
> + return ret;
> + if (ret != EC_INFO_SIZE)
> + return -EBADMSG;
> +
> + return scnprintf(buf, PAGE_SIZE, "%s\n", result);
> +}
> +
> +ssize_t wilco_ec_version_label_show(struct device *dev,
> + struct device_attribute *attr,
> + char *buf)
> +{
> + return get_info(dev, buf, VERSION_INDEX_LABEL);
> +}
> +
> +ssize_t wilco_ec_version_svn_revision_show(struct device *dev,
> + struct device_attribute *attr,
> + char *buf)
> +{
> + return get_info(dev, buf, VERSION_INDEX_SVN_REVISION);
> +}
> +
> +ssize_t wilco_ec_version_model_number_show(struct device *dev,
> + struct device_attribute *attr,
> + char *buf)
> +{
> + return get_info(dev, buf, VERSION_INDEX_MODEL_NUMBER);
> +}
> +
> +ssize_t wilco_ec_version_build_date_show(struct device *dev,
> + struct device_attribute *attr,
> + char *buf)
> +{
> + return get_info(dev, buf, VERSION_INDEX_BUILD_DATE);
> +}
> +
> +ssize_t wilco_ec_stealth_mode_store(struct device *dev,
> + struct device_attribute *attr,
> + const char *buf, size_t count)
> +{
> + struct wilco_ec_device *ec = dev_get_drvdata(dev);
> + u8 param;
> + struct wilco_ec_message msg = {
> + .type = WILCO_EC_MSG_LEGACY,
> + .command = EC_COMMAND_STEALTH_MODE,
> + .request_data = ¶m,
> + .request_size = sizeof(param),
> + };
> + int ret;
> + bool enable;
> +
> + ret = kstrtobool(buf, &enable);
> + if (ret) {
> + dev_err(dev, "Unable to parse '%s' to bool", buf);
> + return ret;
> + }
> +
> + /* Invert input parameter, EC expects 0=on and 1=off */
> + param = !enable;
> +
> + ret = wilco_ec_mailbox(ec, &msg);
> + if (ret < 0)
> + return ret;
> +
> + return count;
> +}
> diff --git a/drivers/platform/chrome/wilco_ec/legacy.h b/drivers/platform/chrome/wilco_ec/legacy.h
> new file mode 100644
> index 000000000000..a7f51dec4ccb
> --- /dev/null
> +++ b/drivers/platform/chrome/wilco_ec/legacy.h
> @@ -0,0 +1,79 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Legacy (non-Chrome-specific) sysfs attributes for Wilco EC
> + *
> + * Copyright 2018 Google LLC
> + */
> +
> +#ifndef WILCO_EC_LEGACY_H
> +#define WILCO_EC_LEGACY_H
> +
> +#include <linux/device.h>
> +
> +/**
> + * wilco_ec_version_label_show() - Display Wilco EC version label
> + * @dev: The device underlying the struct wilco_ec_device
> + * @attr: The attribute being read from
> + * @buf: Output buffer to fill with the result
> + *
> + * Output will a version string be similar to the example below:
> + * 95.00.06
> + */
> +ssize_t wilco_ec_version_label_show(struct device *dev,
> + struct device_attribute *attr,
> + char *buf);
> +
> +/**
> + * wilco_ec_version_svn_revision_show() - Display Wilco EC SVN revision
> + * @dev: The device underlying the struct wilco_ec_device
> + * @attr: The attribute being read from
> + * @buf: Output buffer to fill with the result
> + *
> + * Output will a version string be similar to the example below:
> + * 5960a.06
> + */
> +ssize_t wilco_ec_version_svn_revision_show(struct device *dev,
> + struct device_attribute *attr,
> + char *buf);
> +
> +/**
> + * wilco_ec_version_model_number_show() - Display Wilco EC model number
> + * @dev: The device underlying the struct wilco_ec_device
> + * @attr: The attribute being read from
> + * @buf: Output buffer to fill with the result
> + *
> + * Output will a version string be similar to the example below:
> + * 08;8
> + */
> +ssize_t wilco_ec_version_model_number_show(struct device *dev,
> + struct device_attribute *attr,
> + char *buf);
> +
> +/**
> + * wilco_ec_version_build_date_show() - Display Wilco EC firmware build date
> + * @dev: The device underlying the struct wilco_ec_device
> + * @attr: The attribute being read from
> + * @buf: Output buffer to fill with the result
> + *
> + * Output will a MM/DD/YY string.
> + */
> +ssize_t wilco_ec_version_build_date_show(struct device *dev,
> + struct device_attribute *attr,
> + char *buf);
> +
> +
> +/**
> + * wilco_ec_stealth_mode_store() - Turn stealth_mode on or off on EC
> + * @dev: Device representing the EC
> + * @attr: The attribute in question
> + * @buf: Input buffer, should be parseable by kstrtobool(). Anything parsed to
> + * True means enable stealth mode (turn off screen, etc)
> + * @count: Number of bytes in input buffer
> + *
> + * Return: Number of bytes consumed from input, negative error code on failure
> + */
> +ssize_t wilco_ec_stealth_mode_store(struct device *dev,
> + struct device_attribute *attr,
> + const char *buf, size_t count);
> +
> +#endif /* WILCO_EC_LEGACY_H */
> diff --git a/drivers/platform/chrome/wilco_ec/sysfs.c b/drivers/platform/chrome/wilco_ec/sysfs.c
> new file mode 100644
> index 000000000000..a885026e5d24
> --- /dev/null
> +++ b/drivers/platform/chrome/wilco_ec/sysfs.c
> @@ -0,0 +1,79 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Sysfs attributes for Wilco Embedded Controller
> + *
> + * Copyright 2018 Google LLC
> + *
> + * The sysfs attributes appear under /sys/bus/platform/devices/GOOG000C\:00/
> + * To actually learn what each attribute does, read the corresponding _show() or
> + * _store() function source.
> + */
> +
> +#include <linux/ctype.h>
> +#include <linux/platform_data/wilco-ec.h>
> +#include <linux/platform_device.h>
> +#include <linux/sysfs.h>
> +
> +#include "legacy.h"
> +
> +#define WILCO_EC_ATTR_RO(_name) \
> +__ATTR(_name, 0444, wilco_ec_##_name##_show, NULL)
> +
This is only to add the wilco_ec_ prefix to the attributes, I'd prefer
you use the standard ATTR_ attibutes and just name the attributes
without the wilco_ec_ prefix.
> +#define WILCO_EC_ATTR_WO(_name) \
> +__ATTR(_name, 0200, NULL, wilco_ec_##_name##_store)
> +
ditto
> +/* Make top-level attributes, which will live inside GOOG000C:00/ */
> +static struct device_attribute stealth_attr = WILCO_EC_ATTR_WO(stealth_mode);
> +static struct device_attribute version_label_attr =
> + WILCO_EC_ATTR_RO(version_label);
> +static struct device_attribute version_svn_revision_attr =
> + WILCO_EC_ATTR_RO(version_svn_revision);
> +static struct device_attribute version_model_number_attr =
> + WILCO_EC_ATTR_RO(version_model_number);
> +static struct device_attribute version_build_date_attr =
> + WILCO_EC_ATTR_RO(version_build_date);
> +static struct attribute *wilco_ec_toplevel_attrs[] = {
> + &version_label_attr.attr,
> + &version_svn_revision_attr.attr,
> + &version_model_number_attr.attr,
> + &version_build_date_attr.attr,
> + &stealth_attr.attr,
> + NULL
> +};
> +static const struct attribute_group wilco_ec_toplevel_group = {
> + .attrs = wilco_ec_toplevel_attrs,
> +};
> +static const struct attribute_group *wilco_ec_toplevel_groups[] = {
> + &wilco_ec_toplevel_group,
> + NULL,
> +};
> +
> +/**
> + * wilco_ec_sysfs_init() - Initialize the sysfs directories and attributes
> + * @dev: The device representing the EC
> + *
> + * Creates the sysfs directory structure and populates it with all attributes.
> + * If there is a problem it will clean up the entire filesystem.
> + *
> + * Return 0 on success, -ENOMEM on failure creating directories or attibutes.
> + */
> +int wilco_ec_sysfs_init(struct wilco_ec_device *ec)
> +{
> + struct device *dev = ec->dev;
> + int ret;
> +
> + /* add the top-level attributes */
> + ret = sysfs_create_groups(&dev->kobj, wilco_ec_toplevel_groups);
> + if (ret)
> + return -ENOMEM;
> +
> + return 0;
> +}
> +
> +void wilco_ec_sysfs_remove(struct wilco_ec_device *ec)
> +{
> + struct device *dev = ec->dev;
> +
> + /* go upwards through the directory structure */
> + sysfs_remove_groups(&dev->kobj, wilco_ec_toplevel_groups);
> +}
> diff --git a/include/linux/platform_data/wilco-ec.h b/include/linux/platform_data/wilco-ec.h
> index 5477b8802f81..7c6ab6de7239 100644
> --- a/include/linux/platform_data/wilco-ec.h
> +++ b/include/linux/platform_data/wilco-ec.h
> @@ -135,4 +135,18 @@ struct wilco_ec_response {
> */
> int wilco_ec_mailbox(struct wilco_ec_device *ec, struct wilco_ec_message *msg);
>
> +/**
> + * wilco_ec_sysfs_init() - Create sysfs attributes.
> + * @ec: EC device.
> + *
> + * Return: 0 for success or negative error code on failure.
> + */
> +int wilco_ec_sysfs_init(struct wilco_ec_device *ec);
> +
> +/**
> + * wilco_ec_sysfs_remove() - Remove sysfs attributes.
> + * @ec: EC device.
> + */
> +void wilco_ec_sysfs_remove(struct wilco_ec_device *ec);
> +
> #endif /* WILCO_EC_H */
> --
> 2.20.1.321.g9e740568ce-goog
>
Regards,
Enric
^ permalink raw reply
* Re: [PATCH] HID: roccat: Mark expected switch fall-through
From: Jiri Kosina @ 2019-02-19 13:16 UTC (permalink / raw)
To: Gustavo A. R. Silva
Cc: Stefan Achatz, Benjamin Tissoires, linux-input, linux-kernel,
Kees Cook
In-Reply-To: <20190211215334.GA6216@embeddedor>
On Mon, 11 Feb 2019, Gustavo A. R. Silva wrote:
> In preparation to enabling -Wimplicit-fallthrough, mark switch
> cases where we are expecting to fall through.
>
> This patch fixes the following warning:
>
> drivers/hid/hid-roccat-kone.c: In function ‘kone_keep_values_up_to_date’:
> drivers/hid/hid-roccat-kone.c:784:20: warning: this statement may fall through [-Wimplicit-fallthrough=]
> kone->actual_dpi = kone->profiles[event->value - 1].
> ~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> startup_dpi;
> ~~~~~~~~~~~
> drivers/hid/hid-roccat-kone.c:786:2: note: here
> case kone_mouse_event_osd_profile:
> ^~~~
>
> Warning level 3 was used: -Wimplicit-fallthrough=3
>
> This patch is part of the ongoing efforts to enable
> -Wimplicit-fallthrough.
>
> Signed-off-by: Gustavo A. R. Silva <gustavo@embeddedor.com>
> ---
> drivers/hid/hid-roccat-kone.c | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/drivers/hid/hid-roccat-kone.c b/drivers/hid/hid-roccat-kone.c
> index bf4675a27396..c4dd6162c1d6 100644
> --- a/drivers/hid/hid-roccat-kone.c
> +++ b/drivers/hid/hid-roccat-kone.c
> @@ -783,6 +783,7 @@ static void kone_keep_values_up_to_date(struct kone_device *kone,
> case kone_mouse_event_switch_profile:
> kone->actual_dpi = kone->profiles[event->value - 1].
> startup_dpi;
> + /* fall through */
> case kone_mouse_event_osd_profile:
> kone->actual_profile = event->value;
> break;
Stefan, could you please confirm that this is intended behavior?
Thanks,
--
Jiri Kosina
SUSE Labs
^ permalink raw reply
* [PATCH v6 4/4] Input: goodix - Add GT5663 CTP support
From: Jagan Teki @ 2019-02-19 10:16 UTC (permalink / raw)
To: Dmitry Torokhov, Bastien Nocera, Rob Herring
Cc: Henrik Rydberg, linux-input, linux-kernel, devicetree,
Mark Rutland, linux-amarula, Michael Trimarchi, Jagan Teki
In-Reply-To: <20190219101629.15977-1-jagan@amarulasolutions.com>
GT5663 is capacitive touch controller with customized smart
wakeup gestures.
Add support for it by adding compatible and supported chip data.
The chip data on GT5663 is similar to GT1151, like
- config data register has 0x8050 address
- config data register max len is 240
- config data checksum has 16-bit
Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
---
drivers/input/touchscreen/goodix.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c
index 5f9e755c5bc7..405246d61701 100644
--- a/drivers/input/touchscreen/goodix.c
+++ b/drivers/input/touchscreen/goodix.c
@@ -219,6 +219,7 @@ static const struct goodix_chip_data *goodix_get_chip_data(u16 id)
{
switch (id) {
case 1151:
+ case 5663:
return >1x_chip_data;
case 911:
@@ -1000,6 +1001,7 @@ MODULE_DEVICE_TABLE(acpi, goodix_acpi_match);
#ifdef CONFIG_OF
static const struct of_device_id goodix_of_match[] = {
{ .compatible = "goodix,gt1151" },
+ { .compatible = "goodix,gt5663" },
{ .compatible = "goodix,gt911" },
{ .compatible = "goodix,gt9110" },
{ .compatible = "goodix,gt912" },
--
2.18.0.321.gffc6fa0e3
^ permalink raw reply related
* [PATCH v6 3/4] dt-bindings: input: touchscreen: goodix: Add GT5663 compatible
From: Jagan Teki @ 2019-02-19 10:16 UTC (permalink / raw)
To: Dmitry Torokhov, Bastien Nocera, Rob Herring
Cc: Henrik Rydberg, linux-input, linux-kernel, devicetree,
Mark Rutland, linux-amarula, Michael Trimarchi, Jagan Teki
In-Reply-To: <20190219101629.15977-1-jagan@amarulasolutions.com>
GT5663 is capacitive touch controller with customized smart
wakeup gestures, it support chipdata which is similar to
existing GT1151 and require AVDD28 supply for some boards.
Document the compatible for the same.
Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
Reviewed-by: Rob Herring <robh@kernel.org>
---
Documentation/devicetree/bindings/input/touchscreen/goodix.txt | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/input/touchscreen/goodix.txt b/Documentation/devicetree/bindings/input/touchscreen/goodix.txt
index b9b8f196dc90..1dcae643427f 100644
--- a/Documentation/devicetree/bindings/input/touchscreen/goodix.txt
+++ b/Documentation/devicetree/bindings/input/touchscreen/goodix.txt
@@ -3,6 +3,7 @@ Device tree bindings for Goodix GT9xx series touchscreen controller
Required properties:
- compatible : Should be "goodix,gt1151"
+ or "goodix,gt5663"
or "goodix,gt911"
or "goodix,gt9110"
or "goodix,gt912"
--
2.18.0.321.gffc6fa0e3
^ permalink raw reply related
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