Linux Input/HID development
 help / color / mirror / Atom feed
* [PATCH v2 2/2] cap1106: support for irq-active-high option
From: Matt Ranostay @ 2014-09-23  4:04 UTC (permalink / raw)
  To: galak, dmitry.torokhov, zonque, linux-input, linux-kernel,
	robh+dt
  Cc: devicetree, Matt Ranostay
In-Reply-To: <1411445057-30048-1-git-send-email-mranostay@gmail.com>

Some applications need to use the irq-active-high push-pull option.
This allows it be enabled in the device tree child node.

Signed-off-by: Matt Ranostay <mranostay@gmail.com>
---
 Documentation/devicetree/bindings/input/cap1106.txt | 4 ++++
 drivers/input/keyboard/cap1106.c                    | 8 ++++++++
 2 files changed, 12 insertions(+)

diff --git a/Documentation/devicetree/bindings/input/cap1106.txt b/Documentation/devicetree/bindings/input/cap1106.txt
index 4b46390..6f5a143 100644
--- a/Documentation/devicetree/bindings/input/cap1106.txt
+++ b/Documentation/devicetree/bindings/input/cap1106.txt
@@ -26,6 +26,10 @@ Optional properties:
 				Valid values are 1, 2, 4, and 8.
 				By default, a gain of 1 is set.
 
+	microchip,irq-active-high:	By default the interrupt pin is active low
+				open drain. This property allows using the active
+				high push-pull output.
+
 	linux,keycodes:		Specifies an array of numeric keycode values to
 				be used for the channels. If this property is
 				omitted, KEY_A, KEY_B, etc are used as
diff --git a/drivers/input/keyboard/cap1106.c b/drivers/input/keyboard/cap1106.c
index 07f9e88..d5ce060 100644
--- a/drivers/input/keyboard/cap1106.c
+++ b/drivers/input/keyboard/cap1106.c
@@ -47,6 +47,7 @@
 #define CAP1106_REG_STANDBY_SENSITIVITY	0x42
 #define CAP1106_REG_STANDBY_THRESH	0x43
 #define CAP1106_REG_CONFIG2		0x44
+#define CAP1106_REG_CONFIG2_ALT_POL	BIT(6)
 #define CAP1106_REG_SENSOR_BASE_CNT(X)	(0x50 + (X))
 #define CAP1106_REG_SENSOR_CALIB	(0xb1 + (X))
 #define CAP1106_REG_SENSOR_CALIB_LSB1	0xb9
@@ -260,6 +261,13 @@ static int cap1106_i2c_probe(struct i2c_client *i2c_client,
 			dev_err(dev, "Invalid sensor-gain value %d\n", gain32);
 	}
 
+	if (of_property_read_bool(node, "microchip,irq-active-high")) {
+		error = regmap_update_bits(priv->regmap, CAP1106_REG_CONFIG2,
+					   CAP1106_REG_CONFIG2_ALT_POL, 0);
+		if (error)
+			return error;
+	}
+
 	/* Provide some useful defaults */
 	for (i = 0; i < priv->num_channels; i++)
 		priv->keycodes[i] = KEY_A + i;
-- 
1.9.1

^ permalink raw reply related

* Re: [PATCH v2 1/2] cap1106: Add support for various cap11xx devices
From: Daniel Mack @ 2014-09-23  6:46 UTC (permalink / raw)
  To: Matt Ranostay, galak, dmitry.torokhov, zonque, linux-input,
	linux-kernel, robh+dt
  Cc: devicetree
In-Reply-To: <1411445057-30048-2-git-send-email-mranostay@gmail.com>

On 09/23/2014 06:04 AM, Matt Ranostay wrote:
> diff --git a/drivers/input/keyboard/cap1106.c b/drivers/input/keyboard/cap1106.c
> index d70b65a..07f9e88 100644
> --- a/drivers/input/keyboard/cap1106.c
> +++ b/drivers/input/keyboard/cap1106.c
> @@ -55,8 +55,6 @@
>  #define CAP1106_REG_MANUFACTURER_ID	0xfe
>  #define CAP1106_REG_REVISION		0xff
>  
> -#define CAP1106_NUM_CHN 6
> -#define CAP1106_PRODUCT_ID	0x55
>  #define CAP1106_MANUFACTURER_ID	0x5d
>  
>  struct cap1106_priv {
> @@ -64,7 +62,25 @@ struct cap1106_priv {
>  	struct input_dev *idev;
>  
>  	/* config */
> -	unsigned short keycodes[CAP1106_NUM_CHN];
> +	u32 *keycodes;
> +	unsigned int num_channels;
> +};
> +
> +struct cap11xx_hw_model {
> +	uint8_t product_id;
> +	unsigned int num_channels;
> +};
> +
> +enum {
> +	CAP1106,
> +	CAP1126,
> +	CAP1188,
> +};
> +
> +struct cap11xx_hw_model cap11xx_devices[] = {

This can be static const.

And, as I said, there should be a 3rd patch that renames the file and
its functions, structs, defines etc to the more generic "11xx" variants.


Thanks,
Daniel


^ permalink raw reply

* PROBLEM: [Asus X750LN] Touchpad not recognized
From: Nikola Nikolov @ 2014-09-23 11:30 UTC (permalink / raw)
  To: linux-input

[1.] One line summary of the problem:
[Asus X750LN] Touchpad not recognized

[2.] Full description of the problem/report:
Running the latest mainline kernel, the touchpad on my laptop is not
recognized at all - it's not listed as an input device and nothing
happens whenever I try using it.

[3.] Keywords:

[4.] Kernel version (from /proc/version):
Linux version 3.17.0-031700rc6-generic (apw@gomeisa) (gcc version
4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5) ) #201409211935 SMP Sun Sep 21
23:37:11 UTC 2014

[5.] Output of Oops.. message (if applicable) with symbolic
information resolved (see Documentation/oops-tracing.txt):
N/A

[6.] A small shell script or example program which triggers the
problem (if possible):
N/A

[7.] Environment:
Description: Ubuntu 14.04.1 LTS
Release: 14.04

[7.1.] Software (add the output of the ver_linux script here):
If some fields are empty or look unusual you may have an old version.
Compare to the current minimal requirements in Documentation/Changes.

Linux moonwatch-laptop 3.17.0-031700rc6-generic #201409211935 SMP Sun
Sep 21 23:37:11 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux

Gnu C                  4.8
Gnu make               3.81
binutils               2.24
util-linux             2.20.1
mount                  support
module-init-tools      15
e2fsprogs              1.42.9
pcmciautils            018
PPP                    2.4.5
Linux C Library        2.19
Dynamic linker (ldd)   2.19
Procps                 3.3.9
Net-tools              1.60
Kbd                    1.15.5
Sh-utils               8.21
wireless-tools         30
Modules Loaded         snd_hda_codec_realtek snd_hda_codec_hdmi
snd_hda_codec_generic bnep rfcomm bluetooth joydev hid_generic
asus_nb_wmi asus_wmi sparse_keymap intel_rapl x86_pkg_temp_thermal
intel_powerclamp coretemp kvm_intel kvm crct10dif_pclmul crc32_pclmul
ghash_clmulni_intel aesni_intel aes_x86_64 lrw gf128mul glue_helper
ablk_helper cryptd uvcvideo videobuf2_vmalloc serio_raw
videobuf2_memops videobuf2_core uas v4l2_common nouveau usb_storage
videodev media usbhid lpc_ich mxm_wmi ttm mei_me mei snd_soc_rt5640
snd_soc_rl6231 snd_soc_core i2c_hid dw_dmac snd_soc_sst_acpi hid
snd_compress dw_dmac_core snd_pcm_dmaengine 8250_dw
i2c_designware_platform mac_hid i2c_designware_core
spi_pxa2xx_platform wmi snd_hda_intel snd_hda_controller snd_hda_codec
snd_hwdep snd_pcm i915 snd_seq_midi snd_seq_midi_event snd_rawmidi
snd_seq video snd_seq_device snd_timer drm_kms_helper drm snd
soundcore i2c_algo_bit parport_pc ppdev lp parport ahci r8169 libahci
mii sdhci_acpi sdhci

[7.2.] Processor information (from /proc/cpuinfo):
processor : 0
vendor_id : GenuineIntel
cpu family : 6
model : 69
model name : Intel(R) Core(TM) i7-4510U CPU @ 2.00GHz
stepping : 1
microcode : 0x17
cpu MHz : 2003.015
cache size : 4096 KB
physical id : 0
siblings : 4
core id : 0
cpu cores : 2
apicid : 0
initial apicid : 0
fpu : yes
fpu_exception : yes
cpuid level : 13
wp : yes
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov
pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx
pdpe1gb rdtscp lm constant_tsc arch_perfmon pebs bts rep_good nopl
xtopology nonstop_tsc aperfmperf eagerfpu pni pclmulqdq dtes64 monitor
ds_cpl vmx est tm2 ssse3 fma cx16 xtpr pdcm pcid sse4_1 sse4_2 movbe
popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm ida
arat epb pln pts dtherm tpr_shadow vnmi flexpriority ept vpid fsgsbase
tsc_adjust bmi1 avx2 smep bmi2 erms invpcid xsaveopt
bugs :
bogomips : 5188.24
clflush size : 64
cache_alignment : 64
address sizes : 39 bits physical, 48 bits virtual
power management:

processor : 1
vendor_id : GenuineIntel
cpu family : 6
model : 69
model name : Intel(R) Core(TM) i7-4510U CPU @ 2.00GHz
stepping : 1
microcode : 0x17
cpu MHz : 1999.968
cache size : 4096 KB
physical id : 0
siblings : 4
core id : 1
cpu cores : 2
apicid : 2
initial apicid : 2
fpu : yes
fpu_exception : yes
cpuid level : 13
wp : yes
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov
pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx
pdpe1gb rdtscp lm constant_tsc arch_perfmon pebs bts rep_good nopl
xtopology nonstop_tsc aperfmperf eagerfpu pni pclmulqdq dtes64 monitor
ds_cpl vmx est tm2 ssse3 fma cx16 xtpr pdcm pcid sse4_1 sse4_2 movbe
popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm ida
arat epb pln pts dtherm tpr_shadow vnmi flexpriority ept vpid fsgsbase
tsc_adjust bmi1 avx2 smep bmi2 erms invpcid xsaveopt
bugs :
bogomips : 5188.24
clflush size : 64
cache_alignment : 64
address sizes : 39 bits physical, 48 bits virtual
power management:

processor : 2
vendor_id : GenuineIntel
cpu family : 6
model : 69
model name : Intel(R) Core(TM) i7-4510U CPU @ 2.00GHz
stepping : 1
microcode : 0x17
cpu MHz : 2000.070
cache size : 4096 KB
physical id : 0
siblings : 4
core id : 0
cpu cores : 2
apicid : 1
initial apicid : 1
fpu : yes
fpu_exception : yes
cpuid level : 13
wp : yes
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov
pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx
pdpe1gb rdtscp lm constant_tsc arch_perfmon pebs bts rep_good nopl
xtopology nonstop_tsc aperfmperf eagerfpu pni pclmulqdq dtes64 monitor
ds_cpl vmx est tm2 ssse3 fma cx16 xtpr pdcm pcid sse4_1 sse4_2 movbe
popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm ida
arat epb pln pts dtherm tpr_shadow vnmi flexpriority ept vpid fsgsbase
tsc_adjust bmi1 avx2 smep bmi2 erms invpcid xsaveopt
bugs :
bogomips : 5188.24
clflush size : 64
cache_alignment : 64
address sizes : 39 bits physical, 48 bits virtual
power management:

processor : 3
vendor_id : GenuineIntel
cpu family : 6
model : 69
model name : Intel(R) Core(TM) i7-4510U CPU @ 2.00GHz
stepping : 1
microcode : 0x17
cpu MHz : 2844.156
cache size : 4096 KB
physical id : 0
siblings : 4
core id : 1
cpu cores : 2
apicid : 3
initial apicid : 3
fpu : yes
fpu_exception : yes
cpuid level : 13
wp : yes
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov
pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx
pdpe1gb rdtscp lm constant_tsc arch_perfmon pebs bts rep_good nopl
xtopology nonstop_tsc aperfmperf eagerfpu pni pclmulqdq dtes64 monitor
ds_cpl vmx est tm2 ssse3 fma cx16 xtpr pdcm pcid sse4_1 sse4_2 movbe
popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm ida
arat epb pln pts dtherm tpr_shadow vnmi flexpriority ept vpid fsgsbase
tsc_adjust bmi1 avx2 smep bmi2 erms invpcid xsaveopt
bugs :
bogomips : 5188.24
clflush size : 64
cache_alignment : 64
address sizes : 39 bits physical, 48 bits virtual
power management:

[7.3.] Module information (from /proc/modules):
snd_hda_codec_realtek 78564 1 - Live 0x0000000000000000
snd_hda_codec_hdmi 52620 1 - Live 0x0000000000000000
snd_hda_codec_generic 70087 1 snd_hda_codec_realtek, Live 0x0000000000000000
bnep 19884 2 - Live 0x0000000000000000
rfcomm 75114 0 - Live 0x0000000000000000
bluetooth 477455 10 bnep,rfcomm, Live 0x0000000000000000
joydev 17587 0 - Live 0x0000000000000000
hid_generic 12559 0 - Live 0x0000000000000000
asus_nb_wmi 21128 0 - Live 0x0000000000000000
asus_wmi 24697 1 asus_nb_wmi, Live 0x0000000000000000
sparse_keymap 13890 1 asus_wmi, Live 0x0000000000000000
intel_rapl 19196 0 - Live 0x0000000000000000
x86_pkg_temp_thermal 14312 0 - Live 0x0000000000000000
intel_powerclamp 19099 0 - Live 0x0000000000000000
coretemp 13638 0 - Live 0x0000000000000000
kvm_intel 149257 0 - Live 0x0000000000000000
kvm 468567 1 kvm_intel, Live 0x0000000000000000
crct10dif_pclmul 14268 0 - Live 0x0000000000000000
crc32_pclmul 13180 0 - Live 0x0000000000000000
ghash_clmulni_intel 13230 0 - Live 0x0000000000000000
aesni_intel 165515 0 - Live 0x0000000000000000
aes_x86_64 17131 1 aesni_intel, Live 0x0000000000000000
lrw 13323 1 aesni_intel, Live 0x0000000000000000
gf128mul 14951 1 lrw, Live 0x0000000000000000
glue_helper 14095 1 aesni_intel, Live 0x0000000000000000
ablk_helper 13597 1 aesni_intel, Live 0x0000000000000000
cryptd 20531 3 ghash_clmulni_intel,aesni_intel,ablk_helper, Live
0x0000000000000000
uvcvideo 86628 0 - Live 0x0000000000000000
videobuf2_vmalloc 13216 1 uvcvideo, Live 0x0000000000000000
serio_raw 13483 0 - Live 0x0000000000000000
videobuf2_memops 13362 1 videobuf2_vmalloc, Live 0x0000000000000000
videobuf2_core 59907 1 uvcvideo, Live 0x0000000000000000
uas 27623 0 - Live 0x0000000000000000
v4l2_common 15715 1 videobuf2_core, Live 0x0000000000000000
nouveau 1321757 0 - Live 0x0000000000000000
usb_storage 67010 1 uas, Live 0x0000000000000000
videodev 163831 3 uvcvideo,videobuf2_core,v4l2_common, Live 0x0000000000000000
media 22008 2 uvcvideo,videodev, Live 0x0000000000000000
usbhid 53122 0 - Live 0x0000000000000000
lpc_ich 21176 0 - Live 0x0000000000000000
mxm_wmi 13021 1 nouveau, Live 0x0000000000000000
ttm 90376 1 nouveau, Live 0x0000000000000000
mei_me 19524 0 - Live 0x0000000000000000
mei 88810 1 mei_me, Live 0x0000000000000000
snd_soc_rt5640 93123 0 - Live 0x0000000000000000
snd_soc_rl6231 13037 1 snd_soc_rt5640, Live 0x0000000000000000
snd_soc_core 207547 1 snd_soc_rt5640, Live 0x0000000000000000
i2c_hid 19065 0 - Live 0x0000000000000000
dw_dmac 12835 0 - Live 0x0000000000000000
snd_soc_sst_acpi 13007 0 - Live 0x0000000000000000
hid 110572 3 hid_generic,usbhid,i2c_hid, Live 0x0000000000000000
snd_compress 19435 1 snd_soc_core, Live 0x0000000000000000
dw_dmac_core 28566 1 dw_dmac, Live 0x0000000000000000
snd_pcm_dmaengine 15229 1 snd_soc_core, Live 0x0000000000000000
8250_dw 13474 0 - Live 0x0000000000000000
i2c_designware_platform 13025 0 - Live 0x0000000000000000
mac_hid 13275 0 - Live 0x0000000000000000
i2c_designware_core 14990 1 i2c_designware_platform, Live 0x0000000000000000
spi_pxa2xx_platform 23302 0 - Live 0x0000000000000000
wmi 19379 3 asus_wmi,nouveau,mxm_wmi, Live 0x0000000000000000
snd_hda_intel 30783 5 - Live 0x0000000000000000
snd_hda_controller 32234 1 snd_hda_intel, Live 0x0000000000000000
snd_hda_codec 145035 5
snd_hda_codec_realtek,snd_hda_codec_hdmi,snd_hda_codec_generic,snd_hda_intel,snd_hda_controller,
Live 0x0000000000000000
snd_hwdep 17709 1 snd_hda_codec, Live 0x0000000000000000
snd_pcm 105052 7
snd_hda_codec_hdmi,snd_soc_rt5640,snd_soc_core,snd_pcm_dmaengine,snd_hda_intel,snd_hda_controller,snd_hda_codec,
Live 0x0000000000000000
i915 993210 7 - Live 0x0000000000000000
snd_seq_midi 13564 0 - Live 0x0000000000000000
snd_seq_midi_event 14899 1 snd_seq_midi, Live 0x0000000000000000
snd_rawmidi 31197 1 snd_seq_midi, Live 0x0000000000000000
snd_seq 63540 2 snd_seq_midi,snd_seq_midi_event, Live 0x0000000000000000
video 20569 3 asus_wmi,nouveau,i915, Live 0x0000000000000000
snd_seq_device 14497 3 snd_seq_midi,snd_rawmidi,snd_seq, Live 0x0000000000000000
snd_timer 30118 2 snd_pcm,snd_seq, Live 0x0000000000000000
drm_kms_helper 99872 2 nouveau,i915, Live 0x0000000000000000
drm 318542 8 nouveau,ttm,i915,drm_kms_helper, Live 0x0000000000000000
snd 84025 23 snd_hda_codec_realtek,snd_hda_codec_hdmi,snd_hda_codec_generic,snd_soc_core,snd_compress,snd_hda_intel,snd_hda_codec,snd_hwdep,snd_pcm,snd_rawmidi,snd_seq,snd_seq_device,snd_timer,
Live 0x0000000000000000
soundcore 15091 2 snd_hda_codec,snd, Live 0x0000000000000000
i2c_algo_bit 13564 2 nouveau,i915, Live 0x0000000000000000
parport_pc 32906 0 - Live 0x0000000000000000
ppdev 17711 0 - Live 0x0000000000000000
lp 17799 0 - Live 0x0000000000000000
parport 42481 3 parport_pc,ppdev,lp, Live 0x0000000000000000
ahci 30167 3 - Live 0x0000000000000000
r8169 77680 0 - Live 0x0000000000000000
libahci 32533 1 ahci, Live 0x0000000000000000
mii 13981 1 r8169, Live 0x0000000000000000
sdhci_acpi 13395 0 - Live 0x0000000000000000
sdhci 44159 1 sdhci_acpi, Live 0x0000000000000000

[7.4.] Loaded driver and hardware information (/proc/ioports, /proc/iomem)
cat /proc/ioports:
0000-0cf7 : PCI Bus 0000:00
  0000-001f : dma1
  0020-0021 : pic1
  0040-0043 : timer0
  0050-0053 : timer1
  0060-0060 : keyboard
  0064-0064 : keyboard
  0070-0077 : rtc0
  0080-008f : dma page reg
  00a0-00a1 : pic2
  00c0-00df : dma2
  00f0-00ff : fpu
  03c0-03df : vesafb
  04d0-04d1 : pnp 00:04
  0680-069f : pnp 00:01
0cf8-0cff : PCI conf1
0d00-ffff : PCI Bus 0000:00
  164e-164f : pnp 00:01
  1800-1803 : ACPI PM1a_EVT_BLK
  1804-1805 : ACPI PM1a_CNT_BLK
  1808-180b : ACPI PM_TMR
  1810-1815 : ACPI CPU throttle
  1830-1833 : iTCO_wdt
  1850-1850 : ACPI PM2_CNT_BLK
  1854-1857 : pnp 00:03
  1860-187f : iTCO_wdt
  1880-189f : ACPI GPE0_BLK
  1c00-1cfe : pnp 00:01
  1d00-1dfe : pnp 00:01
  1e00-1efe : pnp 00:01
  1f00-1ffe : pnp 00:01
  2000-2fff : PCI Bus 0000:01
  d000-dfff : PCI Bus 0000:04
    d000-d07f : 0000:04:00.0
  e000-efff : PCI Bus 0000:03
    e000-e0ff : 0000:03:00.0
      e000-e0ff : r8169
  f000-f03f : 0000:00:02.0
  f040-f05f : 0000:00:1f.3
  f060-f07f : 0000:00:1f.2
    f060-f07f : ahci
  f080-f083 : 0000:00:1f.2
    f080-f083 : ahci
  f090-f097 : 0000:00:1f.2
    f090-f097 : ahci
  f0a0-f0a3 : 0000:00:1f.2
    f0a0-f0a3 : ahci
  f0b0-f0b7 : 0000:00:1f.2
    f0b0-f0b7 : ahci
  ffff-ffff : pnp 00:01
    ffff-ffff : pnp 00:01
      ffff-ffff : pnp 00:01

cat /proc/iomem:
00000000-00000fff : reserved
00001000-0009d7ff : System RAM
0009d800-0009ffff : reserved
000a0000-000bffff : PCI Bus 0000:00
000c0000-000cebff : Video ROM
000d0000-000d3fff : PCI Bus 0000:00
000d4000-000d7fff : PCI Bus 0000:00
000d8000-000dbfff : PCI Bus 0000:00
000dc000-000dffff : PCI Bus 0000:00
000e0000-000fffff : reserved
  000e0000-000e3fff : PCI Bus 0000:00
  000e4000-000e7fff : PCI Bus 0000:00
  000f0000-000fffff : System ROM
00100000-b8a8cfff : System RAM
  01000000-017a9977 : Kernel code
  017a9978-01d1e4ff : Kernel data
  01e80000-01fc6fff : Kernel bss
b8a8d000-b8a93fff : ACPI Non-volatile Storage
b8a94000-b8ecbfff : System RAM
b8ecc000-b943cfff : reserved
b943d000-c8c15fff : System RAM
c8c16000-c8c9ffff : reserved
c8ca0000-c8e7bfff : System RAM
c8e7c000-c9615fff : ACPI Non-volatile Storage
c9616000-c9ffdfff : reserved
c9ffe000-c9ffefff : System RAM
c9fff000-caffffff : RAM buffer
cb000000-cf1fffff : reserved
  cb200000-cf1fffff : Graphics Stolen Memory
cf200000-feafffff : PCI Bus 0000:00
  cf200000-cf3fffff : PCI Bus 0000:01
  cf400000-cf5fffff : PCI Bus 0000:01
  d0000000-dfffffff : 0000:00:02.0
  e0000000-f1ffffff : PCI Bus 0000:04
    e0000000-efffffff : 0000:04:00.0
    f0000000-f1ffffff : 0000:04:00.0
  f2100000-f21fffff : PCI Bus 0000:03
    f2100000-f2103fff : 0000:03:00.0
      f2100000-f2103fff : r8169
  f6000000-f70fffff : PCI Bus 0000:04
    f6000000-f6ffffff : 0000:04:00.0
    f7000000-f707ffff : 0000:04:00.0
  f7400000-f77fffff : 0000:00:02.0
  f7800000-f78fffff : PCI Bus 0000:03
    f7800000-f7800fff : 0000:03:00.0
      f7800000-f7800fff : r8169
  f7900000-f79fffff : PCI Bus 0000:02
    f7900000-f7907fff : 0000:02:00.0
  f7a00000-f7a0ffff : 0000:00:14.0
    f7a00000-f7a0ffff : xhci_hcd
  f7a10000-f7a13fff : 0000:00:1b.0
    f7a10000-f7a13fff : ICH HD audio
  f7a14000-f7a17fff : 0000:00:03.0
    f7a14000-f7a17fff : ICH HD audio
  f7a19000-f7a190ff : 0000:00:1f.3
  f7a1a000-f7a1a7ff : 0000:00:1f.2
    f7a1a000-f7a1a7ff : ahci
  f7a1b000-f7a1b3ff : 0000:00:1d.0
    f7a1b000-f7a1b3ff : ehci_hcd
  f7a1d000-f7a1d01f : 0000:00:16.0
    f7a1d000-f7a1d01f : mei_me
  f7fdf000-f7fdffff : pnp 00:08
  f7fe0000-f7feffff : pnp 00:08
  f8000000-fbffffff : PCI MMCONFIG 0000 [bus 00-3f]
    f8000000-fbffffff : reserved
      f8000000-fbffffff : pnp 00:08
  fe104000-fe104fff : pnp 00:07
  fe106000-fe106fff : pnp 00:07
  fe10e000-fe10efff : pnp 00:07
  fe111000-fe111007 : pnp 00:07
  fe111014-fe111fff : pnp 00:07
  fe112000-fe112fff : pnp 00:07
fec00000-fec00fff : reserved
  fec00000-fec003ff : IOAPIC 0
fed00000-fed03fff : reserved
  fed00000-fed003ff : HPET 0
    fed00000-fed003ff : PNP0103:00
fed10000-fed17fff : pnp 00:08
fed18000-fed18fff : pnp 00:08
fed19000-fed19fff : pnp 00:08
fed1c000-fed1ffff : reserved
  fed1c000-fed1ffff : pnp 00:08
    fed1f410-fed1f414 : iTCO_wdt
fed20000-fed3ffff : pnp 00:08
fed40000-fed44fff : pnp 00:00
fed45000-fed8ffff : pnp 00:08
fed90000-fed93fff : pnp 00:08
fee00000-fee00fff : Local APIC
  fee00000-fee00fff : reserved
ff000000-ffffffff : reserved
  ff000000-ffffffff : INT0800:00
    ff000000-ffffffff : pnp 00:08
100000000-22fdfffff : System RAM
22fe00000-22fffffff : RAM buffer

[7.5.] PCI information ('lspci -vvv' as root):
00:00.0 Host bridge: Intel Corporation Haswell-ULT DRAM Controller (rev 0b)
Subsystem: ASUSTeK Computer Inc. Device 14fd
Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr-
Stepping- SERR- FastB2B- DisINTx-
Status: Cap+ 66MHz- UDF- FastB2B+ ParErr- DEVSEL=fast >TAbort-
<TAbort- <MAbort+ >SERR- <PERR- INTx-
Latency: 0
Capabilities: [e0] Vendor Specific Information: Len=0c <?>

00:02.0 VGA compatible controller: Intel Corporation Haswell-ULT
Integrated Graphics Controller (rev 0b) (prog-if 00 [VGA controller])
Subsystem: ASUSTeK Computer Inc. Device 14fd
Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr-
Stepping- SERR- FastB2B- DisINTx+
Status: Cap+ 66MHz- UDF- FastB2B+ ParErr- DEVSEL=fast >TAbort-
<TAbort- <MAbort- >SERR- <PERR- INTx-
Latency: 0
Interrupt: pin A routed to IRQ 47
Region 0: Memory at f7400000 (64-bit, non-prefetchable) [size=4M]
Region 2: Memory at d0000000 (64-bit, prefetchable) [size=256M]
Region 4: I/O ports at f000 [size=64]
Expansion ROM at <unassigned> [disabled]
Capabilities: [90] MSI: Enable+ Count=1/1 Maskable- 64bit-
Address: fee0f00c  Data: 4152
Capabilities: [d0] Power Management version 2
Flags: PMEClk- DSI+ D1- D2- AuxCurrent=0mA PME(D0-,D1-,D2-,D3hot-,D3cold-)
Status: D0 NoSoftRst- PME-Enable- DSel=0 DScale=0 PME-
Capabilities: [a4] PCI Advanced Features
AFCap: TP+ FLR+
AFCtrl: FLR-
AFStatus: TP-
Kernel driver in use: i915

00:03.0 Audio device: Intel Corporation Haswell-ULT HD Audio Controller (rev 0b)
Subsystem: ASUSTeK Computer Inc. Device 14fd
Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr-
Stepping- SERR- FastB2B- DisINTx+
Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort-
<TAbort- <MAbort- >SERR- <PERR- INTx-
Latency: 0, Cache Line Size: 64 bytes
Interrupt: pin A routed to IRQ 50
Region 0: Memory at f7a14000 (64-bit, non-prefetchable) [size=16K]
Capabilities: [50] Power Management version 2
Flags: PMEClk- DSI- D1- D2- AuxCurrent=0mA PME(D0-,D1-,D2-,D3hot-,D3cold-)
Status: D0 NoSoftRst- PME-Enable- DSel=0 DScale=0 PME-
Capabilities: [60] MSI: Enable+ Count=1/1 Maskable- 64bit-
Address: fee0f00c  Data: 4192
Capabilities: [70] Express (v1) Root Complex Integrated Endpoint, MSI 00
DevCap: MaxPayload 128 bytes, PhantFunc 0
ExtTag- RBE-
DevCtl: Report errors: Correctable- Non-Fatal- Fatal- Unsupported-
RlxdOrd- ExtTag- PhantFunc- AuxPwr- NoSnoop-
MaxPayload 128 bytes, MaxReadReq 128 bytes
DevSta: CorrErr- UncorrErr- FatalErr- UnsuppReq- AuxPwr- TransPend-
Kernel driver in use: snd_hda_intel

00:14.0 USB controller: Intel Corporation Lynx Point-LP USB xHCI HC
(rev 04) (prog-if 30 [XHCI])
Subsystem: ASUSTeK Computer Inc. Device 201f
Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr-
Stepping- SERR- FastB2B- DisINTx+
Status: Cap+ 66MHz- UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort-
<TAbort- <MAbort- >SERR- <PERR- INTx-
Latency: 0
Interrupt: pin A routed to IRQ 44
Region 0: Memory at f7a00000 (64-bit, non-prefetchable) [size=64K]
Capabilities: [70] Power Management version 2
Flags: PMEClk- DSI- D1- D2- AuxCurrent=375mA PME(D0-,D1-,D2-,D3hot+,D3cold+)
Status: D0 NoSoftRst+ PME-Enable- DSel=0 DScale=0 PME-
Capabilities: [80] MSI: Enable+ Count=1/8 Maskable- 64bit+
Address: 00000000fee0500c  Data: 41e1
Kernel driver in use: xhci_hcd

00:16.0 Communication controller: Intel Corporation Lynx Point-LP HECI
#0 (rev 04)
Subsystem: ASUSTeK Computer Inc. Device 14fd
Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr-
Stepping- SERR- FastB2B- DisINTx+
Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort-
<TAbort- <MAbort- >SERR- <PERR- INTx-
Latency: 0
Interrupt: pin A routed to IRQ 48
Region 0: Memory at f7a1d000 (64-bit, non-prefetchable) [size=32]
Capabilities: [50] Power Management version 3
Flags: PMEClk- DSI- D1- D2- AuxCurrent=0mA PME(D0+,D1-,D2-,D3hot+,D3cold+)
Status: D0 NoSoftRst+ PME-Enable- DSel=0 DScale=0 PME-
Capabilities: [8c] MSI: Enable+ Count=1/1 Maskable- 64bit+
Address: 00000000fee0f00c  Data: 4172
Kernel driver in use: mei_me

00:1b.0 Audio device: Intel Corporation Lynx Point-LP HD Audio
Controller (rev 04)
Subsystem: ASUSTeK Computer Inc. Device 14fd
Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr-
Stepping- SERR- FastB2B- DisINTx+
Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort-
<TAbort- <MAbort- >SERR- <PERR- INTx-
Latency: 0, Cache Line Size: 64 bytes
Interrupt: pin A routed to IRQ 49
Region 0: Memory at f7a10000 (64-bit, non-prefetchable) [size=16K]
Capabilities: [50] Power Management version 3
Flags: PMEClk- DSI- D1- D2- AuxCurrent=55mA PME(D0+,D1-,D2-,D3hot+,D3cold+)
Status: D0 NoSoftRst- PME-Enable- DSel=0 DScale=0 PME-
Capabilities: [60] MSI: Enable+ Count=1/1 Maskable- 64bit+
Address: 00000000fee0f00c  Data: 4182
Capabilities: [70] Express (v1) Root Complex Integrated Endpoint, MSI 00
DevCap: MaxPayload 128 bytes, PhantFunc 0
ExtTag- RBE-
DevCtl: Report errors: Correctable- Non-Fatal- Fatal- Unsupported-
RlxdOrd- ExtTag- PhantFunc- AuxPwr- NoSnoop-
MaxPayload 128 bytes, MaxReadReq 128 bytes
DevSta: CorrErr- UncorrErr- FatalErr- UnsuppReq- AuxPwr+ TransPend-
Capabilities: [100 v1] Virtual Channel
Caps: LPEVC=0 RefClk=100ns PATEntryBits=1
Arb: Fixed- WRR32- WRR64- WRR128-
Ctrl: ArbSelect=Fixed
Status: InProgress-
VC0: Caps: PATOffset=00 MaxTimeSlots=1 RejSnoopTrans-
Arb: Fixed- WRR32- WRR64- WRR128- TWRR128- WRR256-
Ctrl: Enable+ ID=0 ArbSelect=Fixed TC/VC=01
Status: NegoPending- InProgress-
VC1: Caps: PATOffset=00 MaxTimeSlots=1 RejSnoopTrans-
Arb: Fixed- WRR32- WRR64- WRR128- TWRR128- WRR256-
Ctrl: Enable- ID=2 ArbSelect=Fixed TC/VC=04
Status: NegoPending- InProgress-
Kernel driver in use: snd_hda_intel

00:1c.0 PCI bridge: Intel Corporation Lynx Point-LP PCI Express Root
Port 1 (rev e4) (prog-if 00 [Normal decode])
Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr-
Stepping- SERR- FastB2B- DisINTx+
Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort-
<TAbort- <MAbort- >SERR- <PERR- INTx-
Latency: 0, Cache Line Size: 64 bytes
Bus: primary=00, secondary=01, subordinate=01, sec-latency=0
I/O behind bridge: 00002000-00002fff
Memory behind bridge: cf200000-cf3fffff
Prefetchable memory behind bridge: 00000000cf400000-00000000cf5fffff
Secondary status: 66MHz- FastB2B- ParErr- DEVSEL=fast >TAbort-
<TAbort- <MAbort+ <SERR- <PERR-
BridgeCtl: Parity- SERR- NoISA- VGA- MAbort- >Reset- FastB2B-
PriDiscTmr- SecDiscTmr- DiscTmrStat- DiscTmrSERREn-
Capabilities: [40] Express (v2) Root Port (Slot+), MSI 00
DevCap: MaxPayload 128 bytes, PhantFunc 0
ExtTag- RBE+
DevCtl: Report errors: Correctable- Non-Fatal- Fatal- Unsupported-
RlxdOrd- ExtTag- PhantFunc- AuxPwr- NoSnoop-
MaxPayload 128 bytes, MaxReadReq 128 bytes
DevSta: CorrErr- UncorrErr- FatalErr- UnsuppReq- AuxPwr+ TransPend-
LnkCap: Port #1, Speed 5GT/s, Width x1, ASPM L0s L1, Exit Latency L0s
<1us, L1 <4us
ClockPM- Surprise- LLActRep+ BwNot+
LnkCtl: ASPM Disabled; RCB 64 bytes Disabled- CommClk-
ExtSynch- ClockPM- AutWidDis- BWInt- AutBWInt-
LnkSta: Speed 2.5GT/s, Width x0, TrErr- Train- SlotClk+ DLActive-
BWMgmt- ABWMgmt-
SltCap: AttnBtn- PwrCtrl- MRL- AttnInd- PwrInd- HotPlug+ Surprise+
Slot #0, PowerLimit 0.000W; Interlock- NoCompl+
SltCtl: Enable: AttnBtn- PwrFlt- MRL- PresDet+ CmdCplt- HPIrq+ LinkChg+
Control: AttnInd Unknown, PwrInd Unknown, Power- Interlock-
SltSta: Status: AttnBtn- PowerFlt- MRL- CmdCplt- PresDet- Interlock-
Changed: MRL- PresDet- LinkState-
RootCtl: ErrCorrectable- ErrNon-Fatal- ErrFatal- PMEIntEna+ CRSVisible-
RootCap: CRSVisible-
RootSta: PME ReqID 0000, PMEStatus- PMEPending-
DevCap2: Completion Timeout: Range ABC, TimeoutDis+, LTR+, OBFF Via
WAKE# ARIFwd-
DevCtl2: Completion Timeout: 50us to 50ms, TimeoutDis-, LTR+, OBFF
Disabled ARIFwd-
LnkCtl2: Target Link Speed: 5GT/s, EnterCompliance- SpeedDis-
Transmit Margin: Normal Operating Range, EnterModifiedCompliance- ComplianceSOS-
Compliance De-emphasis: -6dB
LnkSta2: Current De-emphasis Level: -3.5dB, EqualizationComplete-,
EqualizationPhase1-
EqualizationPhase2-, EqualizationPhase3-, LinkEqualizationRequest-
Capabilities: [80] MSI: Enable+ Count=1/1 Maskable- 64bit-
Address: fee0f00c  Data: 4171
Capabilities: [90] Subsystem: ASUSTeK Computer Inc. Device 14fd
Capabilities: [a0] Power Management version 3
Flags: PMEClk- DSI- D1- D2- AuxCurrent=0mA PME(D0+,D1-,D2-,D3hot+,D3cold+)
Status: D0 NoSoftRst- PME-Enable- DSel=0 DScale=0 PME-
Kernel driver in use: pcieport

00:1c.2 PCI bridge: Intel Corporation Lynx Point-LP PCI Express Root
Port 3 (rev e4) (prog-if 00 [Normal decode])
Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr-
Stepping- SERR- FastB2B- DisINTx+
Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort-
<TAbort- <MAbort- >SERR- <PERR- INTx-
Latency: 0, Cache Line Size: 64 bytes
Bus: primary=00, secondary=02, subordinate=02, sec-latency=0
I/O behind bridge: 0000f000-00000fff
Memory behind bridge: f7900000-f79fffff
Prefetchable memory behind bridge: 00000000fff00000-00000000000fffff
Secondary status: 66MHz- FastB2B- ParErr- DEVSEL=fast >TAbort-
<TAbort- <MAbort- <SERR- <PERR-
BridgeCtl: Parity- SERR- NoISA- VGA- MAbort- >Reset- FastB2B-
PriDiscTmr- SecDiscTmr- DiscTmrStat- DiscTmrSERREn-
Capabilities: [40] Express (v2) Root Port (Slot+), MSI 00
DevCap: MaxPayload 128 bytes, PhantFunc 0
ExtTag- RBE+
DevCtl: Report errors: Correctable- Non-Fatal- Fatal- Unsupported-
RlxdOrd- ExtTag- PhantFunc- AuxPwr- NoSnoop-
MaxPayload 128 bytes, MaxReadReq 128 bytes
DevSta: CorrErr- UncorrErr- FatalErr- UnsuppReq- AuxPwr+ TransPend-
LnkCap: Port #3, Speed 5GT/s, Width x1, ASPM L0s L1, Exit Latency L0s
<512ns, L1 <16us
ClockPM- Surprise- LLActRep+ BwNot+
LnkCtl: ASPM L0s L1 Enabled; RCB 64 bytes Disabled- CommClk+
ExtSynch- ClockPM- AutWidDis- BWInt- AutBWInt-
LnkSta: Speed 2.5GT/s, Width x1, TrErr- Train- SlotClk+ DLActive+
BWMgmt+ ABWMgmt-
SltCap: AttnBtn- PwrCtrl- MRL- AttnInd- PwrInd- HotPlug- Surprise-
Slot #2, PowerLimit 10.000W; Interlock- NoCompl+
SltCtl: Enable: AttnBtn- PwrFlt- MRL- PresDet- CmdCplt- HPIrq- LinkChg-
Control: AttnInd Unknown, PwrInd Unknown, Power- Interlock-
SltSta: Status: AttnBtn- PowerFlt- MRL- CmdCplt- PresDet+ Interlock-
Changed: MRL- PresDet- LinkState-
RootCtl: ErrCorrectable- ErrNon-Fatal- ErrFatal- PMEIntEna+ CRSVisible-
RootCap: CRSVisible-
RootSta: PME ReqID 0000, PMEStatus- PMEPending-
DevCap2: Completion Timeout: Range ABC, TimeoutDis+, LTR+, OBFF Not
Supported ARIFwd-
DevCtl2: Completion Timeout: 50us to 50ms, TimeoutDis-, LTR+, OBFF
Disabled ARIFwd-
LnkCtl2: Target Link Speed: 5GT/s, EnterCompliance- SpeedDis-
Transmit Margin: Normal Operating Range, EnterModifiedCompliance- ComplianceSOS-
Compliance De-emphasis: -6dB
LnkSta2: Current De-emphasis Level: -3.5dB, EqualizationComplete-,
EqualizationPhase1-
EqualizationPhase2-, EqualizationPhase3-, LinkEqualizationRequest-
Capabilities: [80] MSI: Enable+ Count=1/1 Maskable- 64bit-
Address: fee0f00c  Data: 4191
Capabilities: [90] Subsystem: ASUSTeK Computer Inc. Device 14fd
Capabilities: [a0] Power Management version 3
Flags: PMEClk- DSI- D1- D2- AuxCurrent=0mA PME(D0+,D1-,D2-,D3hot+,D3cold+)
Status: D0 NoSoftRst- PME-Enable- DSel=0 DScale=0 PME-
Capabilities: [100 v0] #00
Capabilities: [200 v1] L1 PM Substates
L1SubCap: PCI-PM_L1.2+ PCI-PM_L1.1+ ASPM_L1.2+ ASPM_L1.1+ L1_PM_Substates+
 PortCommonModeRestoreTime=40us PortTPowerOnTime=10us
Kernel driver in use: pcieport

00:1c.3 PCI bridge: Intel Corporation Lynx Point-LP PCI Express Root
Port 4 (rev e4) (prog-if 00 [Normal decode])
Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr-
Stepping- SERR- FastB2B- DisINTx+
Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort-
<TAbort- <MAbort- >SERR- <PERR- INTx-
Latency: 0, Cache Line Size: 64 bytes
Bus: primary=00, secondary=03, subordinate=03, sec-latency=0
I/O behind bridge: 0000e000-0000efff
Memory behind bridge: f7800000-f78fffff
Prefetchable memory behind bridge: 00000000f2100000-00000000f21fffff
Secondary status: 66MHz- FastB2B- ParErr- DEVSEL=fast >TAbort-
<TAbort- <MAbort- <SERR- <PERR-
BridgeCtl: Parity- SERR- NoISA- VGA- MAbort- >Reset- FastB2B-
PriDiscTmr- SecDiscTmr- DiscTmrStat- DiscTmrSERREn-
Capabilities: [40] Express (v2) Root Port (Slot+), MSI 00
DevCap: MaxPayload 128 bytes, PhantFunc 0
ExtTag- RBE+
DevCtl: Report errors: Correctable- Non-Fatal- Fatal- Unsupported-
RlxdOrd- ExtTag- PhantFunc- AuxPwr- NoSnoop-
MaxPayload 128 bytes, MaxReadReq 128 bytes
DevSta: CorrErr- UncorrErr- FatalErr- UnsuppReq- AuxPwr+ TransPend-
LnkCap: Port #4, Speed 5GT/s, Width x1, ASPM L0s L1, Exit Latency L0s
<512ns, L1 <16us
ClockPM- Surprise- LLActRep+ BwNot+
LnkCtl: ASPM Disabled; RCB 64 bytes Disabled- CommClk+
ExtSynch- ClockPM- AutWidDis- BWInt- AutBWInt-
LnkSta: Speed 2.5GT/s, Width x1, TrErr- Train- SlotClk+ DLActive+
BWMgmt+ ABWMgmt-
SltCap: AttnBtn- PwrCtrl- MRL- AttnInd- PwrInd- HotPlug- Surprise-
Slot #3, PowerLimit 10.000W; Interlock- NoCompl+
SltCtl: Enable: AttnBtn- PwrFlt- MRL- PresDet- CmdCplt- HPIrq- LinkChg-
Control: AttnInd Unknown, PwrInd Unknown, Power- Interlock-
SltSta: Status: AttnBtn- PowerFlt- MRL- CmdCplt- PresDet+ Interlock-
Changed: MRL- PresDet- LinkState-
RootCtl: ErrCorrectable- ErrNon-Fatal- ErrFatal- PMEIntEna+ CRSVisible-
RootCap: CRSVisible-
RootSta: PME ReqID 0000, PMEStatus- PMEPending-
DevCap2: Completion Timeout: Range ABC, TimeoutDis+, LTR+, OBFF Not
Supported ARIFwd-
DevCtl2: Completion Timeout: 50us to 50ms, TimeoutDis-, LTR+, OBFF
Disabled ARIFwd-
LnkCtl2: Target Link Speed: 5GT/s, EnterCompliance- SpeedDis-
Transmit Margin: Normal Operating Range, EnterModifiedCompliance- ComplianceSOS-
Compliance De-emphasis: -6dB
LnkSta2: Current De-emphasis Level: -3.5dB, EqualizationComplete-,
EqualizationPhase1-
EqualizationPhase2-, EqualizationPhase3-, LinkEqualizationRequest-
Capabilities: [80] MSI: Enable+ Count=1/1 Maskable- 64bit-
Address: fee0f00c  Data: 41b1
Capabilities: [90] Subsystem: ASUSTeK Computer Inc. Device 14fd
Capabilities: [a0] Power Management version 3
Flags: PMEClk- DSI- D1- D2- AuxCurrent=0mA PME(D0+,D1-,D2-,D3hot+,D3cold+)
Status: D0 NoSoftRst- PME-Enable- DSel=0 DScale=0 PME-
Capabilities: [100 v0] #00
Capabilities: [200 v1] L1 PM Substates
L1SubCap: PCI-PM_L1.2+ PCI-PM_L1.1+ ASPM_L1.2+ ASPM_L1.1+ L1_PM_Substates+
 PortCommonModeRestoreTime=40us PortTPowerOnTime=10us
Kernel driver in use: pcieport

00:1c.4 PCI bridge: Intel Corporation Lynx Point-LP PCI Express Root
Port 5 (rev e4) (prog-if 00 [Normal decode])
Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr-
Stepping- SERR- FastB2B- DisINTx+
Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort-
<TAbort- <MAbort- >SERR- <PERR- INTx-
Latency: 0, Cache Line Size: 64 bytes
Bus: primary=00, secondary=04, subordinate=04, sec-latency=0
I/O behind bridge: 0000d000-0000dfff
Memory behind bridge: f6000000-f70fffff
Prefetchable memory behind bridge: 00000000e0000000-00000000f1ffffff
Secondary status: 66MHz- FastB2B- ParErr- DEVSEL=fast >TAbort-
<TAbort- <MAbort+ <SERR- <PERR-
BridgeCtl: Parity- SERR- NoISA- VGA- MAbort- >Reset- FastB2B-
PriDiscTmr- SecDiscTmr- DiscTmrStat- DiscTmrSERREn-
Capabilities: [40] Express (v2) Root Port (Slot+), MSI 00
DevCap: MaxPayload 128 bytes, PhantFunc 0
ExtTag- RBE+
DevCtl: Report errors: Correctable- Non-Fatal- Fatal- Unsupported-
RlxdOrd- ExtTag- PhantFunc- AuxPwr- NoSnoop-
MaxPayload 128 bytes, MaxReadReq 128 bytes
DevSta: CorrErr- UncorrErr- FatalErr- UnsuppReq- AuxPwr+ TransPend-
LnkCap: Port #5, Speed 5GT/s, Width x4, ASPM L0s L1, Exit Latency L0s
<512ns, L1 <16us
ClockPM- Surprise- LLActRep+ BwNot+
LnkCtl: ASPM Disabled; RCB 64 bytes Disabled- CommClk+
ExtSynch- ClockPM- AutWidDis- BWInt- AutBWInt-
LnkSta: Speed 5GT/s, Width x4, TrErr- Train- SlotClk+ DLActive+ BWMgmt+ ABWMgmt-
SltCap: AttnBtn- PwrCtrl- MRL- AttnInd- PwrInd- HotPlug- Surprise-
Slot #4, PowerLimit 25.000W; Interlock- NoCompl+
SltCtl: Enable: AttnBtn- PwrFlt- MRL- PresDet- CmdCplt- HPIrq- LinkChg-
Control: AttnInd Unknown, PwrInd Unknown, Power- Interlock-
SltSta: Status: AttnBtn- PowerFlt- MRL- CmdCplt- PresDet+ Interlock-
Changed: MRL- PresDet- LinkState-
RootCtl: ErrCorrectable- ErrNon-Fatal- ErrFatal- PMEIntEna+ CRSVisible-
RootCap: CRSVisible-
RootSta: PME ReqID 0000, PMEStatus- PMEPending-
DevCap2: Completion Timeout: Range ABC, TimeoutDis+, LTR+, OBFF Not
Supported ARIFwd-
DevCtl2: Completion Timeout: 50us to 50ms, TimeoutDis-, LTR+, OBFF
Disabled ARIFwd-
LnkCtl2: Target Link Speed: 5GT/s, EnterCompliance- SpeedDis-
Transmit Margin: Normal Operating Range, EnterModifiedCompliance- ComplianceSOS-
Compliance De-emphasis: -6dB
LnkSta2: Current De-emphasis Level: -6dB, EqualizationComplete-,
EqualizationPhase1-
EqualizationPhase2-, EqualizationPhase3-, LinkEqualizationRequest-
Capabilities: [80] MSI: Enable+ Count=1/1 Maskable- 64bit-
Address: fee0f00c  Data: 41c1
Capabilities: [90] Subsystem: ASUSTeK Computer Inc. Device 14fd
Capabilities: [a0] Power Management version 3
Flags: PMEClk- DSI- D1- D2- AuxCurrent=0mA PME(D0+,D1-,D2-,D3hot+,D3cold+)
Status: D0 NoSoftRst- PME-Enable- DSel=0 DScale=0 PME-
Capabilities: [100 v0] #00
Capabilities: [200 v1] L1 PM Substates
L1SubCap: PCI-PM_L1.2+ PCI-PM_L1.1+ ASPM_L1.2+ ASPM_L1.1+ L1_PM_Substates+
 PortCommonModeRestoreTime=40us PortTPowerOnTime=10us
Kernel driver in use: pcieport

00:1d.0 USB controller: Intel Corporation Lynx Point-LP USB EHCI #1
(rev 04) (prog-if 20 [EHCI])
Subsystem: ASUSTeK Computer Inc. Device 14fd
Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr-
Stepping- SERR- FastB2B- DisINTx-
Status: Cap+ 66MHz- UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort-
<TAbort- <MAbort- >SERR- <PERR- INTx-
Latency: 0
Interrupt: pin A routed to IRQ 23
Region 0: Memory at f7a1b000 (32-bit, non-prefetchable) [size=1K]
Capabilities: [50] Power Management version 3
Flags: PMEClk- DSI- D1- D2- AuxCurrent=375mA PME(D0+,D1-,D2-,D3hot+,D3cold+)
Status: D0 NoSoftRst+ PME-Enable- DSel=0 DScale=0 PME-
Capabilities: [58] Debug port: BAR=1 offset=00a0
Capabilities: [98] PCI Advanced Features
AFCap: TP+ FLR+
AFCtrl: FLR-
AFStatus: TP-
Kernel driver in use: ehci-pci

00:1f.0 ISA bridge: Intel Corporation Lynx Point-LP LPC Controller (rev 04)
Subsystem: ASUSTeK Computer Inc. Device 14fd
Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr-
Stepping- SERR- FastB2B- DisINTx-
Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=medium >TAbort-
<TAbort- <MAbort- >SERR- <PERR- INTx-
Latency: 0
Capabilities: [e0] Vendor Specific Information: Len=0c <?>
Kernel driver in use: lpc_ich

00:1f.2 SATA controller: Intel Corporation Lynx Point-LP SATA
Controller 1 [AHCI mode] (rev 04) (prog-if 01 [AHCI 1.0])
Subsystem: ASUSTeK Computer Inc. Device 14fd
Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr-
Stepping- SERR- FastB2B- DisINTx+
Status: Cap+ 66MHz+ UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort-
<TAbort- <MAbort- >SERR- <PERR- INTx-
Latency: 0
Interrupt: pin B routed to IRQ 45
Region 0: I/O ports at f0b0 [size=8]
Region 1: I/O ports at f0a0 [size=4]
Region 2: I/O ports at f090 [size=8]
Region 3: I/O ports at f080 [size=4]
Region 4: I/O ports at f060 [size=32]
Region 5: Memory at f7a1a000 (32-bit, non-prefetchable) [size=2K]
Capabilities: [80] MSI: Enable+ Count=1/1 Maskable- 64bit-
Address: fee0500c  Data: 4122
Capabilities: [70] Power Management version 3
Flags: PMEClk- DSI- D1- D2- AuxCurrent=0mA PME(D0-,D1-,D2-,D3hot+,D3cold-)
Status: D0 NoSoftRst+ PME-Enable- DSel=0 DScale=0 PME-
Capabilities: [a8] SATA HBA v1.0 BAR4 Offset=00000004
Kernel driver in use: ahci

00:1f.3 SMBus: Intel Corporation Lynx Point-LP SMBus Controller (rev 04)
Subsystem: ASUSTeK Computer Inc. Device 14fd
Control: I/O+ Mem+ BusMaster- SpecCycle- MemWINV- VGASnoop- ParErr-
Stepping- SERR- FastB2B- DisINTx-
Status: Cap- 66MHz- UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort-
<TAbort- <MAbort- >SERR- <PERR- INTx-
Interrupt: pin C routed to IRQ 3
Region 0: Memory at f7a19000 (64-bit, non-prefetchable) [size=256]
Region 4: I/O ports at f040 [size=32]

02:00.0 Network controller: Broadcom Corporation BCM43142 802.11b/g/n (rev 01)
Subsystem: Lite-On Communications Inc Device 6605
Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr-
Stepping- SERR- FastB2B- DisINTx-
Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort-
<TAbort- <MAbort- >SERR- <PERR- INTx-
Latency: 0, Cache Line Size: 64 bytes
Interrupt: pin A routed to IRQ 3
Region 0: Memory at f7900000 (64-bit, non-prefetchable) [size=32K]
Capabilities: [40] Power Management version 3
Flags: PMEClk- DSI- D1+ D2+ AuxCurrent=0mA PME(D0+,D1-,D2-,D3hot+,D3cold+)
Status: D0 NoSoftRst+ PME-Enable- DSel=0 DScale=2 PME-
Capabilities: [58] Vendor Specific Information: Len=78 <?>
Capabilities: [48] MSI: Enable- Count=1/1 Maskable- 64bit+
Address: 0000000000000000  Data: 0000
Capabilities: [d0] Express (v1) Endpoint, MSI 00
DevCap: MaxPayload 128 bytes, PhantFunc 0, Latency L0s <4us, L1 unlimited
ExtTag+ AttnBtn- AttnInd- PwrInd- RBE+ FLReset-
DevCtl: Report errors: Correctable- Non-Fatal- Fatal- Unsupported-
RlxdOrd- ExtTag- PhantFunc- AuxPwr- NoSnoop-
MaxPayload 128 bytes, MaxReadReq 512 bytes
DevSta: CorrErr- UncorrErr- FatalErr- UnsuppReq- AuxPwr+ TransPend-
LnkCap: Port #0, Speed 2.5GT/s, Width x1, ASPM L0s L1, Exit Latency
L0s <4us, L1 <64us
ClockPM+ Surprise- LLActRep- BwNot-
LnkCtl: ASPM L0s L1 Enabled; RCB 64 bytes Disabled- CommClk+
ExtSynch- ClockPM+ AutWidDis- BWInt- AutBWInt-
LnkSta: Speed 2.5GT/s, Width x1, TrErr- Train- SlotClk+ DLActive-
BWMgmt- ABWMgmt-
Capabilities: [100 v1] Advanced Error Reporting
UESta: DLP- SDES- TLP- FCP- CmpltTO- CmpltAbrt- UnxCmplt- RxOF-
MalfTLP- ECRC- UnsupReq- ACSViol-
UEMsk: DLP- SDES- TLP- FCP- CmpltTO- CmpltAbrt- UnxCmplt- RxOF-
MalfTLP- ECRC- UnsupReq- ACSViol-
UESvrt: DLP+ SDES+ TLP- FCP+ CmpltTO- CmpltAbrt- UnxCmplt- RxOF+
MalfTLP+ ECRC- UnsupReq- ACSViol-
CESta: RxErr+ BadTLP+ BadDLLP- Rollover- Timeout- NonFatalErr-
CEMsk: RxErr- BadTLP- BadDLLP- Rollover- Timeout- NonFatalErr+
AERCap: First Error Pointer: 00, GenCap+ CGenEn- ChkCap+ ChkEn-
Capabilities: [13c v1] Virtual Channel
Caps: LPEVC=0 RefClk=100ns PATEntryBits=1
Arb: Fixed- WRR32- WRR64- WRR128-
Ctrl: ArbSelect=Fixed
Status: InProgress-
VC0: Caps: PATOffset=00 MaxTimeSlots=1 RejSnoopTrans-
Arb: Fixed- WRR32- WRR64- WRR128- TWRR128- WRR256-
Ctrl: Enable+ ID=0 ArbSelect=Fixed TC/VC=01
Status: NegoPending- InProgress-
Capabilities: [160 v1] Device Serial Number 00-00-5e-ff-ff-82-18-cf
Capabilities: [16c v1] Power Budgeting <?>

03:00.0 Ethernet controller: Realtek Semiconductor Co., Ltd.
RTL8111/8168/8411 PCI Express Gigabit Ethernet Controller (rev 0c)
Subsystem: ASUSTeK Computer Inc. Device 200f
Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr-
Stepping- SERR- FastB2B- DisINTx+
Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort-
<TAbort- <MAbort- >SERR- <PERR- INTx-
Latency: 0, Cache Line Size: 64 bytes
Interrupt: pin A routed to IRQ 46
Region 0: I/O ports at e000 [size=256]
Region 2: Memory at f7800000 (64-bit, non-prefetchable) [size=4K]
Region 4: Memory at f2100000 (64-bit, prefetchable) [size=16K]
Capabilities: [40] Power Management version 3
Flags: PMEClk- DSI- D1+ D2+ AuxCurrent=375mA PME(D0+,D1+,D2+,D3hot+,D3cold+)
Status: D0 NoSoftRst+ PME-Enable- DSel=0 DScale=0 PME-
Capabilities: [50] MSI: Enable+ Count=1/1 Maskable- 64bit+
Address: 00000000fee0200c  Data: 4142
Capabilities: [70] Express (v2) Endpoint, MSI 01
DevCap: MaxPayload 128 bytes, PhantFunc 0, Latency L0s <512ns, L1 <64us
ExtTag- AttnBtn- AttnInd- PwrInd- RBE+ FLReset-
DevCtl: Report errors: Correctable- Non-Fatal- Fatal- Unsupported-
RlxdOrd- ExtTag- PhantFunc- AuxPwr- NoSnoop-
MaxPayload 128 bytes, MaxReadReq 4096 bytes
DevSta: CorrErr- UncorrErr- FatalErr- UnsuppReq- AuxPwr+ TransPend-
LnkCap: Port #0, Speed 2.5GT/s, Width x1, ASPM L0s L1, Exit Latency
L0s unlimited, L1 <64us
ClockPM+ Surprise- LLActRep- BwNot-
LnkCtl: ASPM Disabled; RCB 64 bytes Disabled- CommClk+
ExtSynch- ClockPM- AutWidDis- BWInt- AutBWInt-
LnkSta: Speed 2.5GT/s, Width x1, TrErr- Train- SlotClk+ DLActive-
BWMgmt- ABWMgmt-
DevCap2: Completion Timeout: Range ABCD, TimeoutDis+, LTR+, OBFF Via
message/WAKE#
DevCtl2: Completion Timeout: 50us to 50ms, TimeoutDis-, LTR+, OBFF Disabled
LnkCtl2: Target Link Speed: 2.5GT/s, EnterCompliance- SpeedDis-
Transmit Margin: Normal Operating Range, EnterModifiedCompliance- ComplianceSOS-
Compliance De-emphasis: -6dB
LnkSta2: Current De-emphasis Level: -6dB, EqualizationComplete-,
EqualizationPhase1-
EqualizationPhase2-, EqualizationPhase3-, LinkEqualizationRequest-
Capabilities: [b0] MSI-X: Enable- Count=4 Masked-
Vector table: BAR=4 offset=00000000
PBA: BAR=4 offset=00000800
Capabilities: [d0] Vital Product Data
Unknown small resource type 00, will not decode more.
Capabilities: [100 v1] Advanced Error Reporting
UESta: DLP- SDES- TLP- FCP- CmpltTO- CmpltAbrt- UnxCmplt- RxOF-
MalfTLP- ECRC- UnsupReq- ACSViol-
UEMsk: DLP- SDES- TLP- FCP- CmpltTO- CmpltAbrt- UnxCmplt- RxOF-
MalfTLP- ECRC- UnsupReq- ACSViol-
UESvrt: DLP+ SDES+ TLP- FCP+ CmpltTO- CmpltAbrt- UnxCmplt- RxOF+
MalfTLP+ ECRC- UnsupReq- ACSViol-
CESta: RxErr- BadTLP- BadDLLP- Rollover- Timeout- NonFatalErr-
CEMsk: RxErr- BadTLP- BadDLLP- Rollover- Timeout- NonFatalErr+
AERCap: First Error Pointer: 00, GenCap+ CGenEn- ChkCap+ ChkEn-
Capabilities: [140 v1] Virtual Channel
Caps: LPEVC=0 RefClk=100ns PATEntryBits=1
Arb: Fixed- WRR32- WRR64- WRR128-
Ctrl: ArbSelect=Fixed
Status: InProgress-
VC0: Caps: PATOffset=00 MaxTimeSlots=1 RejSnoopTrans-
Arb: Fixed- WRR32- WRR64- WRR128- TWRR128- WRR256-
Ctrl: Enable+ ID=0 ArbSelect=Fixed TC/VC=01
Status: NegoPending- InProgress-
Capabilities: [160 v1] Device Serial Number 01-00-00-00-68-4c-e0-00
Capabilities: [170 v1] Latency Tolerance Reporting
Max snoop latency: 3145728ns
Max no snoop latency: 3145728ns
Kernel driver in use: r8169

04:00.0 3D controller: NVIDIA Corporation GM108M [GeForce 840M] (rev a2)
Subsystem: ASUSTeK Computer Inc. Device 14fd
Control: I/O+ Mem+ BusMaster- SpecCycle- MemWINV- VGASnoop- ParErr-
Stepping- SERR- FastB2B- DisINTx-
Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort-
<TAbort- <MAbort- >SERR- <PERR- INTx-
Interrupt: pin A routed to IRQ 16
Region 0: Memory at f6000000 (32-bit, non-prefetchable) [size=16M]
Region 1: Memory at e0000000 (64-bit, prefetchable) [size=256M]
Region 3: Memory at f0000000 (64-bit, prefetchable) [size=32M]
Region 5: I/O ports at d000 [size=128]
Expansion ROM at f7000000 [disabled] [size=512K]
Capabilities: [60] Power Management version 3
Flags: PMEClk- DSI- D1- D2- AuxCurrent=0mA PME(D0-,D1-,D2-,D3hot-,D3cold-)
Status: D0 NoSoftRst+ PME-Enable- DSel=0 DScale=0 PME-
Capabilities: [68] MSI: Enable- Count=1/1 Maskable- 64bit+
Address: 0000000000000000  Data: 0000
Capabilities: [78] Express (v2) Endpoint, MSI 00
DevCap: MaxPayload 256 bytes, PhantFunc 0, Latency L0s unlimited, L1 <64us
ExtTag+ AttnBtn- AttnInd- PwrInd- RBE+ FLReset-
DevCtl: Report errors: Correctable- Non-Fatal- Fatal- Unsupported-
RlxdOrd- ExtTag- PhantFunc- AuxPwr- NoSnoop+
MaxPayload 128 bytes, MaxReadReq 512 bytes
DevSta: CorrErr- UncorrErr- FatalErr- UnsuppReq- AuxPwr- TransPend-
LnkCap: Port #0, Speed 8GT/s, Width x4, ASPM L0s L1, Exit Latency L0s
<512ns, L1 <4us
ClockPM+ Surprise- LLActRep- BwNot-
LnkCtl: ASPM Disabled; RCB 64 bytes Disabled- CommClk+
ExtSynch- ClockPM+ AutWidDis- BWInt- AutBWInt-
LnkSta: Speed 5GT/s, Width x4, TrErr- Train- SlotClk+ DLActive- BWMgmt- ABWMgmt-
DevCap2: Completion Timeout: Range AB, TimeoutDis+, LTR+, OBFF Via message
DevCtl2: Completion Timeout: 50us to 50ms, TimeoutDis-, LTR+, OBFF Disabled
LnkCtl2: Target Link Speed: 8GT/s, EnterCompliance- SpeedDis-
Transmit Margin: Normal Operating Range, EnterModifiedCompliance- ComplianceSOS-
Compliance De-emphasis: -6dB
LnkSta2: Current De-emphasis Level: -6dB, EqualizationComplete-,
EqualizationPhase1-
EqualizationPhase2-, EqualizationPhase3-, LinkEqualizationRequest-
Capabilities: [100 v1] Virtual Channel
Caps: LPEVC=0 RefClk=100ns PATEntryBits=1
Arb: Fixed- WRR32- WRR64- WRR128-
Ctrl: ArbSelect=Fixed
Status: InProgress-
VC0: Caps: PATOffset=00 MaxTimeSlots=1 RejSnoopTrans-
Arb: Fixed- WRR32- WRR64- WRR128- TWRR128- WRR256-
Ctrl: Enable+ ID=0 ArbSelect=Fixed TC/VC=01
Status: NegoPending- InProgress-
Capabilities: [250 v1] Latency Tolerance Reporting
Max snoop latency: 3145728ns
Max no snoop latency: 3145728ns
Capabilities: [258 v1] L1 PM Substates
L1SubCap: PCI-PM_L1.2+ PCI-PM_L1.1+ ASPM_L1.2+ ASPM_L1.1+ L1_PM_Substates+
 PortCommonModeRestoreTime=255us PortTPowerOnTime=10us
Capabilities: [128 v1] Power Budgeting <?>
Capabilities: [600 v1] Vendor Specific Information: ID=0001 Rev=1 Len=024 <?>
Capabilities: [900 v1] #19

[7.6.] SCSI information (from /proc/scsi/scsi):
Attached devices:
Host: scsi0 Channel: 00 Id: 00 Lun: 00
  Vendor: ATA      Model: ST1000LM024 HN-M Rev: 0001
  Type:   Direct-Access                    ANSI  SCSI revision: 05
Host: scsi1 Channel: 00 Id: 00 Lun: 00
  Vendor: ATA      Model: CORSAIR FORCE LX Rev: 7A
  Type:   Direct-Access                    ANSI  SCSI revision: 05
Host: scsi2 Channel: 00 Id: 00 Lun: 00
  Vendor: HL-DT-ST Model: DVDRAM GUA0N     Rev: AS00
  Type:   CD-ROM                           ANSI  SCSI revision: 05
Host: scsi3 Channel: 00 Id: 00 Lun: 00
  Vendor: Multiple Model: Card  Reader     Rev: 1.00
  Type:   Direct-Access                    ANSI  SCSI revision: 04

[7.7.] Other information that might be relevant to the problem (please
look in /proc and include all information that you think to be
relevant):
Downstream report may be found at
https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1371914 .

No results executing at a terminal:
cat /proc/bus/input/devices | grep Touch

^ permalink raw reply

* Re: PROBLEM: [Asus X750LN] Touchpad not recognized
From: Benjamin Tissoires @ 2014-09-23 14:13 UTC (permalink / raw)
  To: Nikola Nikolov; +Cc: linux-input, Hans de Goede
In-Reply-To: <CAOwx47d=vnxu=a2nE8d3s4LJ=2RNpPzCyuhJi-gicdA5FaBL6w@mail.gmail.com>

Hi Nikola,

there are big chances that you have the same touchpad/problem that the
X550 users have.
We are working on it with this bugzilla:
https://bugzilla.redhat.com/show_bug.cgi?id=1110011

I guess that if adding "psmouse.proto=bare" to the kernel parameter
makes your touchpad working, then you are in the same situation (see
comment 46).

Feel free to also add the files requested by Hans in comment 92.

Cheers,
Benjamin


On Tue, Sep 23, 2014 at 7:30 AM, Nikola Nikolov <nikolov.tmw@gmail.com> wrote:
> [1.] One line summary of the problem:
> [Asus X750LN] Touchpad not recognized
>
> [2.] Full description of the problem/report:
> Running the latest mainline kernel, the touchpad on my laptop is not
> recognized at all - it's not listed as an input device and nothing
> happens whenever I try using it.
>
> [3.] Keywords:
>
> [4.] Kernel version (from /proc/version):
> Linux version 3.17.0-031700rc6-generic (apw@gomeisa) (gcc version
> 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5) ) #201409211935 SMP Sun Sep 21
> 23:37:11 UTC 2014
>
> [5.] Output of Oops.. message (if applicable) with symbolic
> information resolved (see Documentation/oops-tracing.txt):
> N/A
>
> [6.] A small shell script or example program which triggers the
> problem (if possible):
> N/A
>
> [7.] Environment:
> Description: Ubuntu 14.04.1 LTS
> Release: 14.04
>
> [7.1.] Software (add the output of the ver_linux script here):
> If some fields are empty or look unusual you may have an old version.
> Compare to the current minimal requirements in Documentation/Changes.
>
> Linux moonwatch-laptop 3.17.0-031700rc6-generic #201409211935 SMP Sun
> Sep 21 23:37:11 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux
>
> Gnu C                  4.8
> Gnu make               3.81
> binutils               2.24
> util-linux             2.20.1
> mount                  support
> module-init-tools      15
> e2fsprogs              1.42.9
> pcmciautils            018
> PPP                    2.4.5
> Linux C Library        2.19
> Dynamic linker (ldd)   2.19
> Procps                 3.3.9
> Net-tools              1.60
> Kbd                    1.15.5
> Sh-utils               8.21
> wireless-tools         30
> Modules Loaded         snd_hda_codec_realtek snd_hda_codec_hdmi
> snd_hda_codec_generic bnep rfcomm bluetooth joydev hid_generic
> asus_nb_wmi asus_wmi sparse_keymap intel_rapl x86_pkg_temp_thermal
> intel_powerclamp coretemp kvm_intel kvm crct10dif_pclmul crc32_pclmul
> ghash_clmulni_intel aesni_intel aes_x86_64 lrw gf128mul glue_helper
> ablk_helper cryptd uvcvideo videobuf2_vmalloc serio_raw
> videobuf2_memops videobuf2_core uas v4l2_common nouveau usb_storage
> videodev media usbhid lpc_ich mxm_wmi ttm mei_me mei snd_soc_rt5640
> snd_soc_rl6231 snd_soc_core i2c_hid dw_dmac snd_soc_sst_acpi hid
> snd_compress dw_dmac_core snd_pcm_dmaengine 8250_dw
> i2c_designware_platform mac_hid i2c_designware_core
> spi_pxa2xx_platform wmi snd_hda_intel snd_hda_controller snd_hda_codec
> snd_hwdep snd_pcm i915 snd_seq_midi snd_seq_midi_event snd_rawmidi
> snd_seq video snd_seq_device snd_timer drm_kms_helper drm snd
> soundcore i2c_algo_bit parport_pc ppdev lp parport ahci r8169 libahci
> mii sdhci_acpi sdhci
>
> [7.2.] Processor information (from /proc/cpuinfo):
> processor : 0
> vendor_id : GenuineIntel
> cpu family : 6
> model : 69
> model name : Intel(R) Core(TM) i7-4510U CPU @ 2.00GHz
> stepping : 1
> microcode : 0x17
> cpu MHz : 2003.015
> cache size : 4096 KB
> physical id : 0
> siblings : 4
> core id : 0
> cpu cores : 2
> apicid : 0
> initial apicid : 0
> fpu : yes
> fpu_exception : yes
> cpuid level : 13
> wp : yes
> flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov
> pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx
> pdpe1gb rdtscp lm constant_tsc arch_perfmon pebs bts rep_good nopl
> xtopology nonstop_tsc aperfmperf eagerfpu pni pclmulqdq dtes64 monitor
> ds_cpl vmx est tm2 ssse3 fma cx16 xtpr pdcm pcid sse4_1 sse4_2 movbe
> popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm ida
> arat epb pln pts dtherm tpr_shadow vnmi flexpriority ept vpid fsgsbase
> tsc_adjust bmi1 avx2 smep bmi2 erms invpcid xsaveopt
> bugs :
> bogomips : 5188.24
> clflush size : 64
> cache_alignment : 64
> address sizes : 39 bits physical, 48 bits virtual
> power management:
>
> processor : 1
> vendor_id : GenuineIntel
> cpu family : 6
> model : 69
> model name : Intel(R) Core(TM) i7-4510U CPU @ 2.00GHz
> stepping : 1
> microcode : 0x17
> cpu MHz : 1999.968
> cache size : 4096 KB
> physical id : 0
> siblings : 4
> core id : 1
> cpu cores : 2
> apicid : 2
> initial apicid : 2
> fpu : yes
> fpu_exception : yes
> cpuid level : 13
> wp : yes
> flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov
> pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx
> pdpe1gb rdtscp lm constant_tsc arch_perfmon pebs bts rep_good nopl
> xtopology nonstop_tsc aperfmperf eagerfpu pni pclmulqdq dtes64 monitor
> ds_cpl vmx est tm2 ssse3 fma cx16 xtpr pdcm pcid sse4_1 sse4_2 movbe
> popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm ida
> arat epb pln pts dtherm tpr_shadow vnmi flexpriority ept vpid fsgsbase
> tsc_adjust bmi1 avx2 smep bmi2 erms invpcid xsaveopt
> bugs :
> bogomips : 5188.24
> clflush size : 64
> cache_alignment : 64
> address sizes : 39 bits physical, 48 bits virtual
> power management:
>
> processor : 2
> vendor_id : GenuineIntel
> cpu family : 6
> model : 69
> model name : Intel(R) Core(TM) i7-4510U CPU @ 2.00GHz
> stepping : 1
> microcode : 0x17
> cpu MHz : 2000.070
> cache size : 4096 KB
> physical id : 0
> siblings : 4
> core id : 0
> cpu cores : 2
> apicid : 1
> initial apicid : 1
> fpu : yes
> fpu_exception : yes
> cpuid level : 13
> wp : yes
> flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov
> pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx
> pdpe1gb rdtscp lm constant_tsc arch_perfmon pebs bts rep_good nopl
> xtopology nonstop_tsc aperfmperf eagerfpu pni pclmulqdq dtes64 monitor
> ds_cpl vmx est tm2 ssse3 fma cx16 xtpr pdcm pcid sse4_1 sse4_2 movbe
> popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm ida
> arat epb pln pts dtherm tpr_shadow vnmi flexpriority ept vpid fsgsbase
> tsc_adjust bmi1 avx2 smep bmi2 erms invpcid xsaveopt
> bugs :
> bogomips : 5188.24
> clflush size : 64
> cache_alignment : 64
> address sizes : 39 bits physical, 48 bits virtual
> power management:
>
> processor : 3
> vendor_id : GenuineIntel
> cpu family : 6
> model : 69
> model name : Intel(R) Core(TM) i7-4510U CPU @ 2.00GHz
> stepping : 1
> microcode : 0x17
> cpu MHz : 2844.156
> cache size : 4096 KB
> physical id : 0
> siblings : 4
> core id : 1
> cpu cores : 2
> apicid : 3
> initial apicid : 3
> fpu : yes
> fpu_exception : yes
> cpuid level : 13
> wp : yes
> flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov
> pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx
> pdpe1gb rdtscp lm constant_tsc arch_perfmon pebs bts rep_good nopl
> xtopology nonstop_tsc aperfmperf eagerfpu pni pclmulqdq dtes64 monitor
> ds_cpl vmx est tm2 ssse3 fma cx16 xtpr pdcm pcid sse4_1 sse4_2 movbe
> popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm ida
> arat epb pln pts dtherm tpr_shadow vnmi flexpriority ept vpid fsgsbase
> tsc_adjust bmi1 avx2 smep bmi2 erms invpcid xsaveopt
> bugs :
> bogomips : 5188.24
> clflush size : 64
> cache_alignment : 64
> address sizes : 39 bits physical, 48 bits virtual
> power management:
>
> [7.3.] Module information (from /proc/modules):
> snd_hda_codec_realtek 78564 1 - Live 0x0000000000000000
> snd_hda_codec_hdmi 52620 1 - Live 0x0000000000000000
> snd_hda_codec_generic 70087 1 snd_hda_codec_realtek, Live 0x0000000000000000
> bnep 19884 2 - Live 0x0000000000000000
> rfcomm 75114 0 - Live 0x0000000000000000
> bluetooth 477455 10 bnep,rfcomm, Live 0x0000000000000000
> joydev 17587 0 - Live 0x0000000000000000
> hid_generic 12559 0 - Live 0x0000000000000000
> asus_nb_wmi 21128 0 - Live 0x0000000000000000
> asus_wmi 24697 1 asus_nb_wmi, Live 0x0000000000000000
> sparse_keymap 13890 1 asus_wmi, Live 0x0000000000000000
> intel_rapl 19196 0 - Live 0x0000000000000000
> x86_pkg_temp_thermal 14312 0 - Live 0x0000000000000000
> intel_powerclamp 19099 0 - Live 0x0000000000000000
> coretemp 13638 0 - Live 0x0000000000000000
> kvm_intel 149257 0 - Live 0x0000000000000000
> kvm 468567 1 kvm_intel, Live 0x0000000000000000
> crct10dif_pclmul 14268 0 - Live 0x0000000000000000
> crc32_pclmul 13180 0 - Live 0x0000000000000000
> ghash_clmulni_intel 13230 0 - Live 0x0000000000000000
> aesni_intel 165515 0 - Live 0x0000000000000000
> aes_x86_64 17131 1 aesni_intel, Live 0x0000000000000000
> lrw 13323 1 aesni_intel, Live 0x0000000000000000
> gf128mul 14951 1 lrw, Live 0x0000000000000000
> glue_helper 14095 1 aesni_intel, Live 0x0000000000000000
> ablk_helper 13597 1 aesni_intel, Live 0x0000000000000000
> cryptd 20531 3 ghash_clmulni_intel,aesni_intel,ablk_helper, Live
> 0x0000000000000000
> uvcvideo 86628 0 - Live 0x0000000000000000
> videobuf2_vmalloc 13216 1 uvcvideo, Live 0x0000000000000000
> serio_raw 13483 0 - Live 0x0000000000000000
> videobuf2_memops 13362 1 videobuf2_vmalloc, Live 0x0000000000000000
> videobuf2_core 59907 1 uvcvideo, Live 0x0000000000000000
> uas 27623 0 - Live 0x0000000000000000
> v4l2_common 15715 1 videobuf2_core, Live 0x0000000000000000
> nouveau 1321757 0 - Live 0x0000000000000000
> usb_storage 67010 1 uas, Live 0x0000000000000000
> videodev 163831 3 uvcvideo,videobuf2_core,v4l2_common, Live 0x0000000000000000
> media 22008 2 uvcvideo,videodev, Live 0x0000000000000000
> usbhid 53122 0 - Live 0x0000000000000000
> lpc_ich 21176 0 - Live 0x0000000000000000
> mxm_wmi 13021 1 nouveau, Live 0x0000000000000000
> ttm 90376 1 nouveau, Live 0x0000000000000000
> mei_me 19524 0 - Live 0x0000000000000000
> mei 88810 1 mei_me, Live 0x0000000000000000
> snd_soc_rt5640 93123 0 - Live 0x0000000000000000
> snd_soc_rl6231 13037 1 snd_soc_rt5640, Live 0x0000000000000000
> snd_soc_core 207547 1 snd_soc_rt5640, Live 0x0000000000000000
> i2c_hid 19065 0 - Live 0x0000000000000000
> dw_dmac 12835 0 - Live 0x0000000000000000
> snd_soc_sst_acpi 13007 0 - Live 0x0000000000000000
> hid 110572 3 hid_generic,usbhid,i2c_hid, Live 0x0000000000000000
> snd_compress 19435 1 snd_soc_core, Live 0x0000000000000000
> dw_dmac_core 28566 1 dw_dmac, Live 0x0000000000000000
> snd_pcm_dmaengine 15229 1 snd_soc_core, Live 0x0000000000000000
> 8250_dw 13474 0 - Live 0x0000000000000000
> i2c_designware_platform 13025 0 - Live 0x0000000000000000
> mac_hid 13275 0 - Live 0x0000000000000000
> i2c_designware_core 14990 1 i2c_designware_platform, Live 0x0000000000000000
> spi_pxa2xx_platform 23302 0 - Live 0x0000000000000000
> wmi 19379 3 asus_wmi,nouveau,mxm_wmi, Live 0x0000000000000000
> snd_hda_intel 30783 5 - Live 0x0000000000000000
> snd_hda_controller 32234 1 snd_hda_intel, Live 0x0000000000000000
> snd_hda_codec 145035 5
> snd_hda_codec_realtek,snd_hda_codec_hdmi,snd_hda_codec_generic,snd_hda_intel,snd_hda_controller,
> Live 0x0000000000000000
> snd_hwdep 17709 1 snd_hda_codec, Live 0x0000000000000000
> snd_pcm 105052 7
> snd_hda_codec_hdmi,snd_soc_rt5640,snd_soc_core,snd_pcm_dmaengine,snd_hda_intel,snd_hda_controller,snd_hda_codec,
> Live 0x0000000000000000
> i915 993210 7 - Live 0x0000000000000000
> snd_seq_midi 13564 0 - Live 0x0000000000000000
> snd_seq_midi_event 14899 1 snd_seq_midi, Live 0x0000000000000000
> snd_rawmidi 31197 1 snd_seq_midi, Live 0x0000000000000000
> snd_seq 63540 2 snd_seq_midi,snd_seq_midi_event, Live 0x0000000000000000
> video 20569 3 asus_wmi,nouveau,i915, Live 0x0000000000000000
> snd_seq_device 14497 3 snd_seq_midi,snd_rawmidi,snd_seq, Live 0x0000000000000000
> snd_timer 30118 2 snd_pcm,snd_seq, Live 0x0000000000000000
> drm_kms_helper 99872 2 nouveau,i915, Live 0x0000000000000000
> drm 318542 8 nouveau,ttm,i915,drm_kms_helper, Live 0x0000000000000000
> snd 84025 23 snd_hda_codec_realtek,snd_hda_codec_hdmi,snd_hda_codec_generic,snd_soc_core,snd_compress,snd_hda_intel,snd_hda_codec,snd_hwdep,snd_pcm,snd_rawmidi,snd_seq,snd_seq_device,snd_timer,
> Live 0x0000000000000000
> soundcore 15091 2 snd_hda_codec,snd, Live 0x0000000000000000
> i2c_algo_bit 13564 2 nouveau,i915, Live 0x0000000000000000
> parport_pc 32906 0 - Live 0x0000000000000000
> ppdev 17711 0 - Live 0x0000000000000000
> lp 17799 0 - Live 0x0000000000000000
> parport 42481 3 parport_pc,ppdev,lp, Live 0x0000000000000000
> ahci 30167 3 - Live 0x0000000000000000
> r8169 77680 0 - Live 0x0000000000000000
> libahci 32533 1 ahci, Live 0x0000000000000000
> mii 13981 1 r8169, Live 0x0000000000000000
> sdhci_acpi 13395 0 - Live 0x0000000000000000
> sdhci 44159 1 sdhci_acpi, Live 0x0000000000000000
>
> [7.4.] Loaded driver and hardware information (/proc/ioports, /proc/iomem)
> cat /proc/ioports:
> 0000-0cf7 : PCI Bus 0000:00
>   0000-001f : dma1
>   0020-0021 : pic1
>   0040-0043 : timer0
>   0050-0053 : timer1
>   0060-0060 : keyboard
>   0064-0064 : keyboard
>   0070-0077 : rtc0
>   0080-008f : dma page reg
>   00a0-00a1 : pic2
>   00c0-00df : dma2
>   00f0-00ff : fpu
>   03c0-03df : vesafb
>   04d0-04d1 : pnp 00:04
>   0680-069f : pnp 00:01
> 0cf8-0cff : PCI conf1
> 0d00-ffff : PCI Bus 0000:00
>   164e-164f : pnp 00:01
>   1800-1803 : ACPI PM1a_EVT_BLK
>   1804-1805 : ACPI PM1a_CNT_BLK
>   1808-180b : ACPI PM_TMR
>   1810-1815 : ACPI CPU throttle
>   1830-1833 : iTCO_wdt
>   1850-1850 : ACPI PM2_CNT_BLK
>   1854-1857 : pnp 00:03
>   1860-187f : iTCO_wdt
>   1880-189f : ACPI GPE0_BLK
>   1c00-1cfe : pnp 00:01
>   1d00-1dfe : pnp 00:01
>   1e00-1efe : pnp 00:01
>   1f00-1ffe : pnp 00:01
>   2000-2fff : PCI Bus 0000:01
>   d000-dfff : PCI Bus 0000:04
>     d000-d07f : 0000:04:00.0
>   e000-efff : PCI Bus 0000:03
>     e000-e0ff : 0000:03:00.0
>       e000-e0ff : r8169
>   f000-f03f : 0000:00:02.0
>   f040-f05f : 0000:00:1f.3
>   f060-f07f : 0000:00:1f.2
>     f060-f07f : ahci
>   f080-f083 : 0000:00:1f.2
>     f080-f083 : ahci
>   f090-f097 : 0000:00:1f.2
>     f090-f097 : ahci
>   f0a0-f0a3 : 0000:00:1f.2
>     f0a0-f0a3 : ahci
>   f0b0-f0b7 : 0000:00:1f.2
>     f0b0-f0b7 : ahci
>   ffff-ffff : pnp 00:01
>     ffff-ffff : pnp 00:01
>       ffff-ffff : pnp 00:01
>
> cat /proc/iomem:
> 00000000-00000fff : reserved
> 00001000-0009d7ff : System RAM
> 0009d800-0009ffff : reserved
> 000a0000-000bffff : PCI Bus 0000:00
> 000c0000-000cebff : Video ROM
> 000d0000-000d3fff : PCI Bus 0000:00
> 000d4000-000d7fff : PCI Bus 0000:00
> 000d8000-000dbfff : PCI Bus 0000:00
> 000dc000-000dffff : PCI Bus 0000:00
> 000e0000-000fffff : reserved
>   000e0000-000e3fff : PCI Bus 0000:00
>   000e4000-000e7fff : PCI Bus 0000:00
>   000f0000-000fffff : System ROM
> 00100000-b8a8cfff : System RAM
>   01000000-017a9977 : Kernel code
>   017a9978-01d1e4ff : Kernel data
>   01e80000-01fc6fff : Kernel bss
> b8a8d000-b8a93fff : ACPI Non-volatile Storage
> b8a94000-b8ecbfff : System RAM
> b8ecc000-b943cfff : reserved
> b943d000-c8c15fff : System RAM
> c8c16000-c8c9ffff : reserved
> c8ca0000-c8e7bfff : System RAM
> c8e7c000-c9615fff : ACPI Non-volatile Storage
> c9616000-c9ffdfff : reserved
> c9ffe000-c9ffefff : System RAM
> c9fff000-caffffff : RAM buffer
> cb000000-cf1fffff : reserved
>   cb200000-cf1fffff : Graphics Stolen Memory
> cf200000-feafffff : PCI Bus 0000:00
>   cf200000-cf3fffff : PCI Bus 0000:01
>   cf400000-cf5fffff : PCI Bus 0000:01
>   d0000000-dfffffff : 0000:00:02.0
>   e0000000-f1ffffff : PCI Bus 0000:04
>     e0000000-efffffff : 0000:04:00.0
>     f0000000-f1ffffff : 0000:04:00.0
>   f2100000-f21fffff : PCI Bus 0000:03
>     f2100000-f2103fff : 0000:03:00.0
>       f2100000-f2103fff : r8169
>   f6000000-f70fffff : PCI Bus 0000:04
>     f6000000-f6ffffff : 0000:04:00.0
>     f7000000-f707ffff : 0000:04:00.0
>   f7400000-f77fffff : 0000:00:02.0
>   f7800000-f78fffff : PCI Bus 0000:03
>     f7800000-f7800fff : 0000:03:00.0
>       f7800000-f7800fff : r8169
>   f7900000-f79fffff : PCI Bus 0000:02
>     f7900000-f7907fff : 0000:02:00.0
>   f7a00000-f7a0ffff : 0000:00:14.0
>     f7a00000-f7a0ffff : xhci_hcd
>   f7a10000-f7a13fff : 0000:00:1b.0
>     f7a10000-f7a13fff : ICH HD audio
>   f7a14000-f7a17fff : 0000:00:03.0
>     f7a14000-f7a17fff : ICH HD audio
>   f7a19000-f7a190ff : 0000:00:1f.3
>   f7a1a000-f7a1a7ff : 0000:00:1f.2
>     f7a1a000-f7a1a7ff : ahci
>   f7a1b000-f7a1b3ff : 0000:00:1d.0
>     f7a1b000-f7a1b3ff : ehci_hcd
>   f7a1d000-f7a1d01f : 0000:00:16.0
>     f7a1d000-f7a1d01f : mei_me
>   f7fdf000-f7fdffff : pnp 00:08
>   f7fe0000-f7feffff : pnp 00:08
>   f8000000-fbffffff : PCI MMCONFIG 0000 [bus 00-3f]
>     f8000000-fbffffff : reserved
>       f8000000-fbffffff : pnp 00:08
>   fe104000-fe104fff : pnp 00:07
>   fe106000-fe106fff : pnp 00:07
>   fe10e000-fe10efff : pnp 00:07
>   fe111000-fe111007 : pnp 00:07
>   fe111014-fe111fff : pnp 00:07
>   fe112000-fe112fff : pnp 00:07
> fec00000-fec00fff : reserved
>   fec00000-fec003ff : IOAPIC 0
> fed00000-fed03fff : reserved
>   fed00000-fed003ff : HPET 0
>     fed00000-fed003ff : PNP0103:00
> fed10000-fed17fff : pnp 00:08
> fed18000-fed18fff : pnp 00:08
> fed19000-fed19fff : pnp 00:08
> fed1c000-fed1ffff : reserved
>   fed1c000-fed1ffff : pnp 00:08
>     fed1f410-fed1f414 : iTCO_wdt
> fed20000-fed3ffff : pnp 00:08
> fed40000-fed44fff : pnp 00:00
> fed45000-fed8ffff : pnp 00:08
> fed90000-fed93fff : pnp 00:08
> fee00000-fee00fff : Local APIC
>   fee00000-fee00fff : reserved
> ff000000-ffffffff : reserved
>   ff000000-ffffffff : INT0800:00
>     ff000000-ffffffff : pnp 00:08
> 100000000-22fdfffff : System RAM
> 22fe00000-22fffffff : RAM buffer
>
> [7.5.] PCI information ('lspci -vvv' as root):
> 00:00.0 Host bridge: Intel Corporation Haswell-ULT DRAM Controller (rev 0b)
> Subsystem: ASUSTeK Computer Inc. Device 14fd
> Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr-
> Stepping- SERR- FastB2B- DisINTx-
> Status: Cap+ 66MHz- UDF- FastB2B+ ParErr- DEVSEL=fast >TAbort-
> <TAbort- <MAbort+ >SERR- <PERR- INTx-
> Latency: 0
> Capabilities: [e0] Vendor Specific Information: Len=0c <?>
>
> 00:02.0 VGA compatible controller: Intel Corporation Haswell-ULT
> Integrated Graphics Controller (rev 0b) (prog-if 00 [VGA controller])
> Subsystem: ASUSTeK Computer Inc. Device 14fd
> Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr-
> Stepping- SERR- FastB2B- DisINTx+
> Status: Cap+ 66MHz- UDF- FastB2B+ ParErr- DEVSEL=fast >TAbort-
> <TAbort- <MAbort- >SERR- <PERR- INTx-
> Latency: 0
> Interrupt: pin A routed to IRQ 47
> Region 0: Memory at f7400000 (64-bit, non-prefetchable) [size=4M]
> Region 2: Memory at d0000000 (64-bit, prefetchable) [size=256M]
> Region 4: I/O ports at f000 [size=64]
> Expansion ROM at <unassigned> [disabled]
> Capabilities: [90] MSI: Enable+ Count=1/1 Maskable- 64bit-
> Address: fee0f00c  Data: 4152
> Capabilities: [d0] Power Management version 2
> Flags: PMEClk- DSI+ D1- D2- AuxCurrent=0mA PME(D0-,D1-,D2-,D3hot-,D3cold-)
> Status: D0 NoSoftRst- PME-Enable- DSel=0 DScale=0 PME-
> Capabilities: [a4] PCI Advanced Features
> AFCap: TP+ FLR+
> AFCtrl: FLR-
> AFStatus: TP-
> Kernel driver in use: i915
>
> 00:03.0 Audio device: Intel Corporation Haswell-ULT HD Audio Controller (rev 0b)
> Subsystem: ASUSTeK Computer Inc. Device 14fd
> Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr-
> Stepping- SERR- FastB2B- DisINTx+
> Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort-
> <TAbort- <MAbort- >SERR- <PERR- INTx-
> Latency: 0, Cache Line Size: 64 bytes
> Interrupt: pin A routed to IRQ 50
> Region 0: Memory at f7a14000 (64-bit, non-prefetchable) [size=16K]
> Capabilities: [50] Power Management version 2
> Flags: PMEClk- DSI- D1- D2- AuxCurrent=0mA PME(D0-,D1-,D2-,D3hot-,D3cold-)
> Status: D0 NoSoftRst- PME-Enable- DSel=0 DScale=0 PME-
> Capabilities: [60] MSI: Enable+ Count=1/1 Maskable- 64bit-
> Address: fee0f00c  Data: 4192
> Capabilities: [70] Express (v1) Root Complex Integrated Endpoint, MSI 00
> DevCap: MaxPayload 128 bytes, PhantFunc 0
> ExtTag- RBE-
> DevCtl: Report errors: Correctable- Non-Fatal- Fatal- Unsupported-
> RlxdOrd- ExtTag- PhantFunc- AuxPwr- NoSnoop-
> MaxPayload 128 bytes, MaxReadReq 128 bytes
> DevSta: CorrErr- UncorrErr- FatalErr- UnsuppReq- AuxPwr- TransPend-
> Kernel driver in use: snd_hda_intel
>
> 00:14.0 USB controller: Intel Corporation Lynx Point-LP USB xHCI HC
> (rev 04) (prog-if 30 [XHCI])
> Subsystem: ASUSTeK Computer Inc. Device 201f
> Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr-
> Stepping- SERR- FastB2B- DisINTx+
> Status: Cap+ 66MHz- UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort-
> <TAbort- <MAbort- >SERR- <PERR- INTx-
> Latency: 0
> Interrupt: pin A routed to IRQ 44
> Region 0: Memory at f7a00000 (64-bit, non-prefetchable) [size=64K]
> Capabilities: [70] Power Management version 2
> Flags: PMEClk- DSI- D1- D2- AuxCurrent=375mA PME(D0-,D1-,D2-,D3hot+,D3cold+)
> Status: D0 NoSoftRst+ PME-Enable- DSel=0 DScale=0 PME-
> Capabilities: [80] MSI: Enable+ Count=1/8 Maskable- 64bit+
> Address: 00000000fee0500c  Data: 41e1
> Kernel driver in use: xhci_hcd
>
> 00:16.0 Communication controller: Intel Corporation Lynx Point-LP HECI
> #0 (rev 04)
> Subsystem: ASUSTeK Computer Inc. Device 14fd
> Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr-
> Stepping- SERR- FastB2B- DisINTx+
> Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort-
> <TAbort- <MAbort- >SERR- <PERR- INTx-
> Latency: 0
> Interrupt: pin A routed to IRQ 48
> Region 0: Memory at f7a1d000 (64-bit, non-prefetchable) [size=32]
> Capabilities: [50] Power Management version 3
> Flags: PMEClk- DSI- D1- D2- AuxCurrent=0mA PME(D0+,D1-,D2-,D3hot+,D3cold+)
> Status: D0 NoSoftRst+ PME-Enable- DSel=0 DScale=0 PME-
> Capabilities: [8c] MSI: Enable+ Count=1/1 Maskable- 64bit+
> Address: 00000000fee0f00c  Data: 4172
> Kernel driver in use: mei_me
>
> 00:1b.0 Audio device: Intel Corporation Lynx Point-LP HD Audio
> Controller (rev 04)
> Subsystem: ASUSTeK Computer Inc. Device 14fd
> Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr-
> Stepping- SERR- FastB2B- DisINTx+
> Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort-
> <TAbort- <MAbort- >SERR- <PERR- INTx-
> Latency: 0, Cache Line Size: 64 bytes
> Interrupt: pin A routed to IRQ 49
> Region 0: Memory at f7a10000 (64-bit, non-prefetchable) [size=16K]
> Capabilities: [50] Power Management version 3
> Flags: PMEClk- DSI- D1- D2- AuxCurrent=55mA PME(D0+,D1-,D2-,D3hot+,D3cold+)
> Status: D0 NoSoftRst- PME-Enable- DSel=0 DScale=0 PME-
> Capabilities: [60] MSI: Enable+ Count=1/1 Maskable- 64bit+
> Address: 00000000fee0f00c  Data: 4182
> Capabilities: [70] Express (v1) Root Complex Integrated Endpoint, MSI 00
> DevCap: MaxPayload 128 bytes, PhantFunc 0
> ExtTag- RBE-
> DevCtl: Report errors: Correctable- Non-Fatal- Fatal- Unsupported-
> RlxdOrd- ExtTag- PhantFunc- AuxPwr- NoSnoop-
> MaxPayload 128 bytes, MaxReadReq 128 bytes
> DevSta: CorrErr- UncorrErr- FatalErr- UnsuppReq- AuxPwr+ TransPend-
> Capabilities: [100 v1] Virtual Channel
> Caps: LPEVC=0 RefClk=100ns PATEntryBits=1
> Arb: Fixed- WRR32- WRR64- WRR128-
> Ctrl: ArbSelect=Fixed
> Status: InProgress-
> VC0: Caps: PATOffset=00 MaxTimeSlots=1 RejSnoopTrans-
> Arb: Fixed- WRR32- WRR64- WRR128- TWRR128- WRR256-
> Ctrl: Enable+ ID=0 ArbSelect=Fixed TC/VC=01
> Status: NegoPending- InProgress-
> VC1: Caps: PATOffset=00 MaxTimeSlots=1 RejSnoopTrans-
> Arb: Fixed- WRR32- WRR64- WRR128- TWRR128- WRR256-
> Ctrl: Enable- ID=2 ArbSelect=Fixed TC/VC=04
> Status: NegoPending- InProgress-
> Kernel driver in use: snd_hda_intel
>
> 00:1c.0 PCI bridge: Intel Corporation Lynx Point-LP PCI Express Root
> Port 1 (rev e4) (prog-if 00 [Normal decode])
> Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr-
> Stepping- SERR- FastB2B- DisINTx+
> Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort-
> <TAbort- <MAbort- >SERR- <PERR- INTx-
> Latency: 0, Cache Line Size: 64 bytes
> Bus: primary=00, secondary=01, subordinate=01, sec-latency=0
> I/O behind bridge: 00002000-00002fff
> Memory behind bridge: cf200000-cf3fffff
> Prefetchable memory behind bridge: 00000000cf400000-00000000cf5fffff
> Secondary status: 66MHz- FastB2B- ParErr- DEVSEL=fast >TAbort-
> <TAbort- <MAbort+ <SERR- <PERR-
> BridgeCtl: Parity- SERR- NoISA- VGA- MAbort- >Reset- FastB2B-
> PriDiscTmr- SecDiscTmr- DiscTmrStat- DiscTmrSERREn-
> Capabilities: [40] Express (v2) Root Port (Slot+), MSI 00
> DevCap: MaxPayload 128 bytes, PhantFunc 0
> ExtTag- RBE+
> DevCtl: Report errors: Correctable- Non-Fatal- Fatal- Unsupported-
> RlxdOrd- ExtTag- PhantFunc- AuxPwr- NoSnoop-
> MaxPayload 128 bytes, MaxReadReq 128 bytes
> DevSta: CorrErr- UncorrErr- FatalErr- UnsuppReq- AuxPwr+ TransPend-
> LnkCap: Port #1, Speed 5GT/s, Width x1, ASPM L0s L1, Exit Latency L0s
> <1us, L1 <4us
> ClockPM- Surprise- LLActRep+ BwNot+
> LnkCtl: ASPM Disabled; RCB 64 bytes Disabled- CommClk-
> ExtSynch- ClockPM- AutWidDis- BWInt- AutBWInt-
> LnkSta: Speed 2.5GT/s, Width x0, TrErr- Train- SlotClk+ DLActive-
> BWMgmt- ABWMgmt-
> SltCap: AttnBtn- PwrCtrl- MRL- AttnInd- PwrInd- HotPlug+ Surprise+
> Slot #0, PowerLimit 0.000W; Interlock- NoCompl+
> SltCtl: Enable: AttnBtn- PwrFlt- MRL- PresDet+ CmdCplt- HPIrq+ LinkChg+
> Control: AttnInd Unknown, PwrInd Unknown, Power- Interlock-
> SltSta: Status: AttnBtn- PowerFlt- MRL- CmdCplt- PresDet- Interlock-
> Changed: MRL- PresDet- LinkState-
> RootCtl: ErrCorrectable- ErrNon-Fatal- ErrFatal- PMEIntEna+ CRSVisible-
> RootCap: CRSVisible-
> RootSta: PME ReqID 0000, PMEStatus- PMEPending-
> DevCap2: Completion Timeout: Range ABC, TimeoutDis+, LTR+, OBFF Via
> WAKE# ARIFwd-
> DevCtl2: Completion Timeout: 50us to 50ms, TimeoutDis-, LTR+, OBFF
> Disabled ARIFwd-
> LnkCtl2: Target Link Speed: 5GT/s, EnterCompliance- SpeedDis-
> Transmit Margin: Normal Operating Range, EnterModifiedCompliance- ComplianceSOS-
> Compliance De-emphasis: -6dB
> LnkSta2: Current De-emphasis Level: -3.5dB, EqualizationComplete-,
> EqualizationPhase1-
> EqualizationPhase2-, EqualizationPhase3-, LinkEqualizationRequest-
> Capabilities: [80] MSI: Enable+ Count=1/1 Maskable- 64bit-
> Address: fee0f00c  Data: 4171
> Capabilities: [90] Subsystem: ASUSTeK Computer Inc. Device 14fd
> Capabilities: [a0] Power Management version 3
> Flags: PMEClk- DSI- D1- D2- AuxCurrent=0mA PME(D0+,D1-,D2-,D3hot+,D3cold+)
> Status: D0 NoSoftRst- PME-Enable- DSel=0 DScale=0 PME-
> Kernel driver in use: pcieport
>
> 00:1c.2 PCI bridge: Intel Corporation Lynx Point-LP PCI Express Root
> Port 3 (rev e4) (prog-if 00 [Normal decode])
> Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr-
> Stepping- SERR- FastB2B- DisINTx+
> Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort-
> <TAbort- <MAbort- >SERR- <PERR- INTx-
> Latency: 0, Cache Line Size: 64 bytes
> Bus: primary=00, secondary=02, subordinate=02, sec-latency=0
> I/O behind bridge: 0000f000-00000fff
> Memory behind bridge: f7900000-f79fffff
> Prefetchable memory behind bridge: 00000000fff00000-00000000000fffff
> Secondary status: 66MHz- FastB2B- ParErr- DEVSEL=fast >TAbort-
> <TAbort- <MAbort- <SERR- <PERR-
> BridgeCtl: Parity- SERR- NoISA- VGA- MAbort- >Reset- FastB2B-
> PriDiscTmr- SecDiscTmr- DiscTmrStat- DiscTmrSERREn-
> Capabilities: [40] Express (v2) Root Port (Slot+), MSI 00
> DevCap: MaxPayload 128 bytes, PhantFunc 0
> ExtTag- RBE+
> DevCtl: Report errors: Correctable- Non-Fatal- Fatal- Unsupported-
> RlxdOrd- ExtTag- PhantFunc- AuxPwr- NoSnoop-
> MaxPayload 128 bytes, MaxReadReq 128 bytes
> DevSta: CorrErr- UncorrErr- FatalErr- UnsuppReq- AuxPwr+ TransPend-
> LnkCap: Port #3, Speed 5GT/s, Width x1, ASPM L0s L1, Exit Latency L0s
> <512ns, L1 <16us
> ClockPM- Surprise- LLActRep+ BwNot+
> LnkCtl: ASPM L0s L1 Enabled; RCB 64 bytes Disabled- CommClk+
> ExtSynch- ClockPM- AutWidDis- BWInt- AutBWInt-
> LnkSta: Speed 2.5GT/s, Width x1, TrErr- Train- SlotClk+ DLActive+
> BWMgmt+ ABWMgmt-
> SltCap: AttnBtn- PwrCtrl- MRL- AttnInd- PwrInd- HotPlug- Surprise-
> Slot #2, PowerLimit 10.000W; Interlock- NoCompl+
> SltCtl: Enable: AttnBtn- PwrFlt- MRL- PresDet- CmdCplt- HPIrq- LinkChg-
> Control: AttnInd Unknown, PwrInd Unknown, Power- Interlock-
> SltSta: Status: AttnBtn- PowerFlt- MRL- CmdCplt- PresDet+ Interlock-
> Changed: MRL- PresDet- LinkState-
> RootCtl: ErrCorrectable- ErrNon-Fatal- ErrFatal- PMEIntEna+ CRSVisible-
> RootCap: CRSVisible-
> RootSta: PME ReqID 0000, PMEStatus- PMEPending-
> DevCap2: Completion Timeout: Range ABC, TimeoutDis+, LTR+, OBFF Not
> Supported ARIFwd-
> DevCtl2: Completion Timeout: 50us to 50ms, TimeoutDis-, LTR+, OBFF
> Disabled ARIFwd-
> LnkCtl2: Target Link Speed: 5GT/s, EnterCompliance- SpeedDis-
> Transmit Margin: Normal Operating Range, EnterModifiedCompliance- ComplianceSOS-
> Compliance De-emphasis: -6dB
> LnkSta2: Current De-emphasis Level: -3.5dB, EqualizationComplete-,
> EqualizationPhase1-
> EqualizationPhase2-, EqualizationPhase3-, LinkEqualizationRequest-
> Capabilities: [80] MSI: Enable+ Count=1/1 Maskable- 64bit-
> Address: fee0f00c  Data: 4191
> Capabilities: [90] Subsystem: ASUSTeK Computer Inc. Device 14fd
> Capabilities: [a0] Power Management version 3
> Flags: PMEClk- DSI- D1- D2- AuxCurrent=0mA PME(D0+,D1-,D2-,D3hot+,D3cold+)
> Status: D0 NoSoftRst- PME-Enable- DSel=0 DScale=0 PME-
> Capabilities: [100 v0] #00
> Capabilities: [200 v1] L1 PM Substates
> L1SubCap: PCI-PM_L1.2+ PCI-PM_L1.1+ ASPM_L1.2+ ASPM_L1.1+ L1_PM_Substates+
>  PortCommonModeRestoreTime=40us PortTPowerOnTime=10us
> Kernel driver in use: pcieport
>
> 00:1c.3 PCI bridge: Intel Corporation Lynx Point-LP PCI Express Root
> Port 4 (rev e4) (prog-if 00 [Normal decode])
> Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr-
> Stepping- SERR- FastB2B- DisINTx+
> Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort-
> <TAbort- <MAbort- >SERR- <PERR- INTx-
> Latency: 0, Cache Line Size: 64 bytes
> Bus: primary=00, secondary=03, subordinate=03, sec-latency=0
> I/O behind bridge: 0000e000-0000efff
> Memory behind bridge: f7800000-f78fffff
> Prefetchable memory behind bridge: 00000000f2100000-00000000f21fffff
> Secondary status: 66MHz- FastB2B- ParErr- DEVSEL=fast >TAbort-
> <TAbort- <MAbort- <SERR- <PERR-
> BridgeCtl: Parity- SERR- NoISA- VGA- MAbort- >Reset- FastB2B-
> PriDiscTmr- SecDiscTmr- DiscTmrStat- DiscTmrSERREn-
> Capabilities: [40] Express (v2) Root Port (Slot+), MSI 00
> DevCap: MaxPayload 128 bytes, PhantFunc 0
> ExtTag- RBE+
> DevCtl: Report errors: Correctable- Non-Fatal- Fatal- Unsupported-
> RlxdOrd- ExtTag- PhantFunc- AuxPwr- NoSnoop-
> MaxPayload 128 bytes, MaxReadReq 128 bytes
> DevSta: CorrErr- UncorrErr- FatalErr- UnsuppReq- AuxPwr+ TransPend-
> LnkCap: Port #4, Speed 5GT/s, Width x1, ASPM L0s L1, Exit Latency L0s
> <512ns, L1 <16us
> ClockPM- Surprise- LLActRep+ BwNot+
> LnkCtl: ASPM Disabled; RCB 64 bytes Disabled- CommClk+
> ExtSynch- ClockPM- AutWidDis- BWInt- AutBWInt-
> LnkSta: Speed 2.5GT/s, Width x1, TrErr- Train- SlotClk+ DLActive+
> BWMgmt+ ABWMgmt-
> SltCap: AttnBtn- PwrCtrl- MRL- AttnInd- PwrInd- HotPlug- Surprise-
> Slot #3, PowerLimit 10.000W; Interlock- NoCompl+
> SltCtl: Enable: AttnBtn- PwrFlt- MRL- PresDet- CmdCplt- HPIrq- LinkChg-
> Control: AttnInd Unknown, PwrInd Unknown, Power- Interlock-
> SltSta: Status: AttnBtn- PowerFlt- MRL- CmdCplt- PresDet+ Interlock-
> Changed: MRL- PresDet- LinkState-
> RootCtl: ErrCorrectable- ErrNon-Fatal- ErrFatal- PMEIntEna+ CRSVisible-
> RootCap: CRSVisible-
> RootSta: PME ReqID 0000, PMEStatus- PMEPending-
> DevCap2: Completion Timeout: Range ABC, TimeoutDis+, LTR+, OBFF Not
> Supported ARIFwd-
> DevCtl2: Completion Timeout: 50us to 50ms, TimeoutDis-, LTR+, OBFF
> Disabled ARIFwd-
> LnkCtl2: Target Link Speed: 5GT/s, EnterCompliance- SpeedDis-
> Transmit Margin: Normal Operating Range, EnterModifiedCompliance- ComplianceSOS-
> Compliance De-emphasis: -6dB
> LnkSta2: Current De-emphasis Level: -3.5dB, EqualizationComplete-,
> EqualizationPhase1-
> EqualizationPhase2-, EqualizationPhase3-, LinkEqualizationRequest-
> Capabilities: [80] MSI: Enable+ Count=1/1 Maskable- 64bit-
> Address: fee0f00c  Data: 41b1
> Capabilities: [90] Subsystem: ASUSTeK Computer Inc. Device 14fd
> Capabilities: [a0] Power Management version 3
> Flags: PMEClk- DSI- D1- D2- AuxCurrent=0mA PME(D0+,D1-,D2-,D3hot+,D3cold+)
> Status: D0 NoSoftRst- PME-Enable- DSel=0 DScale=0 PME-
> Capabilities: [100 v0] #00
> Capabilities: [200 v1] L1 PM Substates
> L1SubCap: PCI-PM_L1.2+ PCI-PM_L1.1+ ASPM_L1.2+ ASPM_L1.1+ L1_PM_Substates+
>  PortCommonModeRestoreTime=40us PortTPowerOnTime=10us
> Kernel driver in use: pcieport
>
> 00:1c.4 PCI bridge: Intel Corporation Lynx Point-LP PCI Express Root
> Port 5 (rev e4) (prog-if 00 [Normal decode])
> Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr-
> Stepping- SERR- FastB2B- DisINTx+
> Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort-
> <TAbort- <MAbort- >SERR- <PERR- INTx-
> Latency: 0, Cache Line Size: 64 bytes
> Bus: primary=00, secondary=04, subordinate=04, sec-latency=0
> I/O behind bridge: 0000d000-0000dfff
> Memory behind bridge: f6000000-f70fffff
> Prefetchable memory behind bridge: 00000000e0000000-00000000f1ffffff
> Secondary status: 66MHz- FastB2B- ParErr- DEVSEL=fast >TAbort-
> <TAbort- <MAbort+ <SERR- <PERR-
> BridgeCtl: Parity- SERR- NoISA- VGA- MAbort- >Reset- FastB2B-
> PriDiscTmr- SecDiscTmr- DiscTmrStat- DiscTmrSERREn-
> Capabilities: [40] Express (v2) Root Port (Slot+), MSI 00
> DevCap: MaxPayload 128 bytes, PhantFunc 0
> ExtTag- RBE+
> DevCtl: Report errors: Correctable- Non-Fatal- Fatal- Unsupported-
> RlxdOrd- ExtTag- PhantFunc- AuxPwr- NoSnoop-
> MaxPayload 128 bytes, MaxReadReq 128 bytes
> DevSta: CorrErr- UncorrErr- FatalErr- UnsuppReq- AuxPwr+ TransPend-
> LnkCap: Port #5, Speed 5GT/s, Width x4, ASPM L0s L1, Exit Latency L0s
> <512ns, L1 <16us
> ClockPM- Surprise- LLActRep+ BwNot+
> LnkCtl: ASPM Disabled; RCB 64 bytes Disabled- CommClk+
> ExtSynch- ClockPM- AutWidDis- BWInt- AutBWInt-
> LnkSta: Speed 5GT/s, Width x4, TrErr- Train- SlotClk+ DLActive+ BWMgmt+ ABWMgmt-
> SltCap: AttnBtn- PwrCtrl- MRL- AttnInd- PwrInd- HotPlug- Surprise-
> Slot #4, PowerLimit 25.000W; Interlock- NoCompl+
> SltCtl: Enable: AttnBtn- PwrFlt- MRL- PresDet- CmdCplt- HPIrq- LinkChg-
> Control: AttnInd Unknown, PwrInd Unknown, Power- Interlock-
> SltSta: Status: AttnBtn- PowerFlt- MRL- CmdCplt- PresDet+ Interlock-
> Changed: MRL- PresDet- LinkState-
> RootCtl: ErrCorrectable- ErrNon-Fatal- ErrFatal- PMEIntEna+ CRSVisible-
> RootCap: CRSVisible-
> RootSta: PME ReqID 0000, PMEStatus- PMEPending-
> DevCap2: Completion Timeout: Range ABC, TimeoutDis+, LTR+, OBFF Not
> Supported ARIFwd-
> DevCtl2: Completion Timeout: 50us to 50ms, TimeoutDis-, LTR+, OBFF
> Disabled ARIFwd-
> LnkCtl2: Target Link Speed: 5GT/s, EnterCompliance- SpeedDis-
> Transmit Margin: Normal Operating Range, EnterModifiedCompliance- ComplianceSOS-
> Compliance De-emphasis: -6dB
> LnkSta2: Current De-emphasis Level: -6dB, EqualizationComplete-,
> EqualizationPhase1-
> EqualizationPhase2-, EqualizationPhase3-, LinkEqualizationRequest-
> Capabilities: [80] MSI: Enable+ Count=1/1 Maskable- 64bit-
> Address: fee0f00c  Data: 41c1
> Capabilities: [90] Subsystem: ASUSTeK Computer Inc. Device 14fd
> Capabilities: [a0] Power Management version 3
> Flags: PMEClk- DSI- D1- D2- AuxCurrent=0mA PME(D0+,D1-,D2-,D3hot+,D3cold+)
> Status: D0 NoSoftRst- PME-Enable- DSel=0 DScale=0 PME-
> Capabilities: [100 v0] #00
> Capabilities: [200 v1] L1 PM Substates
> L1SubCap: PCI-PM_L1.2+ PCI-PM_L1.1+ ASPM_L1.2+ ASPM_L1.1+ L1_PM_Substates+
>  PortCommonModeRestoreTime=40us PortTPowerOnTime=10us
> Kernel driver in use: pcieport
>
> 00:1d.0 USB controller: Intel Corporation Lynx Point-LP USB EHCI #1
> (rev 04) (prog-if 20 [EHCI])
> Subsystem: ASUSTeK Computer Inc. Device 14fd
> Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr-
> Stepping- SERR- FastB2B- DisINTx-
> Status: Cap+ 66MHz- UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort-
> <TAbort- <MAbort- >SERR- <PERR- INTx-
> Latency: 0
> Interrupt: pin A routed to IRQ 23
> Region 0: Memory at f7a1b000 (32-bit, non-prefetchable) [size=1K]
> Capabilities: [50] Power Management version 3
> Flags: PMEClk- DSI- D1- D2- AuxCurrent=375mA PME(D0+,D1-,D2-,D3hot+,D3cold+)
> Status: D0 NoSoftRst+ PME-Enable- DSel=0 DScale=0 PME-
> Capabilities: [58] Debug port: BAR=1 offset=00a0
> Capabilities: [98] PCI Advanced Features
> AFCap: TP+ FLR+
> AFCtrl: FLR-
> AFStatus: TP-
> Kernel driver in use: ehci-pci
>
> 00:1f.0 ISA bridge: Intel Corporation Lynx Point-LP LPC Controller (rev 04)
> Subsystem: ASUSTeK Computer Inc. Device 14fd
> Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr-
> Stepping- SERR- FastB2B- DisINTx-
> Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=medium >TAbort-
> <TAbort- <MAbort- >SERR- <PERR- INTx-
> Latency: 0
> Capabilities: [e0] Vendor Specific Information: Len=0c <?>
> Kernel driver in use: lpc_ich
>
> 00:1f.2 SATA controller: Intel Corporation Lynx Point-LP SATA
> Controller 1 [AHCI mode] (rev 04) (prog-if 01 [AHCI 1.0])
> Subsystem: ASUSTeK Computer Inc. Device 14fd
> Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr-
> Stepping- SERR- FastB2B- DisINTx+
> Status: Cap+ 66MHz+ UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort-
> <TAbort- <MAbort- >SERR- <PERR- INTx-
> Latency: 0
> Interrupt: pin B routed to IRQ 45
> Region 0: I/O ports at f0b0 [size=8]
> Region 1: I/O ports at f0a0 [size=4]
> Region 2: I/O ports at f090 [size=8]
> Region 3: I/O ports at f080 [size=4]
> Region 4: I/O ports at f060 [size=32]
> Region 5: Memory at f7a1a000 (32-bit, non-prefetchable) [size=2K]
> Capabilities: [80] MSI: Enable+ Count=1/1 Maskable- 64bit-
> Address: fee0500c  Data: 4122
> Capabilities: [70] Power Management version 3
> Flags: PMEClk- DSI- D1- D2- AuxCurrent=0mA PME(D0-,D1-,D2-,D3hot+,D3cold-)
> Status: D0 NoSoftRst+ PME-Enable- DSel=0 DScale=0 PME-
> Capabilities: [a8] SATA HBA v1.0 BAR4 Offset=00000004
> Kernel driver in use: ahci
>
> 00:1f.3 SMBus: Intel Corporation Lynx Point-LP SMBus Controller (rev 04)
> Subsystem: ASUSTeK Computer Inc. Device 14fd
> Control: I/O+ Mem+ BusMaster- SpecCycle- MemWINV- VGASnoop- ParErr-
> Stepping- SERR- FastB2B- DisINTx-
> Status: Cap- 66MHz- UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort-
> <TAbort- <MAbort- >SERR- <PERR- INTx-
> Interrupt: pin C routed to IRQ 3
> Region 0: Memory at f7a19000 (64-bit, non-prefetchable) [size=256]
> Region 4: I/O ports at f040 [size=32]
>
> 02:00.0 Network controller: Broadcom Corporation BCM43142 802.11b/g/n (rev 01)
> Subsystem: Lite-On Communications Inc Device 6605
> Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr-
> Stepping- SERR- FastB2B- DisINTx-
> Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort-
> <TAbort- <MAbort- >SERR- <PERR- INTx-
> Latency: 0, Cache Line Size: 64 bytes
> Interrupt: pin A routed to IRQ 3
> Region 0: Memory at f7900000 (64-bit, non-prefetchable) [size=32K]
> Capabilities: [40] Power Management version 3
> Flags: PMEClk- DSI- D1+ D2+ AuxCurrent=0mA PME(D0+,D1-,D2-,D3hot+,D3cold+)
> Status: D0 NoSoftRst+ PME-Enable- DSel=0 DScale=2 PME-
> Capabilities: [58] Vendor Specific Information: Len=78 <?>
> Capabilities: [48] MSI: Enable- Count=1/1 Maskable- 64bit+
> Address: 0000000000000000  Data: 0000
> Capabilities: [d0] Express (v1) Endpoint, MSI 00
> DevCap: MaxPayload 128 bytes, PhantFunc 0, Latency L0s <4us, L1 unlimited
> ExtTag+ AttnBtn- AttnInd- PwrInd- RBE+ FLReset-
> DevCtl: Report errors: Correctable- Non-Fatal- Fatal- Unsupported-
> RlxdOrd- ExtTag- PhantFunc- AuxPwr- NoSnoop-
> MaxPayload 128 bytes, MaxReadReq 512 bytes
> DevSta: CorrErr- UncorrErr- FatalErr- UnsuppReq- AuxPwr+ TransPend-
> LnkCap: Port #0, Speed 2.5GT/s, Width x1, ASPM L0s L1, Exit Latency
> L0s <4us, L1 <64us
> ClockPM+ Surprise- LLActRep- BwNot-
> LnkCtl: ASPM L0s L1 Enabled; RCB 64 bytes Disabled- CommClk+
> ExtSynch- ClockPM+ AutWidDis- BWInt- AutBWInt-
> LnkSta: Speed 2.5GT/s, Width x1, TrErr- Train- SlotClk+ DLActive-
> BWMgmt- ABWMgmt-
> Capabilities: [100 v1] Advanced Error Reporting
> UESta: DLP- SDES- TLP- FCP- CmpltTO- CmpltAbrt- UnxCmplt- RxOF-
> MalfTLP- ECRC- UnsupReq- ACSViol-
> UEMsk: DLP- SDES- TLP- FCP- CmpltTO- CmpltAbrt- UnxCmplt- RxOF-
> MalfTLP- ECRC- UnsupReq- ACSViol-
> UESvrt: DLP+ SDES+ TLP- FCP+ CmpltTO- CmpltAbrt- UnxCmplt- RxOF+
> MalfTLP+ ECRC- UnsupReq- ACSViol-
> CESta: RxErr+ BadTLP+ BadDLLP- Rollover- Timeout- NonFatalErr-
> CEMsk: RxErr- BadTLP- BadDLLP- Rollover- Timeout- NonFatalErr+
> AERCap: First Error Pointer: 00, GenCap+ CGenEn- ChkCap+ ChkEn-
> Capabilities: [13c v1] Virtual Channel
> Caps: LPEVC=0 RefClk=100ns PATEntryBits=1
> Arb: Fixed- WRR32- WRR64- WRR128-
> Ctrl: ArbSelect=Fixed
> Status: InProgress-
> VC0: Caps: PATOffset=00 MaxTimeSlots=1 RejSnoopTrans-
> Arb: Fixed- WRR32- WRR64- WRR128- TWRR128- WRR256-
> Ctrl: Enable+ ID=0 ArbSelect=Fixed TC/VC=01
> Status: NegoPending- InProgress-
> Capabilities: [160 v1] Device Serial Number 00-00-5e-ff-ff-82-18-cf
> Capabilities: [16c v1] Power Budgeting <?>
>
> 03:00.0 Ethernet controller: Realtek Semiconductor Co., Ltd.
> RTL8111/8168/8411 PCI Express Gigabit Ethernet Controller (rev 0c)
> Subsystem: ASUSTeK Computer Inc. Device 200f
> Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr-
> Stepping- SERR- FastB2B- DisINTx+
> Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort-
> <TAbort- <MAbort- >SERR- <PERR- INTx-
> Latency: 0, Cache Line Size: 64 bytes
> Interrupt: pin A routed to IRQ 46
> Region 0: I/O ports at e000 [size=256]
> Region 2: Memory at f7800000 (64-bit, non-prefetchable) [size=4K]
> Region 4: Memory at f2100000 (64-bit, prefetchable) [size=16K]
> Capabilities: [40] Power Management version 3
> Flags: PMEClk- DSI- D1+ D2+ AuxCurrent=375mA PME(D0+,D1+,D2+,D3hot+,D3cold+)
> Status: D0 NoSoftRst+ PME-Enable- DSel=0 DScale=0 PME-
> Capabilities: [50] MSI: Enable+ Count=1/1 Maskable- 64bit+
> Address: 00000000fee0200c  Data: 4142
> Capabilities: [70] Express (v2) Endpoint, MSI 01
> DevCap: MaxPayload 128 bytes, PhantFunc 0, Latency L0s <512ns, L1 <64us
> ExtTag- AttnBtn- AttnInd- PwrInd- RBE+ FLReset-
> DevCtl: Report errors: Correctable- Non-Fatal- Fatal- Unsupported-
> RlxdOrd- ExtTag- PhantFunc- AuxPwr- NoSnoop-
> MaxPayload 128 bytes, MaxReadReq 4096 bytes
> DevSta: CorrErr- UncorrErr- FatalErr- UnsuppReq- AuxPwr+ TransPend-
> LnkCap: Port #0, Speed 2.5GT/s, Width x1, ASPM L0s L1, Exit Latency
> L0s unlimited, L1 <64us
> ClockPM+ Surprise- LLActRep- BwNot-
> LnkCtl: ASPM Disabled; RCB 64 bytes Disabled- CommClk+
> ExtSynch- ClockPM- AutWidDis- BWInt- AutBWInt-
> LnkSta: Speed 2.5GT/s, Width x1, TrErr- Train- SlotClk+ DLActive-
> BWMgmt- ABWMgmt-
> DevCap2: Completion Timeout: Range ABCD, TimeoutDis+, LTR+, OBFF Via
> message/WAKE#
> DevCtl2: Completion Timeout: 50us to 50ms, TimeoutDis-, LTR+, OBFF Disabled
> LnkCtl2: Target Link Speed: 2.5GT/s, EnterCompliance- SpeedDis-
> Transmit Margin: Normal Operating Range, EnterModifiedCompliance- ComplianceSOS-
> Compliance De-emphasis: -6dB
> LnkSta2: Current De-emphasis Level: -6dB, EqualizationComplete-,
> EqualizationPhase1-
> EqualizationPhase2-, EqualizationPhase3-, LinkEqualizationRequest-
> Capabilities: [b0] MSI-X: Enable- Count=4 Masked-
> Vector table: BAR=4 offset=00000000
> PBA: BAR=4 offset=00000800
> Capabilities: [d0] Vital Product Data
> Unknown small resource type 00, will not decode more.
> Capabilities: [100 v1] Advanced Error Reporting
> UESta: DLP- SDES- TLP- FCP- CmpltTO- CmpltAbrt- UnxCmplt- RxOF-
> MalfTLP- ECRC- UnsupReq- ACSViol-
> UEMsk: DLP- SDES- TLP- FCP- CmpltTO- CmpltAbrt- UnxCmplt- RxOF-
> MalfTLP- ECRC- UnsupReq- ACSViol-
> UESvrt: DLP+ SDES+ TLP- FCP+ CmpltTO- CmpltAbrt- UnxCmplt- RxOF+
> MalfTLP+ ECRC- UnsupReq- ACSViol-
> CESta: RxErr- BadTLP- BadDLLP- Rollover- Timeout- NonFatalErr-
> CEMsk: RxErr- BadTLP- BadDLLP- Rollover- Timeout- NonFatalErr+
> AERCap: First Error Pointer: 00, GenCap+ CGenEn- ChkCap+ ChkEn-
> Capabilities: [140 v1] Virtual Channel
> Caps: LPEVC=0 RefClk=100ns PATEntryBits=1
> Arb: Fixed- WRR32- WRR64- WRR128-
> Ctrl: ArbSelect=Fixed
> Status: InProgress-
> VC0: Caps: PATOffset=00 MaxTimeSlots=1 RejSnoopTrans-
> Arb: Fixed- WRR32- WRR64- WRR128- TWRR128- WRR256-
> Ctrl: Enable+ ID=0 ArbSelect=Fixed TC/VC=01
> Status: NegoPending- InProgress-
> Capabilities: [160 v1] Device Serial Number 01-00-00-00-68-4c-e0-00
> Capabilities: [170 v1] Latency Tolerance Reporting
> Max snoop latency: 3145728ns
> Max no snoop latency: 3145728ns
> Kernel driver in use: r8169
>
> 04:00.0 3D controller: NVIDIA Corporation GM108M [GeForce 840M] (rev a2)
> Subsystem: ASUSTeK Computer Inc. Device 14fd
> Control: I/O+ Mem+ BusMaster- SpecCycle- MemWINV- VGASnoop- ParErr-
> Stepping- SERR- FastB2B- DisINTx-
> Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort-
> <TAbort- <MAbort- >SERR- <PERR- INTx-
> Interrupt: pin A routed to IRQ 16
> Region 0: Memory at f6000000 (32-bit, non-prefetchable) [size=16M]
> Region 1: Memory at e0000000 (64-bit, prefetchable) [size=256M]
> Region 3: Memory at f0000000 (64-bit, prefetchable) [size=32M]
> Region 5: I/O ports at d000 [size=128]
> Expansion ROM at f7000000 [disabled] [size=512K]
> Capabilities: [60] Power Management version 3
> Flags: PMEClk- DSI- D1- D2- AuxCurrent=0mA PME(D0-,D1-,D2-,D3hot-,D3cold-)
> Status: D0 NoSoftRst+ PME-Enable- DSel=0 DScale=0 PME-
> Capabilities: [68] MSI: Enable- Count=1/1 Maskable- 64bit+
> Address: 0000000000000000  Data: 0000
> Capabilities: [78] Express (v2) Endpoint, MSI 00
> DevCap: MaxPayload 256 bytes, PhantFunc 0, Latency L0s unlimited, L1 <64us
> ExtTag+ AttnBtn- AttnInd- PwrInd- RBE+ FLReset-
> DevCtl: Report errors: Correctable- Non-Fatal- Fatal- Unsupported-
> RlxdOrd- ExtTag- PhantFunc- AuxPwr- NoSnoop+
> MaxPayload 128 bytes, MaxReadReq 512 bytes
> DevSta: CorrErr- UncorrErr- FatalErr- UnsuppReq- AuxPwr- TransPend-
> LnkCap: Port #0, Speed 8GT/s, Width x4, ASPM L0s L1, Exit Latency L0s
> <512ns, L1 <4us
> ClockPM+ Surprise- LLActRep- BwNot-
> LnkCtl: ASPM Disabled; RCB 64 bytes Disabled- CommClk+
> ExtSynch- ClockPM+ AutWidDis- BWInt- AutBWInt-
> LnkSta: Speed 5GT/s, Width x4, TrErr- Train- SlotClk+ DLActive- BWMgmt- ABWMgmt-
> DevCap2: Completion Timeout: Range AB, TimeoutDis+, LTR+, OBFF Via message
> DevCtl2: Completion Timeout: 50us to 50ms, TimeoutDis-, LTR+, OBFF Disabled
> LnkCtl2: Target Link Speed: 8GT/s, EnterCompliance- SpeedDis-
> Transmit Margin: Normal Operating Range, EnterModifiedCompliance- ComplianceSOS-
> Compliance De-emphasis: -6dB
> LnkSta2: Current De-emphasis Level: -6dB, EqualizationComplete-,
> EqualizationPhase1-
> EqualizationPhase2-, EqualizationPhase3-, LinkEqualizationRequest-
> Capabilities: [100 v1] Virtual Channel
> Caps: LPEVC=0 RefClk=100ns PATEntryBits=1
> Arb: Fixed- WRR32- WRR64- WRR128-
> Ctrl: ArbSelect=Fixed
> Status: InProgress-
> VC0: Caps: PATOffset=00 MaxTimeSlots=1 RejSnoopTrans-
> Arb: Fixed- WRR32- WRR64- WRR128- TWRR128- WRR256-
> Ctrl: Enable+ ID=0 ArbSelect=Fixed TC/VC=01
> Status: NegoPending- InProgress-
> Capabilities: [250 v1] Latency Tolerance Reporting
> Max snoop latency: 3145728ns
> Max no snoop latency: 3145728ns
> Capabilities: [258 v1] L1 PM Substates
> L1SubCap: PCI-PM_L1.2+ PCI-PM_L1.1+ ASPM_L1.2+ ASPM_L1.1+ L1_PM_Substates+
>  PortCommonModeRestoreTime=255us PortTPowerOnTime=10us
> Capabilities: [128 v1] Power Budgeting <?>
> Capabilities: [600 v1] Vendor Specific Information: ID=0001 Rev=1 Len=024 <?>
> Capabilities: [900 v1] #19
>
> [7.6.] SCSI information (from /proc/scsi/scsi):
> Attached devices:
> Host: scsi0 Channel: 00 Id: 00 Lun: 00
>   Vendor: ATA      Model: ST1000LM024 HN-M Rev: 0001
>   Type:   Direct-Access                    ANSI  SCSI revision: 05
> Host: scsi1 Channel: 00 Id: 00 Lun: 00
>   Vendor: ATA      Model: CORSAIR FORCE LX Rev: 7A
>   Type:   Direct-Access                    ANSI  SCSI revision: 05
> Host: scsi2 Channel: 00 Id: 00 Lun: 00
>   Vendor: HL-DT-ST Model: DVDRAM GUA0N     Rev: AS00
>   Type:   CD-ROM                           ANSI  SCSI revision: 05
> Host: scsi3 Channel: 00 Id: 00 Lun: 00
>   Vendor: Multiple Model: Card  Reader     Rev: 1.00
>   Type:   Direct-Access                    ANSI  SCSI revision: 04
>
> [7.7.] Other information that might be relevant to the problem (please
> look in /proc and include all information that you think to be
> relevant):
> Downstream report may be found at
> https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1371914 .
>
> No results executing at a terminal:
> cat /proc/bus/input/devices | grep Touch
> --
> To unsubscribe from this list: send the line "unsubscribe linux-input" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* How to indicate hover touch when exact distance unknown?
From: Andrew de los Reyes @ 2014-09-23 14:37 UTC (permalink / raw)
  To: hdegoede, Benjamin Tissoires, rydberg, jikos, David Herrmann,
	peter.hutterer, dmitry.torokhov
  Cc: Linux Input

[resending as plain text for the list]

Hi folks,

More and more we're seeing touch input devices that support detection
of fingers that are above the surface and not touching. We were
thinking of writing a kernel patch for one such device. Normally we
would indicate distance with ABS_MT_DISTANCE, but we ran into the
problem that sometimes the hardware will not be able to report a
distance (or will stop reporting a distance when it's too great a
number), and we had the (bad) idea to simply report a value or 1 or
255 or something like that when distance is unknown.

Dmitry warned that a similar thing happened with PRESSURE a while ago,
and it was a mess as different drivers did different things.

We are now wondering if we should come up with a standard way to
indicate hover with or without distance (or with distance being
optional). Dmitry had the idea for a new tool type, HOVER; FINGER
would be for touches that are actually touching.

What do folks here think?

Thanks,
-andrew

^ permalink raw reply

* Re: How to indicate hover touch when exact distance unknown?
From: Benjamin Tissoires @ 2014-09-23 14:59 UTC (permalink / raw)
  To: Andrew de los Reyes
  Cc: hdegoede, rydberg, jikos, David Herrmann, peter.hutterer,
	dmitry.torokhov, Linux Input
In-Reply-To: <CAG_cf+dJfiqW_V1k4MfGMBNUK9Kgc4=9BPAuum7dbs6rkmAgrQ@mail.gmail.com>

Hi Andrew,

On Sep 23 2014 or thereabouts, Andrew de los Reyes wrote:
> Hi folks,
> 
> More and more we're seeing touch input devices that support detection of
> fingers that are above the surface and not touching. We were thinking of
> writing a kernel patch for one such device. Normally we would indicate
> distance with ABS_MT_DISTANCE, but we ran into the problem that sometimes
> the hardware will not be able to report a distance (or will stop reporting
> a distance when it's too great a number), and we had the (bad) idea to
> simply report a value or 1 or 255 or something like that when distance is
> unknown.

FWIW, hid-multitouch already support those devices.
ABS_MT_DISTANCE is set with a min/max of 0/1 when we detect win8
certified panels with hovering capability. By default the spec does not
provide the distance IIRC, and you only have one byte: InRange.

I think Xorg can deal with that (the touch emulation discards the
ABS_MT_DISTANCE, but the xorg-evdev driver should be smart enough to not
take BTN_TOUCH into account).

> 
> Dmitry warned that a similar thing happened with PRESSURE a while ago, and
> it was a mess as different drivers did different things.

As I said, IIRC, xorg-evdev is fine with that. For generic desktop, we
have to make sure libinput is aware, and then you only have to handle
your own xorg chromebook driver. This is not something which scares me
that much, especially given that this is what hid-multitouch reports
since the v3.9 kernel.
libinput is based on a per slot device information, so it is really easy
to implement if it is not already in place. xorg-Synaptics and xorg-Wacom
should not be ported to wayland from what I understood, so the mess with
several implementations can be solved easily.

> 
> We are now wondering if we should come up with a standard way to indicate
> hover with or without distance (or with distance being optional). Dmitry
> had the idea for a new tool type, HOVER; FINGER would be for touches that
> are actually touching.

The tool is still the finger. So I am not very happy with having a new
tool. In the end, it may also disturb older clients which will not know
what to do with HOVER.
And the ABS_MT_DISTANCE approach used to be fully retro-compatible
(assuming that the hovering distance is small enough for the user not to
detect it).

> 
> What do folks here think?
> 

I made my point. Unfortunately, I never had in my hand such device, so
I can not guarantee this approach is the best.

Cheers,
Benjamin


^ permalink raw reply

* Re: [PATCH] HID: input: Finish TransducerSerialNumber implementation
From: Benjamin Tissoires @ 2014-09-23 15:12 UTC (permalink / raw)
  To: Jason Gerecke; +Cc: linux-input, jkosina, pinglinux, Jason Gerecke
In-Reply-To: <1411405130-1663-1-git-send-email-killertofu@gmail.com>

Hi Jason,

On Sep 22 2014 or thereabouts, Jason Gerecke wrote:
> The commit which introduced TransducerSerialNumber (368c966) is missing
> two crucial implementation details. Firstly, the commit does not set the
> type/code/bit/max fields as expected later down the code which can cause
> the driver to crash when a tablet with this usage is connected. Secondly,
> the code to send a MSC_SERIAL event to userspace when this usage is seen
> in a report is nowhere to be found. This commit addresses both issues.
> 
> Signed-off-by: Jason Gerecke <jason.gerecke@wacom.com>
> ---
>  drivers/hid/hid-input.c | 9 +++++++++
>  1 file changed, 9 insertions(+)
> 
> diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
> index 2619f7f..abed624 100644
> --- a/drivers/hid/hid-input.c
> +++ b/drivers/hid/hid-input.c
> @@ -690,6 +690,10 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
>  
>  		case 0x5b: /* TransducerSerialNumber */
>  			set_bit(MSC_SERIAL, input->mscbit);
> +			usage->type = EV_MSC;
> +			usage->code = MSC_SERIAL;
> +			bit = input->mscbit;
> +			max = MSC_MAX;
>  			break;
>  
>  		default:  goto unknown;
> @@ -1041,6 +1045,11 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
>  		input_event(input, EV_KEY, BTN_TOUCH, value > a + ((b - a) >> 3));
>  	}
>  
> +	if (usage->hid == (HID_UP_DIGITIZER | 0x005b)) { /* TransducerSerialNumber */
> +		input_event(input, EV_MSC, MSC_SERIAL, value);
> +		return;
> +	}
> +

Are you sure that the generic call to 
"input_event(input, usage->type, usage->code, value);" in the end of
hidinput_hid_event() is not sufficient enough?

As long as the usage/code are set in the hid_usage struct, you should be
fine.

Cheers,
Benjamin

>  	if (usage->hid == (HID_UP_PID | 0x83UL)) { /* Simultaneous Effects Max */
>  		dbg_hid("Maximum Effects - %d\n",value);
>  		return;
> -- 
> 2.1.0
> 

^ permalink raw reply

* [PATCH] input/serio/i8042-x86ia64io.h: Fix Asus X450LCP touchpad detection
From: Marcos Paulo de Souza @ 2014-09-23 15:24 UTC (permalink / raw)
  To: linux-kernel
  Cc: Marcos Paulo de Souza, Dmitry Torokhov, Hans de Goede,
	Jiri Kosina, Tom Gundersen, Peter Hutterer, linux-input, stable

From: Marcos Paulo de Souza <marcos.souza.org@gmail.com>

Signed-off-by: Marcos Paulo de Souza <marcos.souza.org@gmail.com>
Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Cc: Hans de Goede <hdegoede@redhat.com>
Cc: Jiri Kosina <jkosina@suse.cz>
Cc: Tom Gundersen <teg@jklm.no>
Cc: Peter Hutterer <peter.hutterer@who-t.net>
Cc: linux-input@vger.kernel.org
Cc: stable@vger.kernel.org
---
 drivers/input/serio/i8042-x86ia64io.h | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h
index 136b7b20..ec6cb72 100644
--- a/drivers/input/serio/i8042-x86ia64io.h
+++ b/drivers/input/serio/i8042-x86ia64io.h
@@ -465,6 +465,15 @@ static const struct dmi_system_id __initconst i8042_dmi_nomux_table[] = {
 			DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion dv4 Notebook PC"),
 		},
 	},
+	{
+		/* Asus X450LCP */
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "X450LCP"),
+		},
+	},
+
+
 	{ }
 };
 
-- 
1.9.3

^ permalink raw reply related

* [PATCH 2/5] HID: wacom: split out input allocation and registration
From: Benjamin Tissoires @ 2014-09-23 16:08 UTC (permalink / raw)
  To: Jiri Kosina, Ping Cheng, killertofu; +Cc: linux-input, linux-kernel
In-Reply-To: <1411488489-10625-1-git-send-email-benjamin.tissoires@redhat.com>

If the input can be created earlier during probe, we can already populate
them while reading the report descriptor. This way, we can rely on the
hid subsystem directly for tablets which already provide a meaningful
report descriptor (like ISDv4-5).

This patch only splits the allocation and registration, but do not
change where we allocate the input. This will come in a later patch.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
---
 drivers/hid/wacom_sys.c | 96 ++++++++++++++++++++++++++++++++-----------------
 drivers/hid/wacom_wac.h |  1 +
 2 files changed, 64 insertions(+), 33 deletions(-)

diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c
index 97e1fef..62f3c89 100644
--- a/drivers/hid/wacom_sys.c
+++ b/drivers/hid/wacom_sys.c
@@ -1054,41 +1054,75 @@ static struct input_dev *wacom_allocate_input(struct wacom *wacom)
 	return input_dev;
 }
 
-static void wacom_unregister_inputs(struct wacom *wacom)
+static void wacom_free_inputs(struct wacom *wacom)
 {
-	if (wacom->wacom_wac.input)
-		input_unregister_device(wacom->wacom_wac.input);
-	if (wacom->wacom_wac.pad_input)
-		input_unregister_device(wacom->wacom_wac.pad_input);
-	wacom->wacom_wac.input = NULL;
-	wacom->wacom_wac.pad_input = NULL;
-	wacom_destroy_leds(wacom);
+	struct wacom_wac *wacom_wac = &(wacom->wacom_wac);
+
+	if (wacom_wac->input)
+		input_free_device(wacom_wac->input);
+	if (wacom_wac->pad_input)
+		input_free_device(wacom_wac->pad_input);
+	wacom_wac->input = NULL;
+	wacom_wac->pad_input = NULL;
 }
 
-static int wacom_register_inputs(struct wacom *wacom)
+static int wacom_allocate_inputs(struct wacom *wacom)
 {
 	struct input_dev *input_dev, *pad_input_dev;
 	struct wacom_wac *wacom_wac = &(wacom->wacom_wac);
-	int error;
 
 	input_dev = wacom_allocate_input(wacom);
 	pad_input_dev = wacom_allocate_input(wacom);
 	if (!input_dev || !pad_input_dev) {
-		error = -ENOMEM;
-		goto fail_allocate_input;
+		wacom_free_inputs(wacom);
+		return -ENOMEM;
 	}
 
 	wacom_wac->input = input_dev;
 	wacom_wac->pad_input = pad_input_dev;
 	wacom_wac->pad_input->name = wacom_wac->pad_name;
 
+	return 0;
+}
+
+static void wacom_clean_inputs(struct wacom *wacom)
+{
+	if (wacom->wacom_wac.input) {
+		if (wacom->wacom_wac.input_registered)
+			input_unregister_device(wacom->wacom_wac.input);
+		else
+			input_free_device(wacom->wacom_wac.input);
+	}
+	if (wacom->wacom_wac.pad_input) {
+		if (wacom->wacom_wac.input_registered)
+			input_unregister_device(wacom->wacom_wac.pad_input);
+		else
+			input_free_device(wacom->wacom_wac.pad_input);
+	}
+	wacom->wacom_wac.input = NULL;
+	wacom->wacom_wac.pad_input = NULL;
+	wacom_destroy_leds(wacom);
+}
+
+static int wacom_register_inputs(struct wacom *wacom)
+{
+	struct input_dev *input_dev, *pad_input_dev;
+	struct wacom_wac *wacom_wac = &(wacom->wacom_wac);
+	int error;
+
+	input_dev = wacom_wac->input;
+	pad_input_dev = wacom_wac->pad_input;
+
+	if (!input_dev || !pad_input_dev)
+		return -EINVAL;
+
 	error = wacom_setup_input_capabilities(input_dev, wacom_wac);
 	if (error)
-		goto fail_input_cap;
+		return error;
 
 	error = input_register_device(input_dev);
 	if (error)
-		goto fail_register_input;
+		return error;
 
 	error = wacom_setup_pad_input_capabilities(pad_input_dev, wacom_wac);
 	if (error) {
@@ -1106,6 +1140,8 @@ static int wacom_register_inputs(struct wacom *wacom)
 			goto fail_leds;
 	}
 
+	wacom_wac->input_registered = true;
+
 	return 0;
 
 fail_leds:
@@ -1113,16 +1149,7 @@ fail_leds:
 	pad_input_dev = NULL;
 fail_register_pad_input:
 	input_unregister_device(input_dev);
-	input_dev = NULL;
-fail_register_input:
-fail_input_cap:
 	wacom_wac->input = NULL;
-	wacom_wac->pad_input = NULL;
-fail_allocate_input:
-	if (input_dev)
-		input_free_device(input_dev);
-	if (pad_input_dev)
-		input_free_device(pad_input_dev);
 	return error;
 }
 
@@ -1147,13 +1174,13 @@ static void wacom_wireless_work(struct work_struct *work)
 	hdev1 = usb_get_intfdata(usbdev->config->interface[1]);
 	wacom1 = hid_get_drvdata(hdev1);
 	wacom_wac1 = &(wacom1->wacom_wac);
-	wacom_unregister_inputs(wacom1);
+	wacom_clean_inputs(wacom1);
 
 	/* Touch interface */
 	hdev2 = usb_get_intfdata(usbdev->config->interface[2]);
 	wacom2 = hid_get_drvdata(hdev2);
 	wacom_wac2 = &(wacom2->wacom_wac);
-	wacom_unregister_inputs(wacom2);
+	wacom_clean_inputs(wacom2);
 
 	if (wacom_wac->pid == 0) {
 		hid_info(wacom->hdev, "wireless tablet disconnected\n");
@@ -1187,7 +1214,8 @@ static void wacom_wireless_work(struct work_struct *work)
 		wacom_wac1->shared->touch_max = wacom_wac1->features.touch_max;
 		wacom_wac1->shared->type = wacom_wac1->features.type;
 		wacom_wac1->pid = wacom_wac->pid;
-		error = wacom_register_inputs(wacom1);
+		error = wacom_allocate_inputs(wacom1) ||
+			wacom_register_inputs(wacom1);
 		if (error)
 			goto fail;
 
@@ -1208,7 +1236,8 @@ static void wacom_wireless_work(struct work_struct *work)
 			snprintf(wacom_wac2->pad_name, WACOM_NAME_MAX,
 				 "%s (WL) Pad", wacom_wac2->features.name);
 			wacom_wac2->pid = wacom_wac->pid;
-			error = wacom_register_inputs(wacom2);
+			error = wacom_allocate_inputs(wacom2) ||
+				wacom_register_inputs(wacom2);
 			if (error)
 				goto fail;
 
@@ -1225,8 +1254,8 @@ static void wacom_wireless_work(struct work_struct *work)
 	return;
 
 fail:
-	wacom_unregister_inputs(wacom1);
-	wacom_unregister_inputs(wacom2);
+	wacom_clean_inputs(wacom1);
+	wacom_clean_inputs(wacom2);
 	return;
 }
 
@@ -1400,7 +1429,8 @@ static int wacom_probe(struct hid_device *hdev,
 	}
 
 	if (!(features->quirks & WACOM_QUIRK_NO_INPUT)) {
-		error = wacom_register_inputs(wacom);
+		error = wacom_allocate_inputs(wacom) ||
+			wacom_register_inputs(wacom);
 		if (error)
 			goto fail_register_inputs;
 	}
@@ -1434,11 +1464,11 @@ static int wacom_probe(struct hid_device *hdev,
 	return 0;
 
 fail_hw_start:
-	wacom_unregister_inputs(wacom);
+	wacom_clean_inputs(wacom);
 	if (hdev->bus == BUS_BLUETOOTH)
 		device_remove_file(&hdev->dev, &dev_attr_speed);
 fail_register_inputs:
-	wacom_unregister_inputs(wacom);
+	wacom_clean_inputs(wacom);
 	wacom_destroy_battery(wacom);
 fail_battery:
 	wacom_remove_shared_data(wacom_wac);
@@ -1458,7 +1488,7 @@ static void wacom_remove(struct hid_device *hdev)
 	hid_hw_stop(hdev);
 
 	cancel_work_sync(&wacom->work);
-	wacom_unregister_inputs(wacom);
+	wacom_clean_inputs(wacom);
 	if (hdev->bus == BUS_BLUETOOTH)
 		device_remove_file(&hdev->dev, &dev_attr_speed);
 	wacom_destroy_battery(wacom);
diff --git a/drivers/hid/wacom_wac.h b/drivers/hid/wacom_wac.h
index 339ab5d..72f9ca8 100644
--- a/drivers/hid/wacom_wac.h
+++ b/drivers/hid/wacom_wac.h
@@ -167,6 +167,7 @@ struct wacom_wac {
 	struct wacom_shared *shared;
 	struct input_dev *input;
 	struct input_dev *pad_input;
+	bool input_registered;
 	int pid;
 	int battery_capacity;
 	int num_contacts_left;
-- 
2.1.0

^ permalink raw reply related

* [PATCH 3/5] HID: wacom: move allocation of inputs earlier
From: Benjamin Tissoires @ 2014-09-23 16:08 UTC (permalink / raw)
  To: Jiri Kosina, Ping Cheng, killertofu; +Cc: linux-input, linux-kernel
In-Reply-To: <1411488489-10625-1-git-send-email-benjamin.tissoires@redhat.com>

This allows to have the input devices ready in while parsing the reports
descriptor.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
---
 drivers/hid/wacom_sys.c | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c
index 62f3c89..21ac2ba 100644
--- a/drivers/hid/wacom_sys.c
+++ b/drivers/hid/wacom_sys.c
@@ -1357,6 +1357,12 @@ static int wacom_probe(struct hid_device *hdev,
 	mutex_init(&wacom->lock);
 	INIT_WORK(&wacom->work, wacom_wireless_work);
 
+	if (!(features->quirks & WACOM_QUIRK_NO_INPUT)) {
+		error = wacom_allocate_inputs(wacom);
+		if (error)
+			goto fail_allocate_inputs;
+	}
+
 	/* set the default size in case we do not get them from hid */
 	wacom_set_default_phy(features);
 
@@ -1429,8 +1435,7 @@ static int wacom_probe(struct hid_device *hdev,
 	}
 
 	if (!(features->quirks & WACOM_QUIRK_NO_INPUT)) {
-		error = wacom_allocate_inputs(wacom) ||
-			wacom_register_inputs(wacom);
+		error = wacom_register_inputs(wacom);
 		if (error)
 			goto fail_register_inputs;
 	}
@@ -1464,7 +1469,6 @@ static int wacom_probe(struct hid_device *hdev,
 	return 0;
 
 fail_hw_start:
-	wacom_clean_inputs(wacom);
 	if (hdev->bus == BUS_BLUETOOTH)
 		device_remove_file(&hdev->dev, &dev_attr_speed);
 fail_register_inputs:
@@ -1473,6 +1477,8 @@ fail_register_inputs:
 fail_battery:
 	wacom_remove_shared_data(wacom_wac);
 fail_shared_data:
+	wacom_clean_inputs(wacom);
+fail_allocate_inputs:
 fail_type:
 fail_pktlen:
 fail_parse:
-- 
2.1.0

^ permalink raw reply related

* [PATCH 4/5] HID: wacom: implement generic HID handling for pen generic devices
From: Benjamin Tissoires @ 2014-09-23 16:08 UTC (permalink / raw)
  To: Jiri Kosina, Ping Cheng, killertofu; +Cc: linux-input, linux-kernel
In-Reply-To: <1411488489-10625-1-git-send-email-benjamin.tissoires@redhat.com>

ISDv4 and v5 are plain HID devices. We can directly implement a generic
HID parsing/handling and remove the need to manually add those PID in
the list of supported devices.

This patch implements the pen support only. The finger part will come in
a later patch.

To be properly notified of an .event() and a .report(), we need to force
hid-core to go through the HID parsing. By default, wacom.ko binds only
hidraw, so the hid parsing is not done by hid-core. When a true HID device
is there, we add the flag HID_CLAIMED_DRIVER to hid->claimed which will
force hid-core to parse the incoming reports.
(Note that this can be easily backported by directly setting the .claimed
flag to HID_CLAIMED_DRIVER even if hid-core does not support
HID_CONNECT_DRIVER)

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
---
 drivers/hid/hid-core.c  |   3 +
 drivers/hid/wacom.h     |   6 ++
 drivers/hid/wacom_sys.c |  12 +++-
 drivers/hid/wacom_wac.c | 179 ++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/hid/wacom_wac.h |   8 +++
 include/linux/hid.h     |   2 +
 6 files changed, 208 insertions(+), 2 deletions(-)

diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index eb50818..73bd9e2 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1591,6 +1591,9 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask)
 	if ((connect_mask & HID_CONNECT_HIDRAW) && !hidraw_connect(hdev))
 		hdev->claimed |= HID_CLAIMED_HIDRAW;
 
+	if (connect_mask & HID_CONNECT_DRIVER)
+		hdev->claimed |= HID_CLAIMED_DRIVER;
+
 	/* Drivers with the ->raw_event callback set are not required to connect
 	 * to any other listener. */
 	if (!hdev->claimed && !hdev->driver->raw_event) {
diff --git a/drivers/hid/wacom.h b/drivers/hid/wacom.h
index 64bc1b2..0cc5344 100644
--- a/drivers/hid/wacom.h
+++ b/drivers/hid/wacom.h
@@ -89,6 +89,7 @@
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/mod_devicetable.h>
+#include <linux/hid.h>
 #include <linux/usb/input.h>
 #include <linux/power_supply.h>
 #include <asm/unaligned.h>
@@ -143,4 +144,9 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev,
 				   struct wacom_wac *wacom_wac);
 int wacom_setup_pad_input_capabilities(struct input_dev *input_dev,
 				       struct wacom_wac *wacom_wac);
+void wacom_wac_usage_mapping(struct hid_device *hdev,
+		struct hid_field *field, struct hid_usage *usage);
+int wacom_wac_event(struct hid_device *hdev, struct hid_field *field,
+		struct hid_usage *usage, __s32 value);
+void wacom_wac_report(struct hid_device *hdev, struct hid_report *report);
 #endif
diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c
index 21ac2ba..dd288b2 100644
--- a/drivers/hid/wacom_sys.c
+++ b/drivers/hid/wacom_sys.c
@@ -13,7 +13,6 @@
 
 #include "wacom_wac.h"
 #include "wacom.h"
-#include <linux/hid.h>
 
 #define WAC_MSG_RETRIES		5
 
@@ -215,6 +214,9 @@ static void wacom_usage_mapping(struct hid_device *hdev,
 			features->pressure_max = field->logical_maximum;
 		break;
 	}
+
+	if (features->type == HID_GENERIC)
+		wacom_wac_usage_mapping(hdev, field, usage);
 }
 
 static void wacom_parse_hid(struct hid_device *hdev,
@@ -1318,6 +1320,7 @@ static int wacom_probe(struct hid_device *hdev,
 	struct wacom_wac *wacom_wac;
 	struct wacom_features *features;
 	int error;
+	unsigned int connect_mask = HID_CONNECT_HIDRAW;
 
 	if (!id->driver_data)
 		return -EINVAL;
@@ -1451,8 +1454,11 @@ static int wacom_probe(struct hid_device *hdev,
 	/* Note that if query fails it is not a hard failure */
 	wacom_query_tablet_data(hdev, features);
 
+	if (features->type == HID_GENERIC)
+		connect_mask |= HID_CONNECT_DRIVER;
+
 	/* Regular HID work starts now */
-	error = hid_hw_start(hdev, HID_CONNECT_HIDRAW);
+	error = hid_hw_start(hdev, connect_mask);
 	if (error) {
 		hid_err(hdev, "hw start failed\n");
 		goto fail_hw_start;
@@ -1532,6 +1538,8 @@ static struct hid_driver wacom_driver = {
 	.id_table =	wacom_ids,
 	.probe =	wacom_probe,
 	.remove =	wacom_remove,
+	.event =	wacom_wac_event,
+	.report =	wacom_wac_report,
 #ifdef CONFIG_PM
 	.resume =	wacom_resume,
 	.reset_resume =	wacom_reset_resume,
diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
index b8180e4..e77d46d 100644
--- a/drivers/hid/wacom_wac.c
+++ b/drivers/hid/wacom_wac.c
@@ -1248,6 +1248,176 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, size_t len)
 	return 0;
 }
 
+static void wacom_map_usage(struct wacom *wacom, struct hid_usage *usage,
+		struct hid_field *field, __u8 type, __u16 code, int fuzz)
+{
+	struct wacom_wac *wacom_wac = &wacom->wacom_wac;
+	struct input_dev *input = wacom_wac->input;
+	int fmin = field->logical_minimum;
+	int fmax = field->logical_maximum;
+
+	usage->type = type;
+	usage->code = code;
+
+	set_bit(type, input->evbit);
+
+	switch (type) {
+	case EV_ABS:
+		input_set_abs_params(input, code, fmin, fmax, fuzz, 0);
+		input_abs_set_res(input, code,
+				  hidinput_calc_abs_res(field, code));
+		break;
+	case EV_KEY:
+		input_set_capability(input, EV_KEY, code);
+		break;
+	case EV_MSC:
+		input_set_capability(input, EV_MSC, code);
+		break;
+	}
+}
+
+static void wacom_wac_pen_usage_mapping(struct hid_device *hdev,
+		struct hid_field *field, struct hid_usage *usage)
+{
+	struct wacom *wacom = hid_get_drvdata(hdev);
+
+	switch (usage->hid) {
+	case HID_GD_X:
+		wacom_map_usage(wacom, usage, field, EV_ABS, ABS_X, 4);
+		break;
+	case HID_GD_Y:
+		wacom_map_usage(wacom, usage, field, EV_ABS, ABS_Y, 4);
+		break;
+	case HID_DG_TIPPRESSURE:
+		wacom_map_usage(wacom, usage, field, EV_ABS, ABS_PRESSURE, 0);
+		break;
+	case HID_DG_INRANGE:
+		wacom_map_usage(wacom, usage, field, EV_KEY, BTN_TOOL_PEN, 0);
+		break;
+	case HID_DG_INVERT:
+		wacom_map_usage(wacom, usage, field, EV_KEY,
+				BTN_TOOL_RUBBER, 0);
+		break;
+	case HID_DG_ERASER:
+	case HID_DG_TIPSWITCH:
+		wacom_map_usage(wacom, usage, field, EV_KEY, BTN_TOUCH, 0);
+		break;
+	case HID_DG_BARRELSWITCH:
+		wacom_map_usage(wacom, usage, field, EV_KEY, BTN_STYLUS, 0);
+		break;
+	case HID_DG_BARRELSWITCH2:
+		wacom_map_usage(wacom, usage, field, EV_KEY, BTN_STYLUS2, 0);
+		break;
+	case HID_DG_TOOLSERIALNUMBER:
+		wacom_map_usage(wacom, usage, field, EV_MSC, MSC_SERIAL, 0);
+		break;
+	}
+}
+
+static int wacom_wac_pen_event(struct hid_device *hdev, struct hid_field *field,
+		struct hid_usage *usage, __s32 value)
+{
+	struct wacom *wacom = hid_get_drvdata(hdev);
+	struct wacom_wac *wacom_wac = &wacom->wacom_wac;
+	struct input_dev *input = wacom_wac->input;
+
+	/* checking which Tool / tip switch to send */
+	switch (usage->hid) {
+	case HID_DG_INRANGE:
+		wacom_wac->hid_data.inrange_state = value;
+		return 0;
+	case HID_DG_INVERT:
+		wacom_wac->hid_data.invert_state = value;
+		return 0;
+	case HID_DG_ERASER:
+	case HID_DG_TIPSWITCH:
+		wacom_wac->hid_data.tipswitch |= value;
+		return 0;
+	}
+
+	/* send pen events only when touch is up or forced out */
+	if (!usage->type || wacom_wac->shared->touch_down)
+		return 0;
+
+	input_event(input, usage->type, usage->code, value);
+
+	return 0;
+}
+
+static void wacom_wac_pen_report(struct hid_device *hdev,
+		struct hid_report *report)
+{
+	struct wacom *wacom = hid_get_drvdata(hdev);
+	struct wacom_wac *wacom_wac = &wacom->wacom_wac;
+	struct input_dev *input = wacom_wac->input;
+	bool prox = wacom_wac->hid_data.inrange_state;
+
+	if (!wacom_wac->shared->stylus_in_proximity) /* first in prox */
+		/* Going into proximity select tool */
+		wacom_wac->tool[0] = wacom_wac->hid_data.invert_state ?
+						BTN_TOOL_RUBBER : BTN_TOOL_PEN;
+
+	/* keep pen state for touch events */
+	wacom_wac->shared->stylus_in_proximity = prox;
+
+	/* send pen events only when touch is up or forced out */
+	if (!wacom_wac->shared->touch_down) {
+		input_report_key(input, BTN_TOUCH,
+				wacom_wac->hid_data.tipswitch);
+		input_report_key(input, wacom_wac->tool[0], prox);
+
+		wacom_wac->hid_data.tipswitch = false;
+
+		input_sync(input);
+	}
+}
+
+#define WACOM_PEN_FIELD(f)	(((f)->logical == HID_DG_STYLUS) || \
+				 ((f)->physical == HID_DG_STYLUS))
+#define WACOM_FINGER_FIELD(f)	(((f)->logical == HID_DG_FINGER) || \
+				 ((f)->physical == HID_DG_FINGER))
+
+void wacom_wac_usage_mapping(struct hid_device *hdev,
+		struct hid_field *field, struct hid_usage *usage)
+{
+	struct wacom *wacom = hid_get_drvdata(hdev);
+	struct wacom_wac *wacom_wac = &wacom->wacom_wac;
+	struct input_dev *input = wacom_wac->input;
+
+	/* currently, only direct devices have proper hid report descriptors */
+	__set_bit(INPUT_PROP_DIRECT, input->propbit);
+
+	if (WACOM_PEN_FIELD(field))
+		return wacom_wac_pen_usage_mapping(hdev, field, usage);
+}
+
+int wacom_wac_event(struct hid_device *hdev, struct hid_field *field,
+		struct hid_usage *usage, __s32 value)
+{
+	struct wacom *wacom = hid_get_drvdata(hdev);
+
+	if (wacom->wacom_wac.features.type != HID_GENERIC)
+		return 0;
+
+	if (WACOM_PEN_FIELD(field))
+		return wacom_wac_pen_event(hdev, field, usage, value);
+
+	return 0;
+}
+
+void wacom_wac_report(struct hid_device *hdev, struct hid_report *report)
+{
+	struct wacom *wacom = hid_get_drvdata(hdev);
+	struct wacom_wac *wacom_wac = &wacom->wacom_wac;
+	struct hid_field *field = report->field[0];
+
+	if (wacom_wac->features.type != HID_GENERIC)
+		return;
+
+	if (WACOM_PEN_FIELD(field))
+		return wacom_wac_pen_report(hdev, report);
+}
+
 static int wacom_bpt_touch(struct wacom_wac *wacom)
 {
 	struct wacom_features *features = &wacom->features;
@@ -1746,6 +1916,10 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev,
 
 	input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
 
+	if (features->type == HID_GENERIC)
+		/* setup has already been done */
+		return 0;
+
 	__set_bit(BTN_TOUCH, input_dev->keybit);
 	__set_bit(ABS_MISC, input_dev->absbit);
 
@@ -2585,6 +2759,9 @@ static const struct wacom_features wacom_features_0x30C =
 	  .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x30A, .touch_max = 10,
 	  .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
 
+static const struct wacom_features wacom_features_HID_ANY_ID =
+	{ "Wacom HID", .type = HID_GENERIC };
+
 #define USB_DEVICE_WACOM(prod)						\
 	HID_DEVICE(BUS_USB, HID_GROUP_WACOM, USB_VENDOR_ID_WACOM, prod),\
 	.driver_data = (kernel_ulong_t)&wacom_features_##prod
@@ -2729,6 +2906,8 @@ const struct hid_device_id wacom_ids[] = {
 	{ USB_DEVICE_WACOM(0x4004) },
 	{ USB_DEVICE_WACOM(0x5000) },
 	{ USB_DEVICE_WACOM(0x5002) },
+
+	{ USB_DEVICE_WACOM(HID_ANY_ID) },
 	{ }
 };
 MODULE_DEVICE_TABLE(hid, wacom_ids);
diff --git a/drivers/hid/wacom_wac.h b/drivers/hid/wacom_wac.h
index 72f9ca8..f472eac 100644
--- a/drivers/hid/wacom_wac.h
+++ b/drivers/hid/wacom_wac.h
@@ -113,6 +113,7 @@ enum {
 	MTSCREEN,
 	MTTPC,
 	MTTPC_B,
+	HID_GENERIC,
 	MAX_TYPE
 };
 
@@ -154,6 +155,12 @@ struct wacom_shared {
 	struct input_dev *touch_input;
 };
 
+struct hid_data {
+	bool inrange_state;
+	bool invert_state;
+	bool tipswitch;
+};
+
 struct wacom_wac {
 	char name[WACOM_NAME_MAX];
 	char pad_name[WACOM_NAME_MAX];
@@ -175,6 +182,7 @@ struct wacom_wac {
 	int ps_connected;
 	u8 bt_features;
 	u8 bt_high_speed;
+	struct hid_data hid_data;
 };
 
 #endif
diff --git a/include/linux/hid.h b/include/linux/hid.h
index 26ee25f..78ea9bf 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -265,6 +265,7 @@ struct hid_item {
 #define HID_CONNECT_HIDDEV		0x08
 #define HID_CONNECT_HIDDEV_FORCE	0x10
 #define HID_CONNECT_FF			0x20
+#define HID_CONNECT_DRIVER		0x40
 #define HID_CONNECT_DEFAULT	(HID_CONNECT_HIDINPUT|HID_CONNECT_HIDRAW| \
 		HID_CONNECT_HIDDEV|HID_CONNECT_FF)
 
@@ -441,6 +442,7 @@ struct hid_output_fifo {
 #define HID_CLAIMED_INPUT	1
 #define HID_CLAIMED_HIDDEV	2
 #define HID_CLAIMED_HIDRAW	4
+#define HID_CLAIMED_DRIVER	8
 
 #define HID_STAT_ADDED		1
 #define HID_STAT_PARSED		2
-- 
2.1.0

^ permalink raw reply related

* [PATCH 5/5] HID: wacom: implement the finger part of the HID generic handling
From: Benjamin Tissoires @ 2014-09-23 16:08 UTC (permalink / raw)
  To: Jiri Kosina, Ping Cheng, killertofu; +Cc: linux-input, linux-kernel
In-Reply-To: <1411488489-10625-1-git-send-email-benjamin.tissoires@redhat.com>

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
---
 drivers/hid/wacom_sys.c |  39 ++++++++++++++--
 drivers/hid/wacom_wac.c | 120 ++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/hid/wacom_wac.h |   8 ++++
 3 files changed, 164 insertions(+), 3 deletions(-)

diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c
index dd288b2..8593047 100644
--- a/drivers/hid/wacom_sys.c
+++ b/drivers/hid/wacom_sys.c
@@ -109,6 +109,7 @@ static void wacom_feature_mapping(struct hid_device *hdev,
 {
 	struct wacom *wacom = hid_get_drvdata(hdev);
 	struct wacom_features *features = &wacom->wacom_wac.features;
+	struct hid_data *hid_data = &wacom->wacom_wac.hid_data;
 	u8 *data;
 	int ret;
 
@@ -128,6 +129,16 @@ static void wacom_feature_mapping(struct hid_device *hdev,
 			kfree(data);
 		}
 		break;
+	case HID_DG_INPUTMODE:
+		/* Ignore if value index is out of bounds. */
+		if (usage->usage_index >= field->report_count) {
+			dev_err(&hdev->dev, "HID_DG_INPUTMODE out of range\n");
+			break;
+		}
+
+		hid_data->inputmode = field->report->id;
+		hid_data->inputmode_index = usage->usage_index;
+		break;
 	}
 }
 
@@ -255,6 +266,25 @@ static void wacom_parse_hid(struct hid_device *hdev,
 	}
 }
 
+static int wacom_hid_set_device_mode(struct hid_device *hdev)
+{
+	struct wacom *wacom = hid_get_drvdata(hdev);
+	struct hid_data *hid_data = &wacom->wacom_wac.hid_data;
+	struct hid_report *r;
+	struct hid_report_enum *re;
+
+	if (hid_data->inputmode < 0)
+		return 0;
+
+	re = &(hdev->report_enum[HID_FEATURE_REPORT]);
+	r = re->report_id_hash[hid_data->inputmode];
+	if (r) {
+		r->field[0]->value[hid_data->inputmode_index] = 2;
+		hid_hw_request(hdev, r, HID_REQ_SET_REPORT);
+	}
+	return 0;
+}
+
 static int wacom_set_device_mode(struct hid_device *hdev, int report_id,
 		int length, int mode)
 {
@@ -347,6 +377,9 @@ static int wacom_query_tablet_data(struct hid_device *hdev,
 	if (hdev->bus == BUS_BLUETOOTH)
 		return wacom_bt_query_tablet_data(hdev, 1, features);
 
+	if (features->type == HID_GENERIC)
+		return wacom_hid_set_device_mode(hdev);
+
 	if (features->device_type == BTN_TOOL_FINGER) {
 		if (features->type > TABLETPC) {
 			/* MT Tablet PC touch */
@@ -1451,9 +1484,6 @@ static int wacom_probe(struct hid_device *hdev,
 				 error);
 	}
 
-	/* Note that if query fails it is not a hard failure */
-	wacom_query_tablet_data(hdev, features);
-
 	if (features->type == HID_GENERIC)
 		connect_mask |= HID_CONNECT_DRIVER;
 
@@ -1464,6 +1494,9 @@ static int wacom_probe(struct hid_device *hdev,
 		goto fail_hw_start;
 	}
 
+	/* Note that if query fails it is not a hard failure */
+	wacom_query_tablet_data(hdev, features);
+
 	if (features->quirks & WACOM_QUIRK_MONITOR)
 		error = hid_hw_open(hdev);
 
diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
index e77d46d..586b240 100644
--- a/drivers/hid/wacom_wac.c
+++ b/drivers/hid/wacom_wac.c
@@ -1372,6 +1372,117 @@ static void wacom_wac_pen_report(struct hid_device *hdev,
 	}
 }
 
+static void wacom_wac_finger_usage_mapping(struct hid_device *hdev,
+		struct hid_field *field, struct hid_usage *usage)
+{
+	struct wacom *wacom = hid_get_drvdata(hdev);
+	struct wacom_wac *wacom_wac = &wacom->wacom_wac;
+	struct input_dev *input = wacom_wac->input;
+	unsigned touch_max = wacom_wac->features.touch_max;
+
+	switch (usage->hid) {
+	case HID_GD_X:
+		if (touch_max == 1)
+			wacom_map_usage(wacom, usage, field, EV_ABS, ABS_X, 4);
+		else
+			wacom_map_usage(wacom, usage, field, EV_ABS,
+					ABS_MT_POSITION_X, 4);
+		break;
+	case HID_GD_Y:
+		if (touch_max == 1)
+			wacom_map_usage(wacom, usage, field, EV_ABS, ABS_Y, 4);
+		else
+			wacom_map_usage(wacom, usage, field, EV_ABS,
+					ABS_MT_POSITION_Y, 4);
+		break;
+	case HID_DG_CONTACTID:
+		input_mt_init_slots(input, wacom_wac->features.touch_max,
+			INPUT_MT_DIRECT);
+		break;
+	case HID_DG_INRANGE:
+		break;
+	case HID_DG_INVERT:
+		break;
+	case HID_DG_TIPSWITCH:
+		wacom_map_usage(wacom, usage, field, EV_KEY, BTN_TOUCH, 0);
+		break;
+	}
+}
+
+static int wacom_wac_finger_event(struct hid_device *hdev,
+		struct hid_field *field, struct hid_usage *usage, __s32 value)
+{
+	struct wacom *wacom = hid_get_drvdata(hdev);
+	struct wacom_wac *wacom_wac = &wacom->wacom_wac;
+
+	switch (usage->hid) {
+	case HID_GD_X:
+		wacom_wac->hid_data.x = value;
+		break;
+	case HID_GD_Y:
+		wacom_wac->hid_data.y = value;
+		break;
+	case HID_DG_CONTACTID:
+		wacom_wac->hid_data.id = value;
+		break;
+	case HID_DG_TIPSWITCH:
+		wacom_wac->hid_data.tipswitch = value;
+		break;
+	}
+
+
+	return 0;
+}
+
+static void wacom_wac_finger_mt_report(struct wacom_wac *wacom_wac,
+		struct input_dev *input, bool touch)
+{
+	int slot;
+	struct hid_data *hid_data = &wacom_wac->hid_data;
+
+	slot = input_mt_get_slot_by_key(input, hid_data->id);
+
+	input_mt_slot(input, slot);
+	input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
+	if (touch) {
+		input_report_abs(input, ABS_MT_POSITION_X, hid_data->x);
+		input_report_abs(input, ABS_MT_POSITION_Y, hid_data->y);
+	}
+	input_mt_sync_frame(input);
+}
+
+static void wacom_wac_finger_single_touch_report(struct wacom_wac *wacom_wac,
+		struct input_dev *input, bool touch)
+{
+	struct hid_data *hid_data = &wacom_wac->hid_data;
+
+	if (touch) {
+		input_report_abs(input, ABS_X, hid_data->x);
+		input_report_abs(input, ABS_Y, hid_data->y);
+	}
+	input_report_key(input, BTN_TOUCH, touch);
+}
+
+static void wacom_wac_finger_report(struct hid_device *hdev,
+		struct hid_report *report)
+{
+	struct wacom *wacom = hid_get_drvdata(hdev);
+	struct wacom_wac *wacom_wac = &wacom->wacom_wac;
+	struct input_dev *input = wacom_wac->input;
+	bool touch = wacom_wac->hid_data.tipswitch &&
+		     !wacom_wac->shared->stylus_in_proximity;
+	unsigned touch_max = wacom_wac->features.touch_max;
+
+	if (touch_max > 1)
+		wacom_wac_finger_mt_report(wacom_wac, input, touch);
+	else
+		wacom_wac_finger_single_touch_report(wacom_wac, input, touch);
+	input_sync(input);
+
+	/* keep touch state for pen event */
+	wacom_wac->shared->touch_down = touch;
+}
+
 #define WACOM_PEN_FIELD(f)	(((f)->logical == HID_DG_STYLUS) || \
 				 ((f)->physical == HID_DG_STYLUS))
 #define WACOM_FINGER_FIELD(f)	(((f)->logical == HID_DG_FINGER) || \
@@ -1389,6 +1500,9 @@ void wacom_wac_usage_mapping(struct hid_device *hdev,
 
 	if (WACOM_PEN_FIELD(field))
 		return wacom_wac_pen_usage_mapping(hdev, field, usage);
+
+	if (WACOM_FINGER_FIELD(field))
+		return wacom_wac_finger_usage_mapping(hdev, field, usage);
 }
 
 int wacom_wac_event(struct hid_device *hdev, struct hid_field *field,
@@ -1402,6 +1516,9 @@ int wacom_wac_event(struct hid_device *hdev, struct hid_field *field,
 	if (WACOM_PEN_FIELD(field))
 		return wacom_wac_pen_event(hdev, field, usage, value);
 
+	if (WACOM_FINGER_FIELD(field))
+		return wacom_wac_finger_event(hdev, field, usage, value);
+
 	return 0;
 }
 
@@ -1416,6 +1533,9 @@ void wacom_wac_report(struct hid_device *hdev, struct hid_report *report)
 
 	if (WACOM_PEN_FIELD(field))
 		return wacom_wac_pen_report(hdev, report);
+
+	if (WACOM_FINGER_FIELD(field))
+		return wacom_wac_finger_report(hdev, report);
 }
 
 static int wacom_bpt_touch(struct wacom_wac *wacom)
diff --git a/drivers/hid/wacom_wac.h b/drivers/hid/wacom_wac.h
index f472eac..0f0b85e 100644
--- a/drivers/hid/wacom_wac.h
+++ b/drivers/hid/wacom_wac.h
@@ -156,9 +156,17 @@ struct wacom_shared {
 };
 
 struct hid_data {
+	__s16 inputmode;	/* InputMode HID feature, -1 if non-existent */
+	__s16 inputmode_index;	/* InputMode HID feature index in the report */
 	bool inrange_state;
 	bool invert_state;
 	bool tipswitch;
+	int x;
+	int y;
+	int pressure;
+	int width;
+	int height;
+	int id;
 };
 
 struct wacom_wac {
-- 
2.1.0

^ permalink raw reply related

* [PATCH 0/5] HID: wacom: introduce generic HID handling
From: Benjamin Tissoires @ 2014-09-23 16:08 UTC (permalink / raw)
  To: Jiri Kosina, Ping Cheng, killertofu; +Cc: linux-input, linux-kernel

Hi guys,

So, this patch series aims at supporting natively any future HID compliant wacom
tablet. Those found on the various laptops (ISDv4/5) already are HID compliant
and they should work in the future without any modification of the kernel.

Few things to note here:
- I used the PID 0x00E6 found on the Lenovo X230 for the tests
- I did not removed its entry in the list because there is a slightly different
  behavior while using this patch set: when more than two fingers are on the
  screen, the tablet stops sending finger events, while with the wacom
  proprietary bits, it continues to send them. Besides that, the events emitted
  before and after the patch series are the same (at least on the E6)
- I can not rely on hid-input directly because wacom wants to be in control of
  the input devices it creates. This might be solved in the future, but for now
  it is just easier to rewrite the few mapping/events handling than trying to
  fit in the hid-input model.
- there will still be more specific use cases to handle later (see the joke of
  the MS surface 3 pen[1] for instance), but this should give a roughly working
  pen/touch support for those future devices.

Jason, I would be very glad if you could conduct a few tests for this on the
ISDv4/5 sensors you have.

Cheers,
Benjamin

[1] http://who-t.blogspot.com/2014/09/stylus-behaviour-on-microsoft-surface-3.html

Benjamin Tissoires (5):
  HID: wacom: rename failN with some meaningful information
  HID: wacom: split out input allocation and registration
  HID: wacom: move allocation of inputs earlier
  HID: wacom: implement generic HID handling for pen generic devices
  HID: wacom: implement the finger part of the HID generic handling

 drivers/hid/hid-core.c  |   3 +
 drivers/hid/wacom.h     |   6 +
 drivers/hid/wacom_sys.c | 184 +++++++++++++++++++++--------
 drivers/hid/wacom_wac.c | 299 ++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/hid/wacom_wac.h |  17 +++
 include/linux/hid.h     |   2 +
 6 files changed, 462 insertions(+), 49 deletions(-)

-- 
2.1.0


^ permalink raw reply

* [PATCH 1/5] HID: wacom: rename failN with some meaningful information
From: Benjamin Tissoires @ 2014-09-23 16:08 UTC (permalink / raw)
  To: Jiri Kosina, Ping Cheng, killertofu; +Cc: linux-input, linux-kernel
In-Reply-To: <1411488489-10625-1-git-send-email-benjamin.tissoires@redhat.com>

When we have to deal with new elements in probe, having the exit labels
named sequencially is a pain to maintain. Put a meaningful name instead
so that we do not have to renumber them on inserts.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
---
 drivers/hid/wacom_sys.c | 49 +++++++++++++++++++++++++++++--------------------
 1 file changed, 29 insertions(+), 20 deletions(-)

diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c
index 2508628..97e1fef 100644
--- a/drivers/hid/wacom_sys.c
+++ b/drivers/hid/wacom_sys.c
@@ -1075,7 +1075,7 @@ static int wacom_register_inputs(struct wacom *wacom)
 	pad_input_dev = wacom_allocate_input(wacom);
 	if (!input_dev || !pad_input_dev) {
 		error = -ENOMEM;
-		goto fail1;
+		goto fail_allocate_input;
 	}
 
 	wacom_wac->input = input_dev;
@@ -1084,11 +1084,11 @@ static int wacom_register_inputs(struct wacom *wacom)
 
 	error = wacom_setup_input_capabilities(input_dev, wacom_wac);
 	if (error)
-		goto fail2;
+		goto fail_input_cap;
 
 	error = input_register_device(input_dev);
 	if (error)
-		goto fail2;
+		goto fail_register_input;
 
 	error = wacom_setup_pad_input_capabilities(pad_input_dev, wacom_wac);
 	if (error) {
@@ -1099,25 +1099,26 @@ static int wacom_register_inputs(struct wacom *wacom)
 	} else {
 		error = input_register_device(pad_input_dev);
 		if (error)
-			goto fail3;
+			goto fail_register_pad_input;
 
 		error = wacom_initialize_leds(wacom);
 		if (error)
-			goto fail4;
+			goto fail_leds;
 	}
 
 	return 0;
 
-fail4:
+fail_leds:
 	input_unregister_device(pad_input_dev);
 	pad_input_dev = NULL;
-fail3:
+fail_register_pad_input:
 	input_unregister_device(input_dev);
 	input_dev = NULL;
-fail2:
+fail_register_input:
+fail_input_cap:
 	wacom_wac->input = NULL;
 	wacom_wac->pad_input = NULL;
-fail1:
+fail_allocate_input:
 	if (input_dev)
 		input_free_device(input_dev);
 	if (pad_input_dev)
@@ -1305,7 +1306,7 @@ static int wacom_probe(struct hid_device *hdev,
 	error = hid_parse(hdev);
 	if (error) {
 		hid_err(hdev, "parse failed\n");
-		goto fail1;
+		goto fail_parse;
 	}
 
 	wacom_wac = &wacom->wacom_wac;
@@ -1314,12 +1315,12 @@ static int wacom_probe(struct hid_device *hdev,
 	features->pktlen = wacom_compute_pktlen(hdev);
 	if (features->pktlen > WACOM_PKGLEN_MAX) {
 		error = -EINVAL;
-		goto fail1;
+		goto fail_pktlen;
 	}
 
 	if (features->check_for_hid_type && features->hid_type != hdev->type) {
 		error = -ENODEV;
-		goto fail1;
+		goto fail_type;
 	}
 
 	wacom->usbdev = dev;
@@ -1388,20 +1389,20 @@ static int wacom_probe(struct hid_device *hdev,
 
 		error = wacom_add_shared_data(hdev);
 		if (error)
-			goto fail1;
+			goto fail_shared_data;
 	}
 
 	if (!(features->quirks & WACOM_QUIRK_MONITOR) &&
 	     (features->quirks & WACOM_QUIRK_BATTERY)) {
 		error = wacom_initialize_battery(wacom);
 		if (error)
-			goto fail2;
+			goto fail_battery;
 	}
 
 	if (!(features->quirks & WACOM_QUIRK_NO_INPUT)) {
 		error = wacom_register_inputs(wacom);
 		if (error)
-			goto fail3;
+			goto fail_register_inputs;
 	}
 
 	if (hdev->bus == BUS_BLUETOOTH) {
@@ -1419,7 +1420,7 @@ static int wacom_probe(struct hid_device *hdev,
 	error = hid_hw_start(hdev, HID_CONNECT_HIDRAW);
 	if (error) {
 		hid_err(hdev, "hw start failed\n");
-		goto fail4;
+		goto fail_hw_start;
 	}
 
 	if (features->quirks & WACOM_QUIRK_MONITOR)
@@ -1432,12 +1433,20 @@ static int wacom_probe(struct hid_device *hdev,
 
 	return 0;
 
- fail4:	if (hdev->bus == BUS_BLUETOOTH)
+fail_hw_start:
+	wacom_unregister_inputs(wacom);
+	if (hdev->bus == BUS_BLUETOOTH)
 		device_remove_file(&hdev->dev, &dev_attr_speed);
+fail_register_inputs:
 	wacom_unregister_inputs(wacom);
- fail3:	wacom_destroy_battery(wacom);
- fail2:	wacom_remove_shared_data(wacom_wac);
- fail1:	kfree(wacom);
+	wacom_destroy_battery(wacom);
+fail_battery:
+	wacom_remove_shared_data(wacom_wac);
+fail_shared_data:
+fail_type:
+fail_pktlen:
+fail_parse:
+	kfree(wacom);
 	hid_set_drvdata(hdev, NULL);
 	return error;
 }
-- 
2.1.0


^ permalink raw reply related

* Re: How to indicate hover touch when exact distance unknown?
From: Dmitry Torokhov @ 2014-09-23 16:28 UTC (permalink / raw)
  To: Benjamin Tissoires
  Cc: Andrew de los Reyes, hdegoede, rydberg, jikos, David Herrmann,
	peter.hutterer, Linux Input
In-Reply-To: <20140923145916.GA3110@mail.corp.redhat.com>

Hi Benjamin,

On Tue, Sep 23, 2014 at 10:59:16AM -0400, Benjamin Tissoires wrote:
> Hi Andrew,
> 
> On Sep 23 2014 or thereabouts, Andrew de los Reyes wrote:
> > Hi folks,
> > 
> > More and more we're seeing touch input devices that support detection of
> > fingers that are above the surface and not touching. We were thinking of
> > writing a kernel patch for one such device. Normally we would indicate
> > distance with ABS_MT_DISTANCE, but we ran into the problem that sometimes
> > the hardware will not be able to report a distance (or will stop reporting
> > a distance when it's too great a number), and we had the (bad) idea to
> > simply report a value or 1 or 255 or something like that when distance is
> > unknown.
> 
> FWIW, hid-multitouch already support those devices.
> ABS_MT_DISTANCE is set with a min/max of 0/1 when we detect win8
> certified panels with hovering capability. By default the spec does not
> provide the distance IIRC, and you only have one byte: InRange.

Hmm, I missed that and this is unfortunate. The ABS capabilities
advertised by the devices should match their real capabilities. If
device can't properly report distance it should not be using
ABS_MT_DISTANCE/ABS_DISTANCE...

> 
> I think Xorg can deal with that (the touch emulation discards the
> ABS_MT_DISTANCE, but the xorg-evdev driver should be smart enough to not
> take BTN_TOUCH into account).
> 
> > 
> > Dmitry warned that a similar thing happened with PRESSURE a while ago, and
> > it was a mess as different drivers did different things.
> 
> As I said, IIRC, xorg-evdev is fine with that. For generic desktop, we
> have to make sure libinput is aware, and then you only have to handle
> your own xorg chromebook driver. This is not something which scares me
> that much, especially given that this is what hid-multitouch reports
> since the v3.9 kernel.
> libinput is based on a per slot device information, so it is really easy
> to implement if it is not already in place. xorg-Synaptics and xorg-Wacom
> should not be ported to wayland from what I understood, so the mess with
> several implementations can be solved easily.
> 
> > 
> > We are now wondering if we should come up with a standard way to indicate
> > hover with or without distance (or with distance being optional). Dmitry
> > had the idea for a new tool type, HOVER; FINGER would be for touches that
> > are actually touching.
> 
> The tool is still the finger.

Do we reliably know that it is a finger and not a pen or eraser or some
other tool? If we do then obviously introducing new tool will not fly.

> So I am not very happy with having a new
> tool. In the end, it may also disturb older clients which will not know
> what to do with HOVER.
> And the ABS_MT_DISTANCE approach used to be fully retro-compatible
> (assuming that the hovering distance is small enough for the user not to
> detect it).

Except that if we start getting devices that can actually tell the
distance we'd need special casing 0/1 handling, no?

Thanks.

-- 
Dmitry

^ permalink raw reply

* Re: [PATCH] HID: add new gamepad LED constants
From: Dmitry Torokhov @ 2014-09-23 16:37 UTC (permalink / raw)
  To: David Herrmann
  Cc: Michael Wright, open list:HID CORE LAYER, Michael Wright,
	Jiri Kosina
In-Reply-To: <CANq1E4R80GwEL43ngV5-8cWXTQAchfCOwpYSxUZfL7Hxy5yVSw@mail.gmail.com>

On Tue, Sep 16, 2014 at 12:00:26PM +0200, David Herrmann wrote:
> Hi
> 
> On Tue, Sep 16, 2014 at 12:58 AM, Dmitry Torokhov
> <dmitry.torokhov@gmail.com> wrote:
> >> The LED subsystem lacks any unprivileged API to control LEDs.
> >
> > As far as I can see it is the same as for input devices. You just need
> > to make sure the device owner can access needed attributes, such as
> > brightness.
> >
> >> There's no cdev to control write-access to the LED API. /sys has never
> >> been intended as unprivileged API
> >
> > chmod/chown works just fine on sysfs attributes.
> 
> Sure it is. You can even use ACLs. But that doesn't mean it provides a
> proper API environment. Udev maintainers have always said "sysfs is
> only writable by root". Reasons mostly being the following:
> 
> * sysfs exists only once. Unlike char-devs, you cannot create multiple
> independent entry-points to the device node. Instead, there's only a
> single entry point which has to be shared between all users (across
> sessions, across containers, across user-namespaces, across
> pid-namespaces).
> 
> * sysfs does not provide per-file contexts. Unlike char-devs, sysfs
> never knows the context of the user that writes into an attribute. It
> cannot associate private data to the open file and it cannot track the
> time the user releases the device again. It cannot multiplex across
> multiple simultaneous users.
> 
> * sysfs is not "lightweight". People always say they don't want full
> blown char-devs because sysfs is much lighter. Don't know where that
> came from.. but looking at the amount of inodes and files needed for
> sysfs APIs, it's definitely not faster nor smaller than char-devs.

I do not recall anyone saying char dev is super heavy. I was only saying
that stuffing everything in input device does not make much sense and
that full-blown input device structure is quite heavy in itself, without
even talking about all interface drivers that can attach to it.

> 
> Just look at IIO to see what happens if you write evdev-like APIs
> based on sysfs attributes "because it's lightweight". It's a mess.
> 
> Sure, one solution would be to provide char-devs for LEDs.

Exactly. If something like chardev is better API for LEDs then do it.
LED subsystem allows us to create many different "triggers".

> But then
> one char-dev per LED sounds like overkill, so my proposal is to

Not really. I think it would be fine.

>
> include it in the input API like we always did. You're free to
> disagree on that. I'm just saying that sysfs APIs to access LEDs on
> GamePads (which this patch is mostly targeted at, I guess) is making
> user-space life miserable.

How can we make life not miserable, but still not merge this into input?
I see the draw of saying "this is only for gamepads", "this is only for
keyboards", etc... But then I see generic-purpose LEDs getting way into
(we already had LED_MAIL, etc creep in), we have LEDs on network cards
(which are incidentally not part of network stack), istorage enclosures
have their LEDs, and all other LEds everywhere.

> It's the same discussion we had with
> backlights for years and we're trying eagerly to merge them into the
> DRM char-devs.
> 

So keyboard backlight is going to be controlled by display chardev? Or
we are fragmenting backlights into different classes?

Thanks.

-- 
Dmitry

^ permalink raw reply

* Re: [PATCH] HID: add new gamepad LED constants
From: Dmitry Torokhov @ 2014-09-23 16:40 UTC (permalink / raw)
  To: Michael Wright
  Cc: Pierre-Loup A. Griffais, Simon Wood, David Herrmann,
	HID CORE LAYER, Michael Wright, Jiri Kosina
In-Reply-To: <CAON4U=OdnD+zOSojh09mWz=GmBd5adTxnqXZbZcn363SD7cmxw@mail.gmail.com>

On Mon, Sep 22, 2014 at 02:36:57PM -0700, Michael Wright wrote:
> Just so I can figure out the next steps, are you still convinced that
> new LEDs should go in the led subsystem Dmitry?

At this point I would really prefer them not be part of input_dev
structure. Actually there are patches to convert input core to use
generic LEDs for the standard keyboard leds, sadly there is an open
question of how to handle access via legacy and the new API together so
I was not able to merge it [yet].

Thanks.

-- 
Dmitry

^ permalink raw reply

* Re: How to indicate hover touch when exact distance unknown?
From: Andrew de los Reyes @ 2014-09-23 16:46 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: Benjamin Tissoires, hdegoede, rydberg, jikos, David Herrmann,
	peter.hutterer, Linux Input
In-Reply-To: <20140923162811.GB40700@core.coreip.homeip.net>

On Tue, Sep 23, 2014 at 9:28 AM, Dmitry Torokhov
<dmitry.torokhov@gmail.com> wrote:
> Hi Benjamin,
>
> On Tue, Sep 23, 2014 at 10:59:16AM -0400, Benjamin Tissoires wrote:
>> Hi Andrew,
>>
>> On Sep 23 2014 or thereabouts, Andrew de los Reyes wrote:
>> > Hi folks,
>> >
>> > More and more we're seeing touch input devices that support detection of
>> > fingers that are above the surface and not touching. We were thinking of
>> > writing a kernel patch for one such device. Normally we would indicate
>> > distance with ABS_MT_DISTANCE, but we ran into the problem that sometimes
>> > the hardware will not be able to report a distance (or will stop reporting
>> > a distance when it's too great a number), and we had the (bad) idea to
>> > simply report a value or 1 or 255 or something like that when distance is
>> > unknown.
>>
>> FWIW, hid-multitouch already support those devices.
>> ABS_MT_DISTANCE is set with a min/max of 0/1 when we detect win8
>> certified panels with hovering capability. By default the spec does not
>> provide the distance IIRC, and you only have one byte: InRange.
>
> Hmm, I missed that and this is unfortunate. The ABS capabilities
> advertised by the devices should match their real capabilities. If
> device can't properly report distance it should not be using
> ABS_MT_DISTANCE/ABS_DISTANCE...
>
>>
>> I think Xorg can deal with that (the touch emulation discards the
>> ABS_MT_DISTANCE, but the xorg-evdev driver should be smart enough to not
>> take BTN_TOUCH into account).
>>
>> >
>> > Dmitry warned that a similar thing happened with PRESSURE a while ago, and
>> > it was a mess as different drivers did different things.
>>
>> As I said, IIRC, xorg-evdev is fine with that. For generic desktop, we
>> have to make sure libinput is aware, and then you only have to handle
>> your own xorg chromebook driver. This is not something which scares me
>> that much, especially given that this is what hid-multitouch reports
>> since the v3.9 kernel.
>> libinput is based on a per slot device information, so it is really easy
>> to implement if it is not already in place. xorg-Synaptics and xorg-Wacom
>> should not be ported to wayland from what I understood, so the mess with
>> several implementations can be solved easily.
>>
>> >
>> > We are now wondering if we should come up with a standard way to indicate
>> > hover with or without distance (or with distance being optional). Dmitry
>> > had the idea for a new tool type, HOVER; FINGER would be for touches that
>> > are actually touching.
>>
>> The tool is still the finger.
>
> Do we reliably know that it is a finger and not a pen or eraser or some
> other tool? If we do then obviously introducing new tool will not fly.

On a capacitive sensor, I think we do know, at least for finger vs
active stylus. To be fair, I do not spend much time working with
styluses, so I may not have the most info.

>
>> So I am not very happy with having a new
>> tool. In the end, it may also disturb older clients which will not know
>> what to do with HOVER.
>> And the ABS_MT_DISTANCE approach used to be fully retro-compatible
>> (assuming that the hovering distance is small enough for the user not to
>> detect it).
>
> Except that if we start getting devices that can actually tell the
> distance we'd need special casing 0/1 handling, no?
>
> Thanks.
>
> --
> Dmitry
> --
> To unsubscribe from this list: send the line "unsubscribe linux-input" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* RE: [PATCH] HID: input: Finish TransducerSerialNumber implementation
From: Jason Gerecke @ 2014-09-23 17:59 UTC (permalink / raw)
  To: Benjamin Tissoires, Jason Gerecke
  Cc: linux-input@vger.kernel.org, jkosina@suse.cz, pinglinux@gmail.com
In-Reply-To: <20140923151224.GB3110@mail.corp.redhat.com>

> -----Original Message-----
> From: Benjamin Tissoires [mailto:benjamin.tissoires@redhat.com]
> Sent: Tuesday, September 23, 2014 8:12 AM
> To: Jason Gerecke
> Cc: linux-input@vger.kernel.org; jkosina@suse.cz; pinglinux@gmail.com;
> Jason Gerecke
> Subject: Re: [PATCH] HID: input: Finish TransducerSerialNumber
> implementation
> 
> Hi Jason,
> 
> On Sep 22 2014 or thereabouts, Jason Gerecke wrote:
> > The commit which introduced TransducerSerialNumber (368c966) is
> > missing two crucial implementation details. Firstly, the commit does
> > not set the type/code/bit/max fields as expected later down the code
> > which can cause the driver to crash when a tablet with this usage is
> > connected. Secondly, the code to send a MSC_SERIAL event to userspace
> > when this usage is seen in a report is nowhere to be found. This commit
> addresses both issues.
> >
> > Signed-off-by: Jason Gerecke <jason.gerecke@wacom.com>
> > ---
> >  drivers/hid/hid-input.c | 9 +++++++++
> >  1 file changed, 9 insertions(+)
> >
> > diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index
> > 2619f7f..abed624 100644
> > --- a/drivers/hid/hid-input.c
> > +++ b/drivers/hid/hid-input.c
> > @@ -690,6 +690,10 @@ static void hidinput_configure_usage(struct
> > hid_input *hidinput, struct hid_fiel
> >
> >  		case 0x5b: /* TransducerSerialNumber */
> >  			set_bit(MSC_SERIAL, input->mscbit);
> > +			usage->type = EV_MSC;
> > +			usage->code = MSC_SERIAL;
> > +			bit = input->mscbit;
> > +			max = MSC_MAX;
> >  			break;
> >
> >  		default:  goto unknown;
> > @@ -1041,6 +1045,11 @@ void hidinput_hid_event(struct hid_device *hid,
> struct hid_field *field, struct
> >  		input_event(input, EV_KEY, BTN_TOUCH, value > a + ((b - a)
> >> 3));
> >  	}
> >
> > +	if (usage->hid == (HID_UP_DIGITIZER | 0x005b)) { /*
> TransducerSerialNumber */
> > +		input_event(input, EV_MSC, MSC_SERIAL, value);
> > +		return;
> > +	}
> > +
> 
> Are you sure that the generic call to
> "input_event(input, usage->type, usage->code, value);" in the end of
> hidinput_hid_event() is not sufficient enough?
> 
> As long as the usage/code are set in the hid_usage struct, you should be fine.
> 
> Cheers,
> Benjamin
> 

Hmmm... This might be an issue with the HID descriptor, actually. It looks like my hardware doesn't set the logical minimum and maximum for the field, so the (quite out-of-range) value is ignored. I start seeing data after patching the descriptor to add these in, but the code is set to MSC_PULSELED instead of MSC_SERIAL. I suspect that the existing call to 'set_bit' in the TransducerSerialNumber case is to blame (which makes it act like 'map_foo' instead of 'map_foo_clear').

Updated patch forthcoming...

Jason

> >  	if (usage->hid == (HID_UP_PID | 0x83UL)) { /* Simultaneous Effects
> Max */
> >  		dbg_hid("Maximum Effects - %d\n",value);
> >  		return;
> > --
> > 2.1.0
> >

^ permalink raw reply

* [PATCH] HID: input: Fix TransducerSerialNumber implementation
From: Jason Gerecke @ 2014-09-23 18:09 UTC (permalink / raw)
  To: Benjamin Tissoires, Jason Gerecke, linux-input@vger.kernel.org,
	jkosina@suse.cz, pinglinux@gmail.com
  Cc: Jason Gerecke
In-Reply-To: <Message-ID: <6B3C86448604A642A31AAD3F8C07EA7724F0B8CD@Exchange1.wacom.com>

The commit which introduced TransducerSerialNumber (368c966) is missing
two crucial implementation details. Firstly, the commit does not set the
type/code/bit/max fields as expected later down the code which can cause
the driver to crash when a tablet with this usage is connected. Secondly,
the call to 'set_bit' causes MSC_PULSELED to be sent instead of the
expected MSC_SERIAL. This commit addreses both issues.

Signed-off-by: Jason Gerecke <jason.gerecke@wacom.com>
---
 drivers/hid/hid-input.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index 2619f7f..cb1b3fa 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -689,7 +689,10 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
 			break;
 
 		case 0x5b: /* TransducerSerialNumber */
-			set_bit(MSC_SERIAL, input->mscbit);
+			usage->type = EV_MSC;
+			usage->code = MSC_SERIAL;
+			bit = input->mscbit;
+			max = MSC_MAX;
 			break;
 
 		default:  goto unknown;
-- 
2.1.0


^ permalink raw reply related

* Re: How to indicate hover touch when exact distance unknown?
From: Henrik Rydberg @ 2014-09-23 18:52 UTC (permalink / raw)
  To: Andrew de los Reyes, Dmitry Torokhov
  Cc: Benjamin Tissoires, hdegoede, jikos, David Herrmann,
	peter.hutterer, Linux Input
In-Reply-To: <CAG_cf+fuugk4QK_1BtWnJWzunWT4QeSus_2cuPpYH_8UCUjMOQ@mail.gmail.com>

>>> So I am not very happy with having a new
>>> tool. In the end, it may also disturb older clients which will not know
>>> what to do with HOVER.
>>> And the ABS_MT_DISTANCE approach used to be fully retro-compatible
>>> (assuming that the hovering distance is small enough for the user not to
>>> detect it).
>>
>> Except that if we start getting devices that can actually tell the
>> distance we'd need special casing 0/1 handling, no?

Logically, a hovering object which does not support real distance reporting
would simply be present in the contact list but have ABS_MT_TOUCH = 0. However,
I do not think all layers of the stack supports this notion.

Henrik


^ permalink raw reply

* [PATCH] Input: driver for the Goodix touchpanel
From: Bastien Nocera @ 2014-09-23 22:28 UTC (permalink / raw)
  To: Dmitry Torokhov, Henrik Rydberg, linux-input; +Cc: Benjamin Tissoires

Add a driver for the Goodix touchscreen panel found in Onda v975w
tablets. The driver is based off the Android driver gt9xx.c found
in some Android code dumps, but now bears no resemblance to the original
driver.

The driver was tested on the aforementioned tablet.

Signed-off-by: Bastien Nocera <hadess@hadess.net>
Tested-by: Bastien Nocera <hadess@hadess.net>
---
 MAINTAINERS                        |   6 +
 drivers/input/touchscreen/Kconfig  |  13 ++
 drivers/input/touchscreen/Makefile |   1 +
 drivers/input/touchscreen/goodix.c | 452 +++++++++++++++++++++++++++++++++++++
 4 files changed, 472 insertions(+)
 create mode 100644 drivers/input/touchscreen/goodix.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 670b3dc..7a37464 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4057,6 +4057,12 @@ L:	linux-media@vger.kernel.org
 S:	Maintained
 F:	drivers/media/usb/go7007/
 
+GOODIX TOUCHSCREEN
+M:	Bastien Nocera <hadess@hadess.net>
+L:	linux-input@vger.kernel.org
+S:	Maintained
+F:	drivers/input/touchscreen/goodix.c
+
 GPIO SUBSYSTEM
 M:	Linus Walleij <linus.walleij@linaro.org>
 M:	Alexandre Courbot <gnurou@gmail.com>
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 6bb9a7d..c328df3 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -283,6 +283,19 @@ config TOUCHSCREEN_FUJITSU
 	  To compile this driver as a module, choose M here: the
 	  module will be called fujitsu-ts.
 
+config TOUCHSCREEN_GOODIX
+	tristate "Goodix I2C touchscreen"
+	depends on I2C && ACPI
+	help
+	  Say Y here if you have the Goodix touchscreen (such as one
+	  installed in Onda v975w tablets) connected to your
+	  system.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called goodix.
+
 config TOUCHSCREEN_ILI210X
 	tristate "Ilitek ILI210X based touchscreen"
 	depends on I2C
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 4be94fc..55af212 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -33,6 +33,7 @@ obj-$(CONFIG_TOUCHSCREEN_EETI)		+= eeti_ts.o
 obj-$(CONFIG_TOUCHSCREEN_ELO)		+= elo.o
 obj-$(CONFIG_TOUCHSCREEN_EGALAX)	+= egalax_ts.o
 obj-$(CONFIG_TOUCHSCREEN_FUJITSU)	+= fujitsu_ts.o
+obj-$(CONFIG_TOUCHSCREEN_GOODIX)	+= goodix.o
 obj-$(CONFIG_TOUCHSCREEN_ILI210X)	+= ili210x.o
 obj-$(CONFIG_TOUCHSCREEN_INEXIO)	+= inexio.o
 obj-$(CONFIG_TOUCHSCREEN_INTEL_MID)	+= intel-mid-touch.o
diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c
new file mode 100644
index 0000000..bda6482
--- /dev/null
+++ b/drivers/input/touchscreen/goodix.c
@@ -0,0 +1,452 @@
+/*
+ *  driver for Goodix Touchscreens
+ *
+ *  Copyright (c) 2014 Red Hat Inc.
+ *
+ *  This code is based on gt9xx.c authored by andrew@goodix.com:
+ *
+ *  2010 - 2012 Goodix Technology.
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; version 2 of the License.
+ */
+
+#include <linux/kernel.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/input/mt.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <asm/unaligned.h>
+
+struct goodix_ts_data {
+	struct i2c_client *client;
+	struct input_dev *input_dev;
+	int abs_x_max;
+	int abs_y_max;
+	unsigned int max_touch_num;
+	unsigned int int_trigger_type;
+};
+
+#define GOODIX_MAX_HEIGHT		4096
+#define GOODIX_MAX_WIDTH		4096
+#define GOODIX_INT_TRIGGER		1
+#define GOODIX_MAX_TOUCH		10
+
+#define GOODIX_CONFIG_MAX_LENGTH	240
+
+/* Register defineS */
+#define GOODIX_READ_COOR_ADDR		0x814E
+#define GOODIX_REG_CONFIG_DATA		0x8047
+#define GOODIX_REG_VERSION		0x8140
+
+#define RESOLUTION_LOC		1
+#define TRIGGER_LOC		6
+
+#define GOODIX_INFO(fmt, arg...)       pr_info("<<-GTP-INFO->> "fmt"\n", ##arg)
+#define GOODIX_ERROR(fmt, arg...)      pr_err("<<-GTP-ERROR->> "fmt"\n", ##arg)
+
+static const char *goodix_ts_name = "Goodix Capacitive TouchScreen";
+static const unsigned long goodix_irq_flags[] = {
+	IRQ_TYPE_EDGE_RISING  | IRQF_ONESHOT,
+	IRQ_TYPE_EDGE_FALLING | IRQF_ONESHOT,
+	IRQ_TYPE_LEVEL_LOW    | IRQF_ONESHOT,
+	IRQ_TYPE_LEVEL_HIGH   | IRQF_ONESHOT
+};
+
+/**
+ * goodix_i2c_read - read data from a register of the i2c slave device.
+ *
+ * @client: i2c device.
+ * @reg: the register to read from.
+ * @buf: raw write data buffer.
+ * @len: length of the buffer to write
+ */
+static int goodix_i2c_read(struct i2c_client *client,
+				u16 reg, u8 *buf, int len)
+{
+	struct i2c_msg msgs[2];
+	u8 wbuf[2] = { reg >> 8, reg & 0xff };
+
+	msgs[0].flags = !I2C_M_RD;
+	msgs[0].addr  = client->addr;
+	msgs[0].len   = 2;
+	msgs[0].buf   = wbuf;
+
+	msgs[1].flags = I2C_M_RD;
+	msgs[1].addr  = client->addr;
+	msgs[1].len   = len;
+	msgs[1].buf   = buf;
+
+	return i2c_transfer(client->adapter, msgs, 2);
+}
+
+/**
+ * goodix_i2c_write - write data to the i2c slave device.
+ *
+ * @client: i2c device.
+ * @reg: the register to read to.
+ * @buf: raw write data buffer.
+ * @len: length of the buffer to write
+ */
+static int goodix_i2c_write(struct i2c_client *client,
+				u16 reg, u8 *buf, int len)
+{
+	struct i2c_msg msg;
+	int ret;
+	u8 *wbuf;
+
+	wbuf = kzalloc(len + 2, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	wbuf[0] = reg >> 8;
+	wbuf[1] = reg & 0xFF;
+	memcpy(&wbuf[2], buf, len);
+
+	msg.flags = !I2C_M_RD;
+	msg.addr  = client->addr;
+	msg.len   = len + 2;
+	msg.buf   = wbuf;
+
+	ret = i2c_transfer(client->adapter, &msg, 1);
+	kfree(wbuf);
+	return ret;
+}
+
+static int goodix_ts_read_input_report(struct goodix_ts_data *ts, u8 *data)
+{
+	int touch_num;
+	int ret;
+
+	ret = goodix_i2c_read(ts->client, GOODIX_READ_COOR_ADDR, data, 10);
+	if (ret < 0) {
+		GOODIX_ERROR("I2C transfer error (%d)\n", ret);
+		return ret;
+	}
+
+	touch_num = data[0] & 0x0f;
+	if (touch_num > GOODIX_MAX_TOUCH)
+		return -EPROTO;
+
+	if (touch_num > 1) {
+		ret = goodix_i2c_read(ts->client, GOODIX_READ_COOR_ADDR + 10,
+				   &data[10], 8 * (touch_num - 1));
+		if (ret < 0)
+			return ret;
+	}
+
+	return touch_num;
+}
+
+static void goodix_ts_parse_touch(struct goodix_ts_data *ts, u8 *coor_data)
+{
+	int id = coor_data[0] & 0x0F;
+	int input_x = get_unaligned_le16(&coor_data[1]);
+	int input_y = get_unaligned_le16(&coor_data[3]);
+	int input_w = get_unaligned_le16(&coor_data[5]);
+
+	input_mt_slot(ts->input_dev, id);
+	input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, true);
+	input_report_abs(ts->input_dev, ABS_MT_POSITION_X, input_x);
+	input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, input_y);
+	input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, input_w);
+	input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, input_w);
+}
+
+/**
+ * goodix_ts_work_func - Process incoming IRQ
+ *
+ * @ts: our goodix_ts_data pointer
+ *
+ * Called when the IRQ is triggered. Read the current device state, and push
+ * the input events to the user space.
+ */
+static void goodix_ts_work_func(struct goodix_ts_data *ts)
+{
+	u8  end_cmd[1] = {0};
+	u8  point_data[1 + 8 * GOODIX_MAX_TOUCH + 1];
+	int touch_num;
+	int i;
+
+	touch_num = goodix_ts_read_input_report(ts, point_data);
+	if (touch_num < 0)
+		goto exit_work_func;
+
+	for (i = 0; i < touch_num; i++)
+		goodix_ts_parse_touch(ts, &point_data[1 + 8 * i]);
+
+	input_mt_sync_frame(ts->input_dev);
+	input_sync(ts->input_dev);
+
+exit_work_func:
+	if (goodix_i2c_write(ts->client,
+				GOODIX_READ_COOR_ADDR, end_cmd, 1) < 0)
+		GOODIX_INFO("I2C write end_cmd error");
+}
+
+/**
+ * goodix_ts_irq_handler - The IRQ handler
+ *
+ * @irq: interrupt number.
+ * @dev_id: private data pointer.
+ */
+static irqreturn_t goodix_ts_irq_handler(int irq, void *dev_id)
+{
+	struct goodix_ts_data *ts = dev_id;
+
+	goodix_ts_work_func(ts);
+
+	return IRQ_HANDLED;
+}
+
+/**
+ * goodix_read_config - Read the embedded configuration of the panel
+ *
+ * @ts: our goodix_ts_data pointer
+ *
+ * Must be called during probe
+ */
+static void goodix_read_config(struct goodix_ts_data *ts)
+{
+	int ret;
+	u8 config[GOODIX_CONFIG_MAX_LENGTH];
+
+	ret = goodix_i2c_read(ts->client, GOODIX_REG_CONFIG_DATA, config,
+			   GOODIX_CONFIG_MAX_LENGTH);
+	if (ret < 0) {
+		GOODIX_ERROR("Error reading config, use default value!");
+		ts->abs_x_max = GOODIX_MAX_WIDTH;
+		ts->abs_y_max = GOODIX_MAX_HEIGHT;
+		ts->int_trigger_type = GOODIX_INT_TRIGGER;
+		return;
+	}
+
+	ts->abs_x_max = get_unaligned_le16(&config[RESOLUTION_LOC]);
+	ts->abs_y_max = get_unaligned_le16(&config[RESOLUTION_LOC + 2]);
+	ts->int_trigger_type = (config[TRIGGER_LOC]) & 0x03;
+	if ((!ts->abs_x_max) || (!ts->abs_y_max)) {
+		GOODIX_ERROR("Invalid config, use default value!");
+		ts->abs_x_max = GOODIX_MAX_WIDTH;
+		ts->abs_y_max = GOODIX_MAX_HEIGHT;
+	}
+}
+
+
+/**
+ * goodix_read_version - Read goodix touchscreen version
+ *
+ * @client: the i2c client
+ * @version: output buffer containing the version on success
+ */
+static int goodix_read_version(struct i2c_client *client, u16 *version)
+{
+	int ret;
+	int i;
+	u8 buf[6];
+
+	ret = goodix_i2c_read(client, GOODIX_REG_VERSION, buf, sizeof(buf));
+	if (ret < 0) {
+		GOODIX_ERROR("GTP read version failed");
+		return ret;
+	}
+
+	if (version)
+		*version = get_unaligned_le16(&buf[4]);
+
+	for (i = 0; i < 4; i++) {
+		if (!buf[i])
+			buf[i] = 0x30;
+	}
+	GOODIX_INFO("IC VERSION: %c%c%c%c_%02x%02x",
+			  buf[0], buf[1], buf[2], buf[3], buf[5], buf[4]);
+
+	return ret;
+}
+
+/**
+ * goodix_i2c_test - I2C test function to check if the device answers.
+ *
+ * @client: the i2c client
+ */
+static int goodix_i2c_test(struct i2c_client *client)
+{
+	u8 test;
+	int ret;
+	int retry = 0;
+
+	while (retry++ < 2) {
+		ret = goodix_i2c_read(client, GOODIX_REG_CONFIG_DATA,
+				      &test, 1);
+		if (ret > 0)
+			return ret;
+
+		GOODIX_ERROR("GTP i2c test failed time %d.", retry);
+		msleep(20);
+	}
+	return ret;
+}
+
+/**
+ * goodix_request_irq - Request the IRQ handler
+ *
+ * @ts: our goodix_ts_data pointer
+ *
+ * Must be called during probe
+ */
+static int goodix_request_irq(struct goodix_ts_data *ts)
+{
+	int ret;
+
+	ret = devm_request_threaded_irq(&ts->client->dev,
+					ts->client->irq, NULL,
+					goodix_ts_irq_handler,
+					goodix_irq_flags[ts->int_trigger_type],
+					ts->client->name,
+					ts);
+	if (ret) {
+		GOODIX_ERROR("Request IRQ failed! ERRNO:%d.", ret);
+		return -1;
+	}
+
+	disable_irq_nosync(ts->client->irq);
+	return 0;
+}
+
+/**
+ * goodix_request_input_dev - Allocate, populate and register the input device
+ *
+ * @ts: our goodix_ts_data pointer
+ *
+ * Must be called during probe
+ */
+static int goodix_request_input_dev(struct goodix_ts_data *ts)
+{
+	int ret;
+
+	ts->input_dev = devm_input_allocate_device(&ts->client->dev);
+	if (ts->input_dev == NULL) {
+		GOODIX_ERROR("Failed to allocate input device.");
+		return -ENOMEM;
+	}
+
+	ts->input_dev->evbit[0] = BIT_MASK(EV_SYN) |
+				  BIT_MASK(EV_KEY) |
+				  BIT_MASK(EV_ABS);
+
+	input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X, 0,
+				ts->abs_x_max, 0, 0);
+	input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, 0,
+				ts->abs_y_max, 0, 0);
+	input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0, 255, 0, 0);
+	input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
+
+	input_mt_init_slots(ts->input_dev, GOODIX_MAX_TOUCH,
+			    INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED);
+
+	ts->input_dev->name = goodix_ts_name;
+	ts->input_dev->phys = "input/ts";
+	ts->input_dev->id.bustype = BUS_I2C;
+	ts->input_dev->id.vendor = 0x0416;
+	ts->input_dev->id.product = 0x1001;
+	ts->input_dev->id.version = 10427;
+
+	ret = input_register_device(ts->input_dev);
+	if (ret) {
+		GOODIX_ERROR("Failed to register %s input device",
+			  ts->input_dev->name);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static int goodix_ts_probe(struct i2c_client *client,
+		const struct i2c_device_id *id)
+{
+	int ret;
+	struct goodix_ts_data *ts;
+	u16 version_info;
+
+	GOODIX_INFO("GTP I2C Address: 0x%02x", client->addr);
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		GOODIX_ERROR("I2C check functionality failed.");
+		return -ENODEV;
+	}
+	ts = devm_kzalloc(&client->dev, sizeof(*ts), GFP_KERNEL);
+	if (ts == NULL) {
+		GOODIX_ERROR("Alloc GFP_KERNEL memory failed.");
+		return -ENOMEM;
+	}
+
+	ts->client = client;
+	i2c_set_clientdata(client, ts);
+
+	ret = goodix_i2c_test(client);
+	if (ret < 0) {
+		client->addr = 0x5d;
+		ret = goodix_i2c_test(client);
+		if (ret < 0) {
+			GOODIX_ERROR("I2C communication ERROR!");
+			return -ENODEV;
+		}
+		GOODIX_INFO("GTP I2C new Address: 0x%02x", client->addr);
+	}
+
+	goodix_read_config(ts);
+
+	ret = goodix_request_input_dev(ts);
+	if (ret < 0) {
+		GOODIX_ERROR("GTP request input dev failed");
+		return ret;
+	}
+
+	ret = goodix_request_irq(ts);
+	if (ret < 0)
+		return ret;
+
+	ret = goodix_read_version(client, &version_info);
+	if (ret < 0) {
+		GOODIX_ERROR("Read version failed.");
+		return ret;
+	}
+
+	enable_irq(ts->client->irq);
+
+	return 0;
+}
+
+static const struct i2c_device_id goodix_ts_id[] = {
+	{ "GDIX1001:00", 0 },
+	{ }
+};
+
+static const struct acpi_device_id goodix_acpi_match[] = {
+	{ "GDIX1001", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(acpi, goodix_acpi_match);
+
+static struct i2c_driver goodix_ts_driver = {
+	.probe = goodix_ts_probe,
+	.id_table = goodix_ts_id,
+	.driver = {
+		.name = "Goodix-TS",
+		.owner = THIS_MODULE,
+		.acpi_match_table = goodix_acpi_match,
+	},
+};
+
+module_i2c_driver(goodix_ts_driver);
+
+MODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@gmail.com>");
+MODULE_AUTHOR("Bastien Nocera <hadess@hadess.net>");
+MODULE_DESCRIPTION("Goodix touchscreen driver");
+MODULE_LICENSE("GPL v2");
-- 
2.1.0



^ permalink raw reply related

* Re: [PATCH v4 1/14] input: cyapa: re-architecture driver to support multi-trackpads in one driver
From: Dmitry Torokhov @ 2014-09-24  0:18 UTC (permalink / raw)
  To: Dudley Du
  Cc: Rafael J. Wysocki, Benson Leung, Patrik Fimml, linux-input,
	linux-kernel
In-Reply-To: <53f70235.610e450a.3800.ffff83c7@mx.google.com>

Hi Dudley,

On Fri, Aug 22, 2014 at 04:41:07PM +0800, Dudley Du wrote:
> Dmitry,
> 
> Thanks for your feedback.
> 
> Thanks,
> Dudley
> 
> > -----Original Message-----
> > From: Dmitry Torokhov [mailto:dmitry.torokhov@gmail.com]
> > Sent: Friday, August 22, 2014 2:21 AM
> > To: Dudley Du
> > Cc: Rafael J. Wysocki; Benson Leung; Patrik Fimml; linux-input@vger.kernel.org;
> > linux-kernel@vger.kernel.org; Dudley Du
> > Subject: Re: [PATCH v4 1/14] input: cyapa: re-architecture driver to support
> > multi-trackpads in one driver
> > 
> > On Thu, Jul 17, 2014 at 02:47:24PM +0800, Dudley Du wrote:
> > > In order to support two different communication protocol based trackpad
> > > device in one cyapa, the new cyapa driver is re-designed with
> > > one cyapa driver core and two devices' functions component.
> > > The cyapa driver core is contained in this patch, it supplies the basic
> > > function with input and kernel system and also defined the interfaces
> > > that the devices' functions component needs to apply and support.
> > > Also, in order to speed up the system boot time, the device states
> > > detecting and probing process is put into the async thread.
> > > TEST=test on Chromebooks.
> > >
> > > Signed-off-by: Dudley Du <dudl@cypress.com>
> > > ---
> > >  drivers/input/mouse/Makefile |    4 +-
> > >  drivers/input/mouse/cyapa.c  | 1083 ++++++++++++++-------------------------
> > ---
> > >  drivers/input/mouse/cyapa.h  |  275 +++++++++++
> > >  3 files changed, 646 insertions(+), 716 deletions(-)
> > >  create mode 100644 drivers/input/mouse/cyapa.h
> > >
> > > diff --git a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile
> > > index c25efdb..8608eb7 100644
> > > --- a/drivers/input/mouse/Makefile
> > > +++ b/drivers/input/mouse/Makefile
> > > @@ -8,7 +8,7 @@ obj-$(CONFIG_MOUSE_AMIGA)		+= amimouse.o
> > >  obj-$(CONFIG_MOUSE_APPLETOUCH)		+= appletouch.o
> > >  obj-$(CONFIG_MOUSE_ATARI)		+= atarimouse.o
> > >  obj-$(CONFIG_MOUSE_BCM5974)		+= bcm5974.o
> > > -obj-$(CONFIG_MOUSE_CYAPA)		+= cyapa.o
> > > +obj-$(CONFIG_MOUSE_CYAPA)		+= cyapatp.o
> > >  obj-$(CONFIG_MOUSE_GPIO)		+= gpio_mouse.o
> > >  obj-$(CONFIG_MOUSE_INPORT)		+= inport.o
> > >  obj-$(CONFIG_MOUSE_LOGIBM)		+= logibm.o
> > > @@ -34,3 +34,5 @@ psmouse-$(CONFIG_MOUSE_PS2_SENTELIC)	+= sentelic.o
> > >  psmouse-$(CONFIG_MOUSE_PS2_TRACKPOINT)	+= trackpoint.o
> > >  psmouse-$(CONFIG_MOUSE_PS2_TOUCHKIT)	+= touchkit_ps2.o
> > >  psmouse-$(CONFIG_MOUSE_PS2_CYPRESS)	+= cypress_ps2.o
> > > +
> > > +cyapatp-y := cyapa.o
> > > diff --git a/drivers/input/mouse/cyapa.c b/drivers/input/mouse/cyapa.c
> > > index b409c3d..5fc8dbe 100644
> > > --- a/drivers/input/mouse/cyapa.c
> > > +++ b/drivers/input/mouse/cyapa.c
> > > @@ -6,7 +6,7 @@
> > >   *   Daniel Kurtz <djkurtz@chromium.org>
> > >   *   Benson Leung <bleung@chromium.org>
> > >   *
> > > - * Copyright (C) 2011-2012 Cypress Semiconductor, Inc.
> > > + * Copyright (C) 2011-2014 Cypress Semiconductor, Inc.
> > >   * Copyright (C) 2011-2012 Google, Inc.
> > >   *
> > >   * This file is subject to the terms and conditions of the GNU General
> > Public
> > > @@ -14,731 +14,114 @@
> > >   * more details.
> > >   */
> > >
> > > +#include <linux/debugfs.h>
> > >  #include <linux/delay.h>
> > >  #include <linux/i2c.h>
> > >  #include <linux/input.h>
> > >  #include <linux/input/mt.h>
> > >  #include <linux/interrupt.h>
> > >  #include <linux/module.h>
> > > +#include <linux/mutex.h>
> > >  #include <linux/slab.h>
> > > +#include <linux/uaccess.h>
> > > +#include <linux/pm_runtime.h>
> > > +#include "cyapa.h"
> > >
> > > -/* APA trackpad firmware generation */
> > > -#define CYAPA_GEN3   0x03   /* support MT-protocol B with tracking ID. */
> > > -
> > > -#define CYAPA_NAME   "Cypress APA Trackpad (cyapa)"
> > > -
> > > -/* commands for read/write registers of Cypress trackpad */
> > > -#define CYAPA_CMD_SOFT_RESET       0x00
> > > -#define CYAPA_CMD_POWER_MODE       0x01
> > > -#define CYAPA_CMD_DEV_STATUS       0x02
> > > -#define CYAPA_CMD_GROUP_DATA       0x03
> > > -#define CYAPA_CMD_GROUP_CMD        0x04
> > > -#define CYAPA_CMD_GROUP_QUERY      0x05
> > > -#define CYAPA_CMD_BL_STATUS        0x06
> > > -#define CYAPA_CMD_BL_HEAD          0x07
> > > -#define CYAPA_CMD_BL_CMD           0x08
> > > -#define CYAPA_CMD_BL_DATA          0x09
> > > -#define CYAPA_CMD_BL_ALL           0x0a
> > > -#define CYAPA_CMD_BLK_PRODUCT_ID   0x0b
> > > -#define CYAPA_CMD_BLK_HEAD         0x0c
> > > -
> > > -/* report data start reg offset address. */
> > > -#define DATA_REG_START_OFFSET  0x0000
> > > -
> > > -#define BL_HEAD_OFFSET 0x00
> > > -#define BL_DATA_OFFSET 0x10
> > > -
> > > -/*
> > > - * Operational Device Status Register
> > > - *
> > > - * bit 7: Valid interrupt source
> > > - * bit 6 - 4: Reserved
> > > - * bit 3 - 2: Power status
> > > - * bit 1 - 0: Device status
> > > - */
> > > -#define REG_OP_STATUS     0x00
> > > -#define OP_STATUS_SRC     0x80
> > > -#define OP_STATUS_POWER   0x0c
> > > -#define OP_STATUS_DEV     0x03
> > > -#define OP_STATUS_MASK (OP_STATUS_SRC | OP_STATUS_POWER | OP_STATUS_DEV)
> > > -
> > > -/*
> > > - * Operational Finger Count/Button Flags Register
> > > - *
> > > - * bit 7 - 4: Number of touched finger
> > > - * bit 3: Valid data
> > > - * bit 2: Middle Physical Button
> > > - * bit 1: Right Physical Button
> > > - * bit 0: Left physical Button
> > > - */
> > > -#define REG_OP_DATA1       0x01
> > > -#define OP_DATA_VALID      0x08
> > > -#define OP_DATA_MIDDLE_BTN 0x04
> > > -#define OP_DATA_RIGHT_BTN  0x02
> > > -#define OP_DATA_LEFT_BTN   0x01
> > > -#define OP_DATA_BTN_MASK (OP_DATA_MIDDLE_BTN | OP_DATA_RIGHT_BTN | \
> > > -			  OP_DATA_LEFT_BTN)
> > > -
> > > -/*
> > > - * Bootloader Status Register
> > > - *
> > > - * bit 7: Busy
> > > - * bit 6 - 5: Reserved
> > > - * bit 4: Bootloader running
> > > - * bit 3 - 1: Reserved
> > > - * bit 0: Checksum valid
> > > - */
> > > -#define REG_BL_STATUS        0x01
> > > -#define BL_STATUS_BUSY       0x80
> > > -#define BL_STATUS_RUNNING    0x10
> > > -#define BL_STATUS_DATA_VALID 0x08
> > > -#define BL_STATUS_CSUM_VALID 0x01
> > > -
> > > -/*
> > > - * Bootloader Error Register
> > > - *
> > > - * bit 7: Invalid
> > > - * bit 6: Invalid security key
> > > - * bit 5: Bootloading
> > > - * bit 4: Command checksum
> > > - * bit 3: Flash protection error
> > > - * bit 2: Flash checksum error
> > > - * bit 1 - 0: Reserved
> > > - */
> > > -#define REG_BL_ERROR         0x02
> > > -#define BL_ERROR_INVALID     0x80
> > > -#define BL_ERROR_INVALID_KEY 0x40
> > > -#define BL_ERROR_BOOTLOADING 0x20
> > > -#define BL_ERROR_CMD_CSUM    0x10
> > > -#define BL_ERROR_FLASH_PROT  0x08
> > > -#define BL_ERROR_FLASH_CSUM  0x04
> > > -
> > > -#define BL_STATUS_SIZE  3  /* length of bootloader status registers */
> > > -#define BLK_HEAD_BYTES 32
> > > -
> > > -#define PRODUCT_ID_SIZE  16
> > > -#define QUERY_DATA_SIZE  27
> > > -#define REG_PROTOCOL_GEN_QUERY_OFFSET  20
> > > -
> > > -#define REG_OFFSET_DATA_BASE     0x0000
> > > -#define REG_OFFSET_COMMAND_BASE  0x0028
> > > -#define REG_OFFSET_QUERY_BASE    0x002a
> > > -
> > > -#define CAPABILITY_LEFT_BTN_MASK	(0x01 << 3)
> > > -#define CAPABILITY_RIGHT_BTN_MASK	(0x01 << 4)
> > > -#define CAPABILITY_MIDDLE_BTN_MASK	(0x01 << 5)
> > > -#define CAPABILITY_BTN_MASK  (CAPABILITY_LEFT_BTN_MASK | \
> > > -			      CAPABILITY_RIGHT_BTN_MASK | \
> > > -			      CAPABILITY_MIDDLE_BTN_MASK)
> > > -
> > > -#define CYAPA_OFFSET_SOFT_RESET  REG_OFFSET_COMMAND_BASE
> > > -
> > > -#define REG_OFFSET_POWER_MODE (REG_OFFSET_COMMAND_BASE + 1)
> > > -
> > > -#define PWR_MODE_MASK   0xfc
> > > -#define PWR_MODE_FULL_ACTIVE (0x3f << 2)
> > > -#define PWR_MODE_IDLE        (0x05 << 2) /* default sleep time is 50 ms. */
> > > -#define PWR_MODE_OFF         (0x00 << 2)
> > > -
> > > -#define PWR_STATUS_MASK      0x0c
> > > -#define PWR_STATUS_ACTIVE    (0x03 << 2)
> > > -#define PWR_STATUS_IDLE      (0x02 << 2)
> > > -#define PWR_STATUS_OFF       (0x00 << 2)
> > > -
> > > -/*
> > > - * CYAPA trackpad device states.
> > > - * Used in register 0x00, bit1-0, DeviceStatus field.
> > > - * Other values indicate device is in an abnormal state and must be reset.
> > > - */
> > > -#define CYAPA_DEV_NORMAL  0x03
> > > -#define CYAPA_DEV_BUSY    0x01
> > > -
> > > -enum cyapa_state {
> > > -	CYAPA_STATE_OP,
> > > -	CYAPA_STATE_BL_IDLE,
> > > -	CYAPA_STATE_BL_ACTIVE,
> > > -	CYAPA_STATE_BL_BUSY,
> > > -	CYAPA_STATE_NO_DEVICE,
> > > -};
> > > -
> > > -
> > > -struct cyapa_touch {
> > > -	/*
> > > -	 * high bits or x/y position value
> > > -	 * bit 7 - 4: high 4 bits of x position value
> > > -	 * bit 3 - 0: high 4 bits of y position value
> > > -	 */
> > > -	u8 xy_hi;
> > > -	u8 x_lo;  /* low 8 bits of x position value. */
> > > -	u8 y_lo;  /* low 8 bits of y position value. */
> > > -	u8 pressure;
> > > -	/* id range is 1 - 15.  It is incremented with every new touch. */
> > > -	u8 id;
> > > -} __packed;
> > > -
> > > -/* The touch.id is used as the MT slot id, thus max MT slot is 15 */
> > > -#define CYAPA_MAX_MT_SLOTS  15
> > > -
> > > -struct cyapa_reg_data {
> > > -	/*
> > > -	 * bit 0 - 1: device status
> > > -	 * bit 3 - 2: power mode
> > > -	 * bit 6 - 4: reserved
> > > -	 * bit 7: interrupt valid bit
> > > -	 */
> > > -	u8 device_status;
> > > -	/*
> > > -	 * bit 7 - 4: number of fingers currently touching pad
> > > -	 * bit 3: valid data check bit
> > > -	 * bit 2: middle mechanism button state if exists
> > > -	 * bit 1: right mechanism button state if exists
> > > -	 * bit 0: left mechanism button state if exists
> > > -	 */
> > > -	u8 finger_btn;
> > > -	/* CYAPA reports up to 5 touches per packet. */
> > > -	struct cyapa_touch touches[5];
> > > -} __packed;
> > > -
> > > -/* The main device structure */
> > > -struct cyapa {
> > > -	enum cyapa_state state;
> > > -
> > > -	struct i2c_client *client;
> > > -	struct input_dev *input;
> > > -	char phys[32];	/* device physical location */
> > > -	int irq;
> > > -	bool irq_wake;  /* irq wake is enabled */
> > > -	bool smbus;
> > > -
> > > -	/* read from query data region. */
> > > -	char product_id[16];
> > > -	u8 btn_capability;
> > > -	u8 gen;
> > > -	int max_abs_x;
> > > -	int max_abs_y;
> > > -	int physical_size_x;
> > > -	int physical_size_y;
> > > -};
> > > -
> > > -static const u8 bl_deactivate[] = { 0x00, 0xff, 0x3b, 0x00, 0x01, 0x02,
> > 0x03,
> > > -		0x04, 0x05, 0x06, 0x07 };
> > > -static const u8 bl_exit[] = { 0x00, 0xff, 0xa5, 0x00, 0x01, 0x02, 0x03,
> > 0x04,
> > > -		0x05, 0x06, 0x07 };
> > > -
> > > -struct cyapa_cmd_len {
> > > -	u8 cmd;
> > > -	u8 len;
> > > -};
> > >
> > >  #define CYAPA_ADAPTER_FUNC_NONE   0
> > >  #define CYAPA_ADAPTER_FUNC_I2C    1
> > >  #define CYAPA_ADAPTER_FUNC_SMBUS  2
> > >  #define CYAPA_ADAPTER_FUNC_BOTH   3
> > >
> > > -/*
> > > - * macros for SMBus communication
> > > - */
> > > -#define SMBUS_READ   0x01
> > > -#define SMBUS_WRITE 0x00
> > > -#define SMBUS_ENCODE_IDX(cmd, idx) ((cmd) | (((idx) & 0x03) << 1))
> > > -#define SMBUS_ENCODE_RW(cmd, rw) ((cmd) | ((rw) & 0x01))
> > > -#define SMBUS_BYTE_BLOCK_CMD_MASK 0x80
> > > -#define SMBUS_GROUP_BLOCK_CMD_MASK 0x40
> > > -
> > > - /* for byte read/write command */
> > > -#define CMD_RESET 0
> > > -#define CMD_POWER_MODE 1
> > > -#define CMD_DEV_STATUS 2
> > > -#define SMBUS_BYTE_CMD(cmd) (((cmd) & 0x3f) << 1)
> > > -#define CYAPA_SMBUS_RESET SMBUS_BYTE_CMD(CMD_RESET)
> > > -#define CYAPA_SMBUS_POWER_MODE SMBUS_BYTE_CMD(CMD_POWER_MODE)
> > > -#define CYAPA_SMBUS_DEV_STATUS SMBUS_BYTE_CMD(CMD_DEV_STATUS)
> > > -
> > > - /* for group registers read/write command */
> > > -#define REG_GROUP_DATA 0
> > > -#define REG_GROUP_CMD 2
> > > -#define REG_GROUP_QUERY 3
> > > -#define SMBUS_GROUP_CMD(grp) (0x80 | (((grp) & 0x07) << 3))
> > > -#define CYAPA_SMBUS_GROUP_DATA SMBUS_GROUP_CMD(REG_GROUP_DATA)
> > > -#define CYAPA_SMBUS_GROUP_CMD SMBUS_GROUP_CMD(REG_GROUP_CMD)
> > > -#define CYAPA_SMBUS_GROUP_QUERY SMBUS_GROUP_CMD(REG_GROUP_QUERY)
> > > -
> > > - /* for register block read/write command */
> > > -#define CMD_BL_STATUS 0
> > > -#define CMD_BL_HEAD 1
> > > -#define CMD_BL_CMD 2
> > > -#define CMD_BL_DATA 3
> > > -#define CMD_BL_ALL 4
> > > -#define CMD_BLK_PRODUCT_ID 5
> > > -#define CMD_BLK_HEAD 6
> > > -#define SMBUS_BLOCK_CMD(cmd) (0xc0 | (((cmd) & 0x1f) << 1))
> > > -
> > > -/* register block read/write command in bootloader mode */
> > > -#define CYAPA_SMBUS_BL_STATUS SMBUS_BLOCK_CMD(CMD_BL_STATUS)
> > > -#define CYAPA_SMBUS_BL_HEAD SMBUS_BLOCK_CMD(CMD_BL_HEAD)
> > > -#define CYAPA_SMBUS_BL_CMD SMBUS_BLOCK_CMD(CMD_BL_CMD)
> > > -#define CYAPA_SMBUS_BL_DATA SMBUS_BLOCK_CMD(CMD_BL_DATA)
> > > -#define CYAPA_SMBUS_BL_ALL SMBUS_BLOCK_CMD(CMD_BL_ALL)
> > > -
> > > -/* register block read/write command in operational mode */
> > > -#define CYAPA_SMBUS_BLK_PRODUCT_ID SMBUS_BLOCK_CMD(CMD_BLK_PRODUCT_ID)
> > > -#define CYAPA_SMBUS_BLK_HEAD SMBUS_BLOCK_CMD(CMD_BLK_HEAD)
> > > -
> > > -static const struct cyapa_cmd_len cyapa_i2c_cmds[] = {
> > > -	{ CYAPA_OFFSET_SOFT_RESET, 1 },
> > > -	{ REG_OFFSET_COMMAND_BASE + 1, 1 },
> > > -	{ REG_OFFSET_DATA_BASE, 1 },
> > > -	{ REG_OFFSET_DATA_BASE, sizeof(struct cyapa_reg_data) },
> > > -	{ REG_OFFSET_COMMAND_BASE, 0 },
> > > -	{ REG_OFFSET_QUERY_BASE, QUERY_DATA_SIZE },
> > > -	{ BL_HEAD_OFFSET, 3 },
> > > -	{ BL_HEAD_OFFSET, 16 },
> > > -	{ BL_HEAD_OFFSET, 16 },
> > > -	{ BL_DATA_OFFSET, 16 },
> > > -	{ BL_HEAD_OFFSET, 32 },
> > > -	{ REG_OFFSET_QUERY_BASE, PRODUCT_ID_SIZE },
> > > -	{ REG_OFFSET_DATA_BASE, 32 }
> > > -};
> > > +#define CYAPA_DEBUGFS_READ_FW	"read_fw"
> > > +#define CYAPA_DEBUGFS_RAW_DATA	"raw_data"
> > > +#define CYAPA_FW_NAME		"cyapa.bin"
> > > +
> > > +const char unique_str[] = "CYTRA";
> > > +
> > >
> > > -static const struct cyapa_cmd_len cyapa_smbus_cmds[] = {
> > > -	{ CYAPA_SMBUS_RESET, 1 },
> > > -	{ CYAPA_SMBUS_POWER_MODE, 1 },
> > > -	{ CYAPA_SMBUS_DEV_STATUS, 1 },
> > > -	{ CYAPA_SMBUS_GROUP_DATA, sizeof(struct cyapa_reg_data) },
> > > -	{ CYAPA_SMBUS_GROUP_CMD, 2 },
> > > -	{ CYAPA_SMBUS_GROUP_QUERY, QUERY_DATA_SIZE },
> > > -	{ CYAPA_SMBUS_BL_STATUS, 3 },
> > > -	{ CYAPA_SMBUS_BL_HEAD, 16 },
> > > -	{ CYAPA_SMBUS_BL_CMD, 16 },
> > > -	{ CYAPA_SMBUS_BL_DATA, 16 },
> > > -	{ CYAPA_SMBUS_BL_ALL, 32 },
> > > -	{ CYAPA_SMBUS_BLK_PRODUCT_ID, PRODUCT_ID_SIZE },
> > > -	{ CYAPA_SMBUS_BLK_HEAD, 16 },
> > > -};
> > >
> > > -static ssize_t cyapa_i2c_reg_read_block(struct cyapa *cyapa, u8 reg, size_t
> > len,
> > > +ssize_t cyapa_i2c_reg_read_block(struct cyapa *cyapa, u8 reg, size_t len,
> > >  					u8 *values)
> > >  {
> > >  	return i2c_smbus_read_i2c_block_data(cyapa->client, reg, len, values);
> > >  }
> > >
> > > -static ssize_t cyapa_i2c_reg_write_block(struct cyapa *cyapa, u8 reg,
> > > +ssize_t cyapa_i2c_reg_write_block(struct cyapa *cyapa, u8 reg,
> > >  					 size_t len, const u8 *values)
> > >  {
> > >  	return i2c_smbus_write_i2c_block_data(cyapa->client, reg, len, values);
> > >  }
> > >
> > > -/*
> > > - * cyapa_smbus_read_block - perform smbus block read command
> > > - * @cyapa  - private data structure of the driver
> > > - * @cmd    - the properly encoded smbus command
> > > - * @len    - expected length of smbus command result
> > > - * @values - buffer to store smbus command result
> > > - *
> > > - * Returns negative errno, else the number of bytes written.
> > > - *
> > > - * Note:
> > > - * In trackpad device, the memory block allocated for I2C register map
> > > - * is 256 bytes, so the max read block for I2C bus is 256 bytes.
> > > - */
> > > -static ssize_t cyapa_smbus_read_block(struct cyapa *cyapa, u8 cmd, size_t
> > len,
> > > -				      u8 *values)
> > > -{
> > > -	ssize_t ret;
> > > -	u8 index;
> > > -	u8 smbus_cmd;
> > > -	u8 *buf;
> > > -	struct i2c_client *client = cyapa->client;
> > > -
> > > -	if (!(SMBUS_BYTE_BLOCK_CMD_MASK & cmd))
> > > -		return -EINVAL;
> > > -
> > > -	if (SMBUS_GROUP_BLOCK_CMD_MASK & cmd) {
> > > -		/* read specific block registers command. */
> > > -		smbus_cmd = SMBUS_ENCODE_RW(cmd, SMBUS_READ);
> > > -		ret = i2c_smbus_read_block_data(client, smbus_cmd, values);
> > > -		goto out;
> > > -	}
> > > -
> > > -	ret = 0;
> > > -	for (index = 0; index * I2C_SMBUS_BLOCK_MAX < len; index++) {
> > > -		smbus_cmd = SMBUS_ENCODE_IDX(cmd, index);
> > > -		smbus_cmd = SMBUS_ENCODE_RW(smbus_cmd, SMBUS_READ);
> > > -		buf = values + I2C_SMBUS_BLOCK_MAX * index;
> > > -		ret = i2c_smbus_read_block_data(client, smbus_cmd, buf);
> > > -		if (ret < 0)
> > > -			goto out;
> > > -	}
> > > -
> > > -out:
> > > -	return ret > 0 ? len : ret;
> > > -}
> > > -
> > > -static s32 cyapa_read_byte(struct cyapa *cyapa, u8 cmd_idx)
> > > -{
> > > -	u8 cmd;
> > > -
> > > -	if (cyapa->smbus) {
> > > -		cmd = cyapa_smbus_cmds[cmd_idx].cmd;
> > > -		cmd = SMBUS_ENCODE_RW(cmd, SMBUS_READ);
> > > -	} else {
> > > -		cmd = cyapa_i2c_cmds[cmd_idx].cmd;
> > > -	}
> > > -	return i2c_smbus_read_byte_data(cyapa->client, cmd);
> > > -}
> > > -
> > > -static s32 cyapa_write_byte(struct cyapa *cyapa, u8 cmd_idx, u8 value)
> > > -{
> > > -	u8 cmd;
> > > -
> > > -	if (cyapa->smbus) {
> > > -		cmd = cyapa_smbus_cmds[cmd_idx].cmd;
> > > -		cmd = SMBUS_ENCODE_RW(cmd, SMBUS_WRITE);
> > > -	} else {
> > > -		cmd = cyapa_i2c_cmds[cmd_idx].cmd;
> > > -	}
> > > -	return i2c_smbus_write_byte_data(cyapa->client, cmd, value);
> > > -}
> > > -
> > > -static ssize_t cyapa_read_block(struct cyapa *cyapa, u8 cmd_idx, u8 *values)
> > > -{
> > > -	u8 cmd;
> > > -	size_t len;
> > > -
> > > -	if (cyapa->smbus) {
> > > -		cmd = cyapa_smbus_cmds[cmd_idx].cmd;
> > > -		len = cyapa_smbus_cmds[cmd_idx].len;
> > > -		return cyapa_smbus_read_block(cyapa, cmd, len, values);
> > > -	} else {
> > > -		cmd = cyapa_i2c_cmds[cmd_idx].cmd;
> > > -		len = cyapa_i2c_cmds[cmd_idx].len;
> > > -		return cyapa_i2c_reg_read_block(cyapa, cmd, len, values);
> > > -	}
> > > -}
> > > -
> > > -/*
> > > - * Query device for its current operating state.
> > > - *
> > > - */
> > > -static int cyapa_get_state(struct cyapa *cyapa)
> > > +/* Returns 0 on success, else negative errno on failure. */
> > > +ssize_t cyapa_i2c_read(struct cyapa *cyapa, u8 reg, size_t len,
> > > +					u8 *values)
> > >  {
> > >  	int ret;
> > > -	u8 status[BL_STATUS_SIZE];
> > > -
> > > -	cyapa->state = CYAPA_STATE_NO_DEVICE;
> > > -
> > > -	/*
> > > -	 * Get trackpad status by reading 3 registers starting from 0.
> > > -	 * If the device is in the bootloader, this will be BL_HEAD.
> > > -	 * If the device is in operation mode, this will be the DATA regs.
> > > -	 *
> > > -	 */
> > > -	ret = cyapa_i2c_reg_read_block(cyapa, BL_HEAD_OFFSET, BL_STATUS_SIZE,
> > > -				       status);
> > > -
> > > -	/*
> > > -	 * On smbus systems in OP mode, the i2c_reg_read will fail with
> > > -	 * -ETIMEDOUT.  In this case, try again using the smbus equivalent
> > > -	 * command.  This should return a BL_HEAD indicating CYAPA_STATE_OP.
> > > -	 */
> > > -	if (cyapa->smbus && (ret == -ETIMEDOUT || ret == -ENXIO))
> > > -		ret = cyapa_read_block(cyapa, CYAPA_CMD_BL_STATUS, status);
> > > -
> > > -	if (ret != BL_STATUS_SIZE)
> > > -		goto error;
> > > -
> > > -	if ((status[REG_OP_STATUS] & OP_STATUS_SRC) == OP_STATUS_SRC) {
> > > -		switch (status[REG_OP_STATUS] & OP_STATUS_DEV) {
> > > -		case CYAPA_DEV_NORMAL:
> > > -		case CYAPA_DEV_BUSY:
> > > -			cyapa->state = CYAPA_STATE_OP;
> > > -			break;
> > > -		default:
> > > -			ret = -EAGAIN;
> > > -			goto error;
> > > -		}
> > > -	} else {
> > > -		if (status[REG_BL_STATUS] & BL_STATUS_BUSY)
> > > -			cyapa->state = CYAPA_STATE_BL_BUSY;
> > > -		else if (status[REG_BL_ERROR] & BL_ERROR_BOOTLOADING)
> > > -			cyapa->state = CYAPA_STATE_BL_ACTIVE;
> > > -		else
> > > -			cyapa->state = CYAPA_STATE_BL_IDLE;
> > > -	}
> > > -
> > > -	return 0;
> > > -error:
> > > -	return (ret < 0) ? ret : -EAGAIN;
> > > +	struct i2c_client *client = cyapa->client;
> > > +	struct i2c_msg msgs[] = {
> > > +		{
> > > +			.addr = client->addr,
> > > +			.flags = 0,
> > > +			.len = 1,
> > > +			.buf = &reg,
> > > +		},
> > > +		{
> > > +			.addr = client->addr,
> > > +			.flags = I2C_M_RD,
> > > +			.len = len,
> > > +			.buf = values,
> > > +		},
> > > +	};
> > > +
> > > +	ret = i2c_transfer(client->adapter, msgs, 2);
> > 
> > You need to watch out for partial transfers. It should be:
> > 
> > 	if (ret != ARRAY_SIZE(msgs))
> > 		return ret < 0 ? ret : -EIO;
> > 
> > 	return 0;
> > 
> 
> Thanks, I will update in next release.
> 
> > > +
> > > +	return ret < 0 ? ret : 0;
> > >  }
> > >
> > > -/*
> > > - * Poll device for its status in a loop, waiting up to timeout for a
> > response.
> > > - *
> > > - * When the device switches state, it usually takes ~300 ms.
> > > - * However, when running a new firmware image, the device must calibrate
> > its
> > > - * sensors, which can take as long as 2 seconds.
> > > +/**
> > > + * cyapa_i2c_write - Execute i2c block data write operation
> > > + * @cyapa: Handle to this driver
> > > + * @ret: Offset of the data to written in the register map
> > > + * @len: number of bytes to write
> > > + * @values: Data to be written
> > >   *
> > > - * Note: The timeout has granularity of the polling rate, which is 100 ms.
> > > - *
> > > - * Returns:
> > > - *   0 when the device eventually responds with a valid non-busy state.
> > > - *   -ETIMEDOUT if device never responds (too many -EAGAIN)
> > > - *   < 0    other errors
> > > + * Return negative errno code on error; return zero when success.
> > >   */
> > > -static int cyapa_poll_state(struct cyapa *cyapa, unsigned int timeout)
> > > +ssize_t cyapa_i2c_write(struct cyapa *cyapa, u8 reg,
> > > +					 size_t len, const void *values)
> > >  {
> > >  	int ret;
> > > -	int tries = timeout / 100;
> > > -
> > > -	ret = cyapa_get_state(cyapa);
> > > -	while ((ret || cyapa->state >= CYAPA_STATE_BL_BUSY) && tries--) {
> > > -		msleep(100);
> > > -		ret = cyapa_get_state(cyapa);
> > > -	}
> > > -	return (ret == -EAGAIN || ret == -ETIMEDOUT) ? -ETIMEDOUT : ret;
> > > -}
> > > +	struct i2c_client *client = cyapa->client;
> > > +	char data[32], *buf;
> > >
> > > -static int cyapa_bl_deactivate(struct cyapa *cyapa)
> > > -{
> > > -	int ret;
> > > +	if (len > 31)
> > > +		buf = kzalloc(len + 1, GFP_KERNEL);
> > > +	else
> > > +		buf = data;
> > >
> > > -	ret = cyapa_i2c_reg_write_block(cyapa, 0, sizeof(bl_deactivate),
> > > -					bl_deactivate);
> > > -	if (ret < 0)
> > > -		return ret;
> > > +	buf[0] = reg;
> > > +	memcpy(&buf[1], values, len);
> > > +	ret = i2c_master_send(client, buf, len + 1);
> > >
> > > -	/* wait for bootloader to switch to idle state; should take < 100ms */
> > > -	msleep(100);
> > > -	ret = cyapa_poll_state(cyapa, 500);
> > > -	if (ret < 0)
> > > -		return ret;
> > > -	if (cyapa->state != CYAPA_STATE_BL_IDLE)
> > > -		return -EAGAIN;
> > > -	return 0;
> > > +	if (buf != data)
> > > +		kfree(buf);
> > > +	return (ret == (len + 1)) ? 0 : ((ret < 0) ? ret : -EIO);
> > >  }
> > >
> > > -/*
> > > - * Exit bootloader
> > > - *
> > > - * Send bl_exit command, then wait 50 - 100 ms to let device transition to
> > > - * operational mode.  If this is the first time the device's firmware is
> > > - * running, it can take up to 2 seconds to calibrate its sensors.  So, poll
> > > - * the device's new state for up to 2 seconds.
> > > - *
> > > - * Returns:
> > > - *   -EIO    failure while reading from device
> > > - *   -EAGAIN device is stuck in bootloader, b/c it has invalid firmware
> > > - *   0       device is supported and in operational mode
> > > - */
> > > -static int cyapa_bl_exit(struct cyapa *cyapa)
> > > +void cyapa_default_irq_handler(struct cyapa *cyapa)
> > >  {
> > > -	int ret;
> > > -
> > > -	ret = cyapa_i2c_reg_write_block(cyapa, 0, sizeof(bl_exit), bl_exit);
> > > -	if (ret < 0)
> > > -		return ret;
> > > -
> > > -	/*
> > > -	 * Wait for bootloader to exit, and operation mode to start.
> > > -	 * Normally, this takes at least 50 ms.
> > > -	 */
> > > -	usleep_range(50000, 100000);
> > >  	/*
> > > -	 * In addition, when a device boots for the first time after being
> > > -	 * updated to new firmware, it must first calibrate its sensors, which
> > > -	 * can take up to an additional 2 seconds.
> > > +	 * Do redetecting when device states is still unknown and
> > > +	 * interrupt envent is received from device.
> > >  	 */
> > > -	ret = cyapa_poll_state(cyapa, 2000);
> > > -	if (ret < 0)
> > > -		return ret;
> > > -	if (cyapa->state != CYAPA_STATE_OP)
> > > -		return -EAGAIN;
> > > -
> > > -	return 0;
> > > -}
> > > -
> > > -/*
> > > - * Set device power mode
> > > - *
> > > - */
> > > -static int cyapa_set_power_mode(struct cyapa *cyapa, u8 power_mode)
> > > -{
> > > -	struct device *dev = &cyapa->client->dev;
> > > -	int ret;
> > > -	u8 power;
> > > -
> > > -	if (cyapa->state != CYAPA_STATE_OP)
> > > -		return 0;
> > > -
> > > -	ret = cyapa_read_byte(cyapa, CYAPA_CMD_POWER_MODE);
> > > -	if (ret < 0)
> > > -		return ret;
> > > -
> > > -	power = ret & ~PWR_MODE_MASK;
> > > -	power |= power_mode & PWR_MODE_MASK;
> > > -	ret = cyapa_write_byte(cyapa, CYAPA_CMD_POWER_MODE, power);
> > > -	if (ret < 0)
> > > -		dev_err(dev, "failed to set power_mode 0x%02x err = %d\n",
> > > -			power_mode, ret);
> > > -	return ret;
> > > -}
> > > -
> > > -static int cyapa_get_query_data(struct cyapa *cyapa)
> > > -{
> > > -	u8 query_data[QUERY_DATA_SIZE];
> > > -	int ret;
> > > -
> > > -	if (cyapa->state != CYAPA_STATE_OP)
> > > -		return -EBUSY;
> > > -
> > > -	ret = cyapa_read_block(cyapa, CYAPA_CMD_GROUP_QUERY, query_data);
> > > -	if (ret < 0)
> > > -		return ret;
> > > -	if (ret != QUERY_DATA_SIZE)
> > > -		return -EIO;
> > > -
> > > -	memcpy(&cyapa->product_id[0], &query_data[0], 5);
> > > -	cyapa->product_id[5] = '-';
> > > -	memcpy(&cyapa->product_id[6], &query_data[5], 6);
> > > -	cyapa->product_id[12] = '-';
> > > -	memcpy(&cyapa->product_id[13], &query_data[11], 2);
> > > -	cyapa->product_id[15] = '\0';
> > > -
> > > -	cyapa->btn_capability = query_data[19] & CAPABILITY_BTN_MASK;
> > > -
> > > -	cyapa->gen = query_data[20] & 0x0f;
> > > -
> > > -	cyapa->max_abs_x = ((query_data[21] & 0xf0) << 4) | query_data[22];
> > > -	cyapa->max_abs_y = ((query_data[21] & 0x0f) << 8) | query_data[23];
> > > -
> > > -	cyapa->physical_size_x =
> > > -		((query_data[24] & 0xf0) << 4) | query_data[25];
> > > -	cyapa->physical_size_y =
> > > -		((query_data[24] & 0x0f) << 8) | query_data[26];
> > > -
> > > -	return 0;
> > > +	async_schedule(cyapa_detect_async, cyapa);
> > 
> > I think I already asked this before - why do we need to try and schedule async
> > detect from interrupt handler. In what cases we will fail to initialize the
> > device during normal probing, but then are fine when stray interrupt arrives?
> > 
> 
> 1) Because gen5 TP devices use interrupt to sync the command and response, and
> in detecting, some commands must be sent and executed in attached devices, so
> the interrupt must be usable in detecting.
> So if do not schedule async detect from interrupt handler, the interrupt
> handler will be taken, and cannot enter again, which will cause the command to
> the device failed, it will also cause long time detecting.
> 2) detecting will fail when no device attached or the attached device is not
> supported gen3 or gen5 TP devices or there is some issue with the device
> that cannot enter into active working mode or stay in bootloader mode
> for invalid firmware detected.
> And it's tested that it's save when stray interrupt arrives in detecting.


I am sorry, I have trouble parsing this. I understand that you may need
interrupt to know when command response is ready, but I do not see how
kicking asynchronous detect helps there. During probe you can figure out
if you are talking to a Cypress device and whether it is operable. If it
is not operable you can try flashing a new firmware and then kick off
detection again after flash is successful. But I do not see any reason
in trying to re-detect the device after random interrupt arrives in hopes
that maybe this time stars will align and we'll be able to work with it.

> 
> Thanks.
>  
> 
> > >  }
> > >
> > > -/*
> > > - * Check if device is operational.
> > > - *
> > > - * An operational device is responding, has exited bootloader, and has
> > > - * firmware supported by this driver.
> > > - *
> > > - * Returns:
> > > - *   -EBUSY  no device or in bootloader
> > > - *   -EIO    failure while reading from device
> > > - *   -EAGAIN device is still in bootloader
> > > - *           if ->state = CYAPA_STATE_BL_IDLE, device has invalid firmware
> > > - *   -EINVAL device is in operational mode, but not supported by this
> > driver
> > > - *   0       device is supported
> > > - */
> > > -static int cyapa_check_is_operational(struct cyapa *cyapa)
> > > -{
> > > -	struct device *dev = &cyapa->client->dev;
> > > -	static const char unique_str[] = "CYTRA";
> > > -	int ret;
> > > -
> > > -	ret = cyapa_poll_state(cyapa, 2000);
> > > -	if (ret < 0)
> > > -		return ret;
> > > -	switch (cyapa->state) {
> > > -	case CYAPA_STATE_BL_ACTIVE:
> > > -		ret = cyapa_bl_deactivate(cyapa);
> > > -		if (ret)
> > > -			return ret;
> > > -
> > > -	/* Fallthrough state */
> > > -	case CYAPA_STATE_BL_IDLE:
> > > -		ret = cyapa_bl_exit(cyapa);
> > > -		if (ret)
> > > -			return ret;
> > > -
> > > -	/* Fallthrough state */
> > > -	case CYAPA_STATE_OP:
> > > -		ret = cyapa_get_query_data(cyapa);
> > > -		if (ret < 0)
> > > -			return ret;
> > > -
> > > -		/* only support firmware protocol gen3 */
> > > -		if (cyapa->gen != CYAPA_GEN3) {
> > > -			dev_err(dev, "unsupported protocol version (%d)",
> > > -				cyapa->gen);
> > > -			return -EINVAL;
> > > -		}
> > > -
> > > -		/* only support product ID starting with CYTRA */
> > > -		if (memcmp(cyapa->product_id, unique_str,
> > > -			   sizeof(unique_str) - 1) != 0) {
> > > -			dev_err(dev, "unsupported product ID (%s)\n",
> > > -				cyapa->product_id);
> > > -			return -EINVAL;
> > > -		}
> > > -		return 0;
> > > -
> > > -	default:
> > > -		return -EIO;
> > > -	}
> > > -	return 0;
> > > -}
> > > -
> > > -static irqreturn_t cyapa_irq(int irq, void *dev_id)
> > > -{
> > > -	struct cyapa *cyapa = dev_id;
> > > -	struct device *dev = &cyapa->client->dev;
> > > -	struct input_dev *input = cyapa->input;
> > > -	struct cyapa_reg_data data;
> > > -	int i;
> > > -	int ret;
> > > -	int num_fingers;
> > > -
> > > -	if (device_may_wakeup(dev))
> > > -		pm_wakeup_event(dev, 0);
> > > -
> > > -	ret = cyapa_read_block(cyapa, CYAPA_CMD_GROUP_DATA, (u8 *)&data);
> > > -	if (ret != sizeof(data))
> > > -		goto out;
> > > -
> > > -	if ((data.device_status & OP_STATUS_SRC) != OP_STATUS_SRC ||
> > > -	    (data.device_status & OP_STATUS_DEV) != CYAPA_DEV_NORMAL ||
> > > -	    (data.finger_btn & OP_DATA_VALID) != OP_DATA_VALID) {
> > > -		goto out;
> > > -	}
> > > -
> > > -	num_fingers = (data.finger_btn >> 4) & 0x0f;
> > > -	for (i = 0; i < num_fingers; i++) {
> > > -		const struct cyapa_touch *touch = &data.touches[i];
> > > -		/* Note: touch->id range is 1 to 15; slots are 0 to 14. */
> > > -		int slot = touch->id - 1;
> > > -
> > > -		input_mt_slot(input, slot);
> > > -		input_mt_report_slot_state(input, MT_TOOL_FINGER, true);
> > > -		input_report_abs(input, ABS_MT_POSITION_X,
> > > -				 ((touch->xy_hi & 0xf0) << 4) | touch->x_lo);
> > > -		input_report_abs(input, ABS_MT_POSITION_Y,
> > > -				 ((touch->xy_hi & 0x0f) << 8) | touch->y_lo);
> > > -		input_report_abs(input, ABS_MT_PRESSURE, touch->pressure);
> > > -	}
> > > -
> > > -	input_mt_sync_frame(input);
> > > -
> > > -	if (cyapa->btn_capability & CAPABILITY_LEFT_BTN_MASK)
> > > -		input_report_key(input, BTN_LEFT,
> > > -				 data.finger_btn & OP_DATA_LEFT_BTN);
> > > -
> > > -	if (cyapa->btn_capability & CAPABILITY_MIDDLE_BTN_MASK)
> > > -		input_report_key(input, BTN_MIDDLE,
> > > -				 data.finger_btn & OP_DATA_MIDDLE_BTN);
> > > -
> > > -	if (cyapa->btn_capability & CAPABILITY_RIGHT_BTN_MASK)
> > > -		input_report_key(input, BTN_RIGHT,
> > > -				 data.finger_btn & OP_DATA_RIGHT_BTN);
> > > -
> > > -	input_sync(input);
> > > +const struct cyapa_dev_ops cyapa_default_ops = {
> > > +	.irq_handler = cyapa_default_irq_handler
> > > +};
> > >
> > > -out:
> > > -	return IRQ_HANDLED;
> > > -}
> > >
> > >  static u8 cyapa_check_adapter_functionality(struct i2c_client *client)
> > >  {
> > > @@ -772,19 +155,40 @@ static int cyapa_create_input_dev(struct cyapa *cyapa)
> > >  	input->phys = cyapa->phys;
> > >  	input->id.bustype = BUS_I2C;
> > >  	input->id.version = 1;
> > > -	input->id.product = 0;  /* means any product in eventcomm. */
> > > +	input->id.product = 0;  /* Means any product in eventcomm. */
> > >  	input->dev.parent = &cyapa->client->dev;
> > >
> > >  	input_set_drvdata(input, cyapa);
> > >
> > >  	__set_bit(EV_ABS, input->evbit);
> > >
> > > -	/* finger position */
> > > +	/* Finger position */
> > >  	input_set_abs_params(input, ABS_MT_POSITION_X, 0, cyapa->max_abs_x, 0,
> > >  			     0);
> > >  	input_set_abs_params(input, ABS_MT_POSITION_Y, 0, cyapa->max_abs_y, 0,
> > >  			     0);
> > > -	input_set_abs_params(input, ABS_MT_PRESSURE, 0, 255, 0, 0);
> > > +	input_set_abs_params(input, ABS_MT_PRESSURE, 0, cyapa->max_z, 0, 0);
> > > +	if (cyapa->gen > CYAPA_GEN3) {
> > > +		input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
> > > +		input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 0, 255, 0, 0);
> > > +		/*
> > > +		 * Orientation is the angle between the vertical axis and
> > > +		 * the major axis of the contact ellipse.
> > > +		 * The range is -127 to 127.
> > > +		 * the positive direction is clockwise form the vertical axis.
> > > +		 * If the ellipse of contact degenerates into a circle,
> > > +		 * orientation is reported as 0.
> > > +		 *
> > > +		 * Also, for Gen5 trackpad the accurate of this orientation
> > > +		 * value is value + (-30 ~ 30).
> > > +		 */
> > > +		input_set_abs_params(input, ABS_MT_ORIENTATION,
> > > +				-127, 127, 0, 0);
> > > +	}
> > > +	if (cyapa->gen >= CYAPA_GEN5) {
> > > +		input_set_abs_params(input, ABS_MT_WIDTH_MAJOR, 0, 255, 0, 0);
> > > +		input_set_abs_params(input, ABS_MT_WIDTH_MINOR, 0, 255, 0, 0);
> > > +	}
> > >
> > >  	input_abs_set_res(input, ABS_MT_POSITION_X,
> > >  			  cyapa->max_abs_x / cyapa->physical_size_x);
> > > @@ -801,7 +205,7 @@ static int cyapa_create_input_dev(struct cyapa *cyapa)
> > >  	if (cyapa->btn_capability == CAPABILITY_LEFT_BTN_MASK)
> > >  		__set_bit(INPUT_PROP_BUTTONPAD, input->propbit);
> > >
> > > -	/* handle pointer emulation and unused slots in core */
> > > +	/* Handle pointer emulation and unused slots in core */
> > >  	ret = input_mt_init_slots(input, CYAPA_MAX_MT_SLOTS,
> > >  				  INPUT_MT_POINTER | INPUT_MT_DROP_UNUSED);
> > >  	if (ret) {
> > > @@ -823,6 +227,224 @@ err_free_device:
> > >  	return ret;
> > >  }
> > >
> > > +/*
> > > + * Check if device is operational.
> > > + *
> > > + * An operational device is responding, has exited bootloader, and has
> > > + * firmware supported by this driver.
> > > + *
> > > + * Returns:
> > > + *   -EBUSY  no device or in bootloader
> > > + *   -EIO    failure while reading from device
> > > + *   -EAGAIN device is still in bootloader
> > > + *           if ->state = CYAPA_STATE_BL_IDLE, device has invalid firmware
> > > + *   -EINVAL device is in operational mode, but not supported by this
> > driver
> > > + *   0       device is supported
> > > + */
> > > +static int cyapa_check_is_operational(struct cyapa *cyapa)
> > > +{
> > > +	int ret;
> > > +
> > > +	ret = cyapa_poll_state(cyapa, 4000);
> > > +	if (ret)
> > > +		return ret;
> > > +
> > > +	switch (cyapa->gen) {
> > > +	default:
> > > +		cyapa->ops = &cyapa_default_ops;
> > > +		cyapa->gen = CYAPA_GEN_UNKNOWN;
> > > +		break;
> > > +	}
> > > +
> > > +	if (cyapa->ops->operational_check)
> > > +		ret = cyapa->ops->operational_check(cyapa);
> > > +	else
> > > +		ret = -EBUSY;
> > > +
> > > +	return ret;
> > > +}
> > > +
> > > +
> > > +static irqreturn_t cyapa_irq(int irq, void *dev_id)
> > > +{
> > > +	struct cyapa *cyapa = dev_id;
> > > +	struct input_dev *input = cyapa->input;
> > > +	bool cont;
> > > +
> > > +	/* Interrupt event maybe cuased by host command to trackpad device. */
> > > +	cont = true;
> > > +	if (cyapa->ops->irq_cmd_handler)
> > > +		cont = cyapa->ops->irq_cmd_handler(cyapa);
> > > +
> > > +	/* Interrupt event maybe from trackpad device input reporting. */
> > > +	if (cont && cyapa->ops->irq_handler) {
> > > +		if (!mutex_trylock(&cyapa->state_sync_lock)) {
> > > +			if (cyapa->ops->sort_empty_output_data)
> > > +				cyapa->ops->sort_empty_output_data(cyapa,
> > > +					NULL, NULL, NULL);
> > > +			goto out;
> > > +		}
> > > +
> > > +		if (!input) {
> > > +			if (cyapa->ops->sort_empty_output_data)
> > > +				cyapa->ops->sort_empty_output_data(cyapa,
> > > +					NULL, NULL, NULL);
> > > +		} else
> > > +			cyapa->ops->irq_handler(cyapa);
> > > +
> > > +		mutex_unlock(&cyapa->state_sync_lock);
> > > +	}
> > > +out:
> > > +	return IRQ_HANDLED;
> > > +}
> > > +
> > > +/*
> > > + * Query device for its current operating state.
> > > + */
> > > +static int cyapa_get_state(struct cyapa *cyapa)
> > > +{
> > > +	cyapa->state = CYAPA_STATE_NO_DEVICE;
> > > +
> > > +	return -ENODEV;
> > > +}
> > > +
> > > +/*
> > > + * Poll device for its status in a loop, waiting up to timeout for a
> > response.
> > > + *
> > > + * When the device switches state, it usually takes ~300 ms.
> > > + * However, when running a new firmware image, the device must calibrate
> > its
> > > + * sensors, which can take as long as 2 seconds.
> > > + *
> > > + * Note: The timeout has granularity of the polling rate, which is 100 ms.
> > > + *
> > > + * Returns:
> > > + *   0 when the device eventually responds with a valid non-busy state.
> > > + *   -ETIMEDOUT if device never responds (too many -EAGAIN)
> > > + *   < 0    other errors
> > > + */
> > > +int cyapa_poll_state(struct cyapa *cyapa, unsigned int timeout)
> > > +{
> > > +	int ret;
> > > +	int tries = timeout / 100;
> > > +
> > > +	ret = cyapa_get_state(cyapa);
> > > +	while ((ret || cyapa->state >= CYAPA_STATE_BL_BUSY) && tries--) {
> > > +		msleep(100);
> > > +		ret = cyapa_get_state(cyapa);
> > > +	}
> > > +
> > > +	return (ret == -EAGAIN || ret == -ETIMEDOUT) ? -ETIMEDOUT : ret;
> > > +}
> > > +
> > > +static void cyapa_detect(struct cyapa *cyapa)
> > > +{
> > > +	struct device *dev = &cyapa->client->dev;
> > > +	char *envp[2] = {"ERROR=1", NULL};
> > > +	int ret;
> > > +
> > > +	ret = cyapa_check_is_operational(cyapa);
> > > +	if (ret == -ETIMEDOUT)
> > > +		dev_err(dev, "no device detected, %d\n", ret);
> > > +	else if (ret)
> > > +		dev_err(dev, "device detected, but not operational, %d\n", ret);
> > > +
> > > +	if (ret) {
> > > +		kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
> > > +		return;
> > > +	}
> > > +
> > > +	if (!cyapa->input) {
> > > +		ret = cyapa_create_input_dev(cyapa);
> > > +		if (ret)
> > > +			dev_err(dev, "create input_dev instance failed, %d\n",
> > > +				ret);
> > > +
> > > +		/*
> > > +		 * On some systems, a system crash / warm boot does not reset
> > > +		 * the device's current power mode to FULL_ACTIVE.
> > > +		 * If such an event happens during suspend, after the device
> > > +		 * has been put in a low power mode, the device will still be
> > > +		 * in low power mode on a subsequent boot, since there was
> > > +		 * never a matching resume().
> > > +		 * Handle this by always forcing full power here, when a
> > > +		 * device is first detected to be in operational mode.
> > > +		 */
> > > +		if (cyapa->ops->set_power_mode) {
> > > +			ret = cyapa->ops->set_power_mode(cyapa,
> > > +					PWR_MODE_FULL_ACTIVE, 0);
> > > +			if (ret)
> > > +				dev_warn(dev, "set active power failed, %d\n",
> > > +						ret);
> > > +		}
> > > +	}
> > > +}
> > > +
> > > +/*
> > > + * Sysfs Interface.
> > > + */
> > > +
> > > +/*
> > > + * cyapa_sleep_time_to_pwr_cmd and cyapa_pwr_cmd_to_sleep_time
> > > + *
> > > + * These are helper functions that convert to and from integer idle
> > > + * times and register settings to write to the PowerMode register.
> > > + * The trackpad supports between 20ms to 1000ms scan intervals.
> > > + * The time will be increased in increments of 10ms from 20ms to 100ms.
> > > + * From 100ms to 1000ms, time will be increased in increments of 20ms.
> > > + *
> > > + * When Idle_Time < 100, the format to convert Idle_Time to Idle_Command is:
> > > + *   Idle_Command = Idle Time / 10;
> > > + * When Idle_Time >= 100, the format to convert Idle_Time to Idle_Command
> > is:
> > > + *   Idle_Command = Idle Time / 20 + 5;
> > > + */
> > > +u8 cyapa_sleep_time_to_pwr_cmd(u16 sleep_time)
> > > +{
> > > +	if (sleep_time < 20)
> > > +		sleep_time = 20;     /* minimal sleep time. */
> > > +	else if (sleep_time > 1000)
> > > +		sleep_time = 1000;   /* maximal sleep time. */
> > 
> > 	clamp_val()
> 
> Thanks. clamp_pwr_cmd_sleep_time() will be used to above code.

No, we have a macro called clamp_val() which does exactly what you are
doing here by hand. So please use

	sleep_time = clamp_val(sleep_time, 20, 1000);


> 
> > 
> > > +
> > > +	if (sleep_time < 100)
> > > +		return ((sleep_time / 10) << 2) & PWR_MODE_MASK;
> > > +	else
> > > +		return ((sleep_time / 20 + 5) << 2) & PWR_MODE_MASK;
> > > +}
> > > +
> > > +u16 cyapa_pwr_cmd_to_sleep_time(u8 pwr_mode)
> > > +{
> > > +	u8 encoded_time = pwr_mode >> 2;
> > > +
> > > +	return (encoded_time < 10) ? encoded_time * 10
> > > +				   : (encoded_time - 5) * 20;
> > > +}
> > > +
> > > +void cyapa_detect_async(void *data, async_cookie_t cookie)
> > > +{
> > > +	struct cyapa *cyapa = (struct cyapa *)data;
> > > +
> > > +	mutex_lock(&cyapa->state_sync_lock);
> > > +
> > > +	/* Keep synchronized with sys interface process threads. */
> > > +	cyapa_detect(cyapa);
> > > +
> > > +	mutex_unlock(&cyapa->state_sync_lock);
> > > +}
> > > +
> > > +static void cyapa_detect_and_start(void *data, async_cookie_t cookie)
> > > +{
> > > +	cyapa_detect_async(data, cookie);
> > > +}
> > > +
> > > +static int cyapa_tp_modules_init(struct cyapa *cyapa)
> > > +{
> > > +	return 0;
> > > +}
> > > +
> > > +static int cyapa_tp_modules_uninit(struct cyapa *cyapa)
> > > +{
> > > +	return 0;
> > > +}
> > > +
> > >  static int cyapa_probe(struct i2c_client *client,
> > >  		       const struct i2c_device_id *dev_id)
> > >  {
> > > @@ -830,6 +452,7 @@ static int cyapa_probe(struct i2c_client *client,
> > >  	u8 adapter_func;
> > >  	struct cyapa *cyapa;
> > >  	struct device *dev = &client->dev;
> > > +	union i2c_smbus_data dummy;
> > >
> > >  	adapter_func = cyapa_check_adapter_functionality(client);
> > >  	if (adapter_func == CYAPA_ADAPTER_FUNC_NONE) {
> > > @@ -837,39 +460,43 @@ static int cyapa_probe(struct i2c_client *client,
> > >  		return -EIO;
> > >  	}
> > >
> > > +	/* Make sure there is something at this address */
> > > +	if (dev->of_node && i2c_smbus_xfer(client->adapter, client->addr, 0,
> > > +			I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE, &dummy) < 0)
> > > +		return -ENODEV;
> > > +
> > >  	cyapa = kzalloc(sizeof(struct cyapa), GFP_KERNEL);
> > >  	if (!cyapa) {
> > >  		dev_err(dev, "allocate memory for cyapa failed\n");
> > >  		return -ENOMEM;
> > >  	}
> > >
> > > -	cyapa->gen = CYAPA_GEN3;
> > >  	cyapa->client = client;
> > >  	i2c_set_clientdata(client, cyapa);
> > >  	sprintf(cyapa->phys, "i2c-%d-%04x/input0", client->adapter->nr,
> > >  		client->addr);
> > >
> > > -	/* i2c isn't supported, use smbus */
> > > -	if (adapter_func == CYAPA_ADAPTER_FUNC_SMBUS)
> > > -		cyapa->smbus = true;
> > > -	cyapa->state = CYAPA_STATE_NO_DEVICE;
> > > -	ret = cyapa_check_is_operational(cyapa);
> > > +	ret = cyapa_tp_modules_init(cyapa);
> > >  	if (ret) {
> > > -		dev_err(dev, "device not operational, %d\n", ret);
> > > -		goto err_mem_free;
> > > +		dev_err(dev, "initialize device modules failed.\n");
> > > +		goto err_unregister_device;
> > >  	}
> > >
> > > -	ret = cyapa_create_input_dev(cyapa);
> > > -	if (ret) {
> > > -		dev_err(dev, "create input_dev instance failed, %d\n", ret);
> > > -		goto err_mem_free;
> > > -	}
> > > +	cyapa->gen = CYAPA_GEN_UNKNOWN;
> > > +	cyapa->ops = &cyapa_default_ops;
> > > +	mutex_init(&cyapa->state_sync_lock);
> > >
> > > -	ret = cyapa_set_power_mode(cyapa, PWR_MODE_FULL_ACTIVE);
> > > -	if (ret) {
> > > -		dev_err(dev, "set active power failed, %d\n", ret);
> > > -		goto err_unregister_device;
> > > -	}
> > > +	/* i2c isn't supported, use smbus */
> > > +	if (adapter_func == CYAPA_ADAPTER_FUNC_SMBUS)
> > > +		cyapa->smbus = true;
> > > +	cyapa->state = CYAPA_STATE_NO_DEVICE;
> > > +	/*
> > > +	 * Set to hard code default, they will be updated with trackpad set
> > > +	 * default values after probe and initialized.
> > > +	 */
> > > +	cyapa->suspend_power_mode = PWR_MODE_SLEEP;
> > > +	cyapa->suspend_sleep_time =
> > > +		cyapa_pwr_cmd_to_sleep_time(cyapa->suspend_power_mode);
> > >
> > >  	cyapa->irq = client->irq;
> > >  	ret = request_threaded_irq(cyapa->irq,
> > > @@ -880,14 +507,17 @@ static int cyapa_probe(struct i2c_client *client,
> > >  				   cyapa);
> > >  	if (ret) {
> > >  		dev_err(dev, "IRQ request failed: %d\n, ", ret);
> > > -		goto err_unregister_device;
> > > +		goto err_uninit_tp_modules;
> > >  	}
> > >
> > > +	async_schedule(cyapa_detect_and_start, cyapa);
> > >  	return 0;
> > >
> > > +err_uninit_tp_modules:
> > > +	cyapa_tp_modules_uninit(cyapa);
> > >  err_unregister_device:
> > >  	input_unregister_device(cyapa->input);
> > > -err_mem_free:
> > > +	i2c_set_clientdata(client, NULL);
> > >  	kfree(cyapa);
> > >
> > >  	return ret;
> > > @@ -898,8 +528,12 @@ static int cyapa_remove(struct i2c_client *client)
> > >  	struct cyapa *cyapa = i2c_get_clientdata(client);
> > >
> > 
> > You schedule detect asynchronously so you need to make sure it is not running
> > (and will not be running) when you try to unbind the driver here.
> 
> Thanks. I will update it in next release.
> 
> To avoid this problem, a removed flag is introduced and is also synced by the
> cyapa->state_sync_lock mutex lock. So when this driver is removing, it's sure
> that the detecting asynchronous thread is not running, and if there's any event
> cause the asynchronous thread is entered, it will do nothing and will exit immediately.

Peeking at the other version of the patch you do:

cyapa_remove()
{
	...
	cyapa->removed = true;
	...
	kfree(cyapa);
}

and

void cyapa_detect_async(void *data, async_cookie_t cookie)
{
	...
	if (cyapa->removed) {
		mutex_unlock(&cyapa->state_sync_lock);
		return;
	}
	...
}

That's not going to work.

Getting asynchronous behavior by individual driver is hard and I believe
Luis Rordiguez is working on allowing to do that is the driver core. So
I would recommend to switch driver to do synchronous probing, at least
for now, and figure out other kinks first.

Thanks.

-- 
Dmitry

^ permalink raw reply

* Re: How to indicate hover touch when exact distance unknown?
From: Dmitry Torokhov @ 2014-09-24  0:27 UTC (permalink / raw)
  To: Henrik Rydberg
  Cc: Andrew de los Reyes, Benjamin Tissoires, hdegoede, jikos,
	David Herrmann, peter.hutterer, Linux Input
In-Reply-To: <5421C15C.6030302@euromail.se>

On Tue, Sep 23, 2014 at 08:52:12PM +0200, Henrik Rydberg wrote:
> >>> So I am not very happy with having a new
> >>> tool. In the end, it may also disturb older clients which will not know
> >>> what to do with HOVER.
> >>> And the ABS_MT_DISTANCE approach used to be fully retro-compatible
> >>> (assuming that the hovering distance is small enough for the user not to
> >>> detect it).
> >>
> >> Except that if we start getting devices that can actually tell the
> >> distance we'd need special casing 0/1 handling, no?
> 
> Logically, a hovering object which does not support real distance reporting
> would simply be present in the contact list but have ABS_MT_TOUCH = 0. However,
> I do not think all layers of the stack supports this notion.

That unfortunately does not give us indication whether device supports
hover or not: we'll know only when we see it.

-- 
Dmitry

^ permalink raw reply

* Re: [PATCH] Input: driver for the Goodix touchpanel
From: Dmitry Torokhov @ 2014-09-24  0:45 UTC (permalink / raw)
  To: Bastien Nocera; +Cc: Henrik Rydberg, linux-input, Benjamin Tissoires
In-Reply-To: <1411511293.29315.16.camel@hadess.net>

Hi Bastien,

On Wed, Sep 24, 2014 at 12:28:13AM +0200, Bastien Nocera wrote:
> Add a driver for the Goodix touchscreen panel found in Onda v975w
> tablets. The driver is based off the Android driver gt9xx.c found
> in some Android code dumps, but now bears no resemblance to the original
> driver.
> 
> The driver was tested on the aforementioned tablet.
> 
> Signed-off-by: Bastien Nocera <hadess@hadess.net>
> Tested-by: Bastien Nocera <hadess@hadess.net>
> ---
>  MAINTAINERS                        |   6 +
>  drivers/input/touchscreen/Kconfig  |  13 ++
>  drivers/input/touchscreen/Makefile |   1 +
>  drivers/input/touchscreen/goodix.c | 452 +++++++++++++++++++++++++++++++++++++
>  4 files changed, 472 insertions(+)
>  create mode 100644 drivers/input/touchscreen/goodix.c
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 670b3dc..7a37464 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -4057,6 +4057,12 @@ L:	linux-media@vger.kernel.org
>  S:	Maintained
>  F:	drivers/media/usb/go7007/
>  
> +GOODIX TOUCHSCREEN
> +M:	Bastien Nocera <hadess@hadess.net>
> +L:	linux-input@vger.kernel.org
> +S:	Maintained
> +F:	drivers/input/touchscreen/goodix.c
> +
>  GPIO SUBSYSTEM
>  M:	Linus Walleij <linus.walleij@linaro.org>
>  M:	Alexandre Courbot <gnurou@gmail.com>
> diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
> index 6bb9a7d..c328df3 100644
> --- a/drivers/input/touchscreen/Kconfig
> +++ b/drivers/input/touchscreen/Kconfig
> @@ -283,6 +283,19 @@ config TOUCHSCREEN_FUJITSU
>  	  To compile this driver as a module, choose M here: the
>  	  module will be called fujitsu-ts.
>  
> +config TOUCHSCREEN_GOODIX
> +	tristate "Goodix I2C touchscreen"
> +	depends on I2C && ACPI
> +	help
> +	  Say Y here if you have the Goodix touchscreen (such as one
> +	  installed in Onda v975w tablets) connected to your
> +	  system.
> +
> +	  If unsure, say N.
> +
> +	  To compile this driver as a module, choose M here: the
> +	  module will be called goodix.
> +
>  config TOUCHSCREEN_ILI210X
>  	tristate "Ilitek ILI210X based touchscreen"
>  	depends on I2C
> diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
> index 4be94fc..55af212 100644
> --- a/drivers/input/touchscreen/Makefile
> +++ b/drivers/input/touchscreen/Makefile
> @@ -33,6 +33,7 @@ obj-$(CONFIG_TOUCHSCREEN_EETI)		+= eeti_ts.o
>  obj-$(CONFIG_TOUCHSCREEN_ELO)		+= elo.o
>  obj-$(CONFIG_TOUCHSCREEN_EGALAX)	+= egalax_ts.o
>  obj-$(CONFIG_TOUCHSCREEN_FUJITSU)	+= fujitsu_ts.o
> +obj-$(CONFIG_TOUCHSCREEN_GOODIX)	+= goodix.o
>  obj-$(CONFIG_TOUCHSCREEN_ILI210X)	+= ili210x.o
>  obj-$(CONFIG_TOUCHSCREEN_INEXIO)	+= inexio.o
>  obj-$(CONFIG_TOUCHSCREEN_INTEL_MID)	+= intel-mid-touch.o
> diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c
> new file mode 100644
> index 0000000..bda6482
> --- /dev/null
> +++ b/drivers/input/touchscreen/goodix.c
> @@ -0,0 +1,452 @@
> +/*
> + *  driver for Goodix Touchscreens
> + *
> + *  Copyright (c) 2014 Red Hat Inc.
> + *
> + *  This code is based on gt9xx.c authored by andrew@goodix.com:
> + *
> + *  2010 - 2012 Goodix Technology.
> + */
> +
> +/*
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the Free
> + * Software Foundation; version 2 of the License.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/i2c.h>
> +#include <linux/input.h>
> +#include <linux/input/mt.h>
> +#include <linux/module.h>
> +#include <linux/delay.h>
> +#include <linux/irq.h>
> +#include <linux/interrupt.h>
> +#include <linux/slab.h>
> +#include <asm/unaligned.h>
> +
> +struct goodix_ts_data {
> +	struct i2c_client *client;
> +	struct input_dev *input_dev;
> +	int abs_x_max;
> +	int abs_y_max;
> +	unsigned int max_touch_num;
> +	unsigned int int_trigger_type;
> +};
> +
> +#define GOODIX_MAX_HEIGHT		4096
> +#define GOODIX_MAX_WIDTH		4096
> +#define GOODIX_INT_TRIGGER		1
> +#define GOODIX_MAX_TOUCH		10
> +
> +#define GOODIX_CONFIG_MAX_LENGTH	240
> +
> +/* Register defineS */
> +#define GOODIX_READ_COOR_ADDR		0x814E
> +#define GOODIX_REG_CONFIG_DATA		0x8047
> +#define GOODIX_REG_VERSION		0x8140
> +
> +#define RESOLUTION_LOC		1
> +#define TRIGGER_LOC		6
> +
> +#define GOODIX_INFO(fmt, arg...)       pr_info("<<-GTP-INFO->> "fmt"\n", ##arg)
> +#define GOODIX_ERROR(fmt, arg...)      pr_err("<<-GTP-ERROR->> "fmt"\n", ##arg)

Let's use standard dev_xxx()

> +
> +static const char *goodix_ts_name = "Goodix Capacitive TouchScreen";
> +static const unsigned long goodix_irq_flags[] = {
> +	IRQ_TYPE_EDGE_RISING  | IRQF_ONESHOT,
> +	IRQ_TYPE_EDGE_FALLING | IRQF_ONESHOT,
> +	IRQ_TYPE_LEVEL_LOW    | IRQF_ONESHOT,
> +	IRQ_TYPE_LEVEL_HIGH   | IRQF_ONESHOT
> +};

I'd rather you pulled out IRQF_ONESHOT and specified it explicitly in
request_threaded_irq().

> +
> +/**
> + * goodix_i2c_read - read data from a register of the i2c slave device.
> + *
> + * @client: i2c device.
> + * @reg: the register to read from.
> + * @buf: raw write data buffer.
> + * @len: length of the buffer to write
> + */
> +static int goodix_i2c_read(struct i2c_client *client,
> +				u16 reg, u8 *buf, int len)
> +{
> +	struct i2c_msg msgs[2];
> +	u8 wbuf[2] = { reg >> 8, reg & 0xff };

cpu_to_be16()?

> +
> +	msgs[0].flags = !I2C_M_RD;

I2C_M_RD is not a boolean, do not negate it.

> +	msgs[0].addr  = client->addr;
> +	msgs[0].len   = 2;
> +	msgs[0].buf   = wbuf;
> +
> +	msgs[1].flags = I2C_M_RD;
> +	msgs[1].addr  = client->addr;
> +	msgs[1].len   = len;
> +	msgs[1].buf   = buf;
> +
> +	return i2c_transfer(client->adapter, msgs, 2);

	return ret < 0 ? ret : (ret != ARRAY_SIZE(msgs) ? -EIO : 0);

I really need to get that i2c_transfer_exact() going again.

> +}
> +
> +/**
> + * goodix_i2c_write - write data to the i2c slave device.
> + *
> + * @client: i2c device.
> + * @reg: the register to read to.
> + * @buf: raw write data buffer.
> + * @len: length of the buffer to write
> + */
> +static int goodix_i2c_write(struct i2c_client *client,
> +				u16 reg, u8 *buf, int len)
> +{
> +	struct i2c_msg msg;
> +	int ret;
> +	u8 *wbuf;
> +
> +	wbuf = kzalloc(len + 2, GFP_KERNEL);
> +	if (!buf)
> +		return -ENOMEM;
> +
> +	wbuf[0] = reg >> 8;
> +	wbuf[1] = reg & 0xFF;

Again cpu_to_be16().

> +	memcpy(&wbuf[2], buf, len);
> +
> +	msg.flags = !I2C_M_RD;

Same here, not boolean.

> +	msg.addr  = client->addr;
> +	msg.len   = len + 2;
> +	msg.buf   = wbuf;
> +
> +	ret = i2c_transfer(client->adapter, &msg, 1);
> +	kfree(wbuf);
> +	return ret;
> +}
> +
> +static int goodix_ts_read_input_report(struct goodix_ts_data *ts, u8 *data)
> +{
> +	int touch_num;
> +	int ret;
> +
> +	ret = goodix_i2c_read(ts->client, GOODIX_READ_COOR_ADDR, data, 10);
> +	if (ret < 0) {
> +		GOODIX_ERROR("I2C transfer error (%d)\n", ret);
> +		return ret;
> +	}
> +
> +	touch_num = data[0] & 0x0f;
> +	if (touch_num > GOODIX_MAX_TOUCH)
> +		return -EPROTO;
> +
> +	if (touch_num > 1) {
> +		ret = goodix_i2c_read(ts->client, GOODIX_READ_COOR_ADDR + 10,
> +				   &data[10], 8 * (touch_num - 1));
> +		if (ret < 0)
> +			return ret;
> +	}
> +
> +	return touch_num;
> +}
> +
> +static void goodix_ts_parse_touch(struct goodix_ts_data *ts, u8 *coor_data)
> +{
> +	int id = coor_data[0] & 0x0F;
> +	int input_x = get_unaligned_le16(&coor_data[1]);
> +	int input_y = get_unaligned_le16(&coor_data[3]);
> +	int input_w = get_unaligned_le16(&coor_data[5]);
> +
> +	input_mt_slot(ts->input_dev, id);
> +	input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, true);
> +	input_report_abs(ts->input_dev, ABS_MT_POSITION_X, input_x);
> +	input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, input_y);
> +	input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, input_w);
> +	input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, input_w);
> +}
> +
> +/**
> + * goodix_ts_work_func - Process incoming IRQ
> + *
> + * @ts: our goodix_ts_data pointer
> + *
> + * Called when the IRQ is triggered. Read the current device state, and push
> + * the input events to the user space.
> + */
> +static void goodix_ts_work_func(struct goodix_ts_data *ts)
> +{
> +	u8  end_cmd[1] = {0};
> +	u8  point_data[1 + 8 * GOODIX_MAX_TOUCH + 1];
> +	int touch_num;
> +	int i;
> +
> +	touch_num = goodix_ts_read_input_report(ts, point_data);
> +	if (touch_num < 0)
> +		goto exit_work_func;
> +
> +	for (i = 0; i < touch_num; i++)
> +		goodix_ts_parse_touch(ts, &point_data[1 + 8 * i]);
> +
> +	input_mt_sync_frame(ts->input_dev);
> +	input_sync(ts->input_dev);
> +
> +exit_work_func:
> +	if (goodix_i2c_write(ts->client,
> +				GOODIX_READ_COOR_ADDR, end_cmd, 1) < 0)
> +		GOODIX_INFO("I2C write end_cmd error");

Why did you need to pull it out of goodix_ts_irq_handler()?

> +}
> +
> +/**
> + * goodix_ts_irq_handler - The IRQ handler
> + *
> + * @irq: interrupt number.
> + * @dev_id: private data pointer.
> + */
> +static irqreturn_t goodix_ts_irq_handler(int irq, void *dev_id)
> +{
> +	struct goodix_ts_data *ts = dev_id;
> +
> +	goodix_ts_work_func(ts);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +/**
> + * goodix_read_config - Read the embedded configuration of the panel
> + *
> + * @ts: our goodix_ts_data pointer
> + *
> + * Must be called during probe
> + */
> +static void goodix_read_config(struct goodix_ts_data *ts)
> +{
> +	int ret;
> +	u8 config[GOODIX_CONFIG_MAX_LENGTH];
> +
> +	ret = goodix_i2c_read(ts->client, GOODIX_REG_CONFIG_DATA, config,
> +			   GOODIX_CONFIG_MAX_LENGTH);
> +	if (ret < 0) {
> +		GOODIX_ERROR("Error reading config, use default value!");
> +		ts->abs_x_max = GOODIX_MAX_WIDTH;
> +		ts->abs_y_max = GOODIX_MAX_HEIGHT;
> +		ts->int_trigger_type = GOODIX_INT_TRIGGER;
> +		return;
> +	}
> +
> +	ts->abs_x_max = get_unaligned_le16(&config[RESOLUTION_LOC]);
> +	ts->abs_y_max = get_unaligned_le16(&config[RESOLUTION_LOC + 2]);
> +	ts->int_trigger_type = (config[TRIGGER_LOC]) & 0x03;
> +	if ((!ts->abs_x_max) || (!ts->abs_y_max)) {
> +		GOODIX_ERROR("Invalid config, use default value!");
> +		ts->abs_x_max = GOODIX_MAX_WIDTH;
> +		ts->abs_y_max = GOODIX_MAX_HEIGHT;
> +	}
> +}
> +
> +
> +/**
> + * goodix_read_version - Read goodix touchscreen version
> + *
> + * @client: the i2c client
> + * @version: output buffer containing the version on success
> + */
> +static int goodix_read_version(struct i2c_client *client, u16 *version)
> +{
> +	int ret;
> +	int i;
> +	u8 buf[6];
> +
> +	ret = goodix_i2c_read(client, GOODIX_REG_VERSION, buf, sizeof(buf));
> +	if (ret < 0) {
> +		GOODIX_ERROR("GTP read version failed");
> +		return ret;
> +	}
> +
> +	if (version)
> +		*version = get_unaligned_le16(&buf[4]);
> +
> +	for (i = 0; i < 4; i++) {
> +		if (!buf[i])
> +			buf[i] = 0x30;

			buf[i] = '0';

but what if they happen to have some other nonprintable garbage there?

> +	}
> +	GOODIX_INFO("IC VERSION: %c%c%c%c_%02x%02x",
> +			  buf[0], buf[1], buf[2], buf[3], buf[5], buf[4]);
> +
> +	return ret;
> +}
> +
> +/**
> + * goodix_i2c_test - I2C test function to check if the device answers.
> + *
> + * @client: the i2c client
> + */
> +static int goodix_i2c_test(struct i2c_client *client)
> +{
> +	u8 test;
> +	int ret;
> +	int retry = 0;
> +
> +	while (retry++ < 2) {
> +		ret = goodix_i2c_read(client, GOODIX_REG_CONFIG_DATA,
> +				      &test, 1);
> +		if (ret > 0)
> +			return ret;
> +
> +		GOODIX_ERROR("GTP i2c test failed time %d.", retry);
> +		msleep(20);
> +	}
> +	return ret;
> +}
> +
> +/**
> + * goodix_request_irq - Request the IRQ handler
> + *
> + * @ts: our goodix_ts_data pointer
> + *
> + * Must be called during probe
> + */
> +static int goodix_request_irq(struct goodix_ts_data *ts)
> +{
> +	int ret;
> +
> +	ret = devm_request_threaded_irq(&ts->client->dev,
> +					ts->client->irq, NULL,
> +					goodix_ts_irq_handler,
> +					goodix_irq_flags[ts->int_trigger_type],
> +					ts->client->name,
> +					ts);
> +	if (ret) {
> +		GOODIX_ERROR("Request IRQ failed! ERRNO:%d.", ret);
> +		return -1;
> +	}
> +
> +	disable_irq_nosync(ts->client->irq);

Why nosync? And why do you need to disable? Yo just need to request it
later, after you've done querying the device. And why a separate funcion
for basically one statement?

> +	return 0;
> +}
> +
> +/**
> + * goodix_request_input_dev - Allocate, populate and register the input device
> + *
> + * @ts: our goodix_ts_data pointer
> + *
> + * Must be called during probe
> + */
> +static int goodix_request_input_dev(struct goodix_ts_data *ts)
> +{
> +	int ret;
> +
> +	ts->input_dev = devm_input_allocate_device(&ts->client->dev);
> +	if (ts->input_dev == NULL) {
> +		GOODIX_ERROR("Failed to allocate input device.");
> +		return -ENOMEM;
> +	}
> +
> +	ts->input_dev->evbit[0] = BIT_MASK(EV_SYN) |
> +				  BIT_MASK(EV_KEY) |
> +				  BIT_MASK(EV_ABS);
> +
> +	input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X, 0,
> +				ts->abs_x_max, 0, 0);
> +	input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, 0,
> +				ts->abs_y_max, 0, 0);
> +	input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0, 255, 0, 0);
> +	input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
> +
> +	input_mt_init_slots(ts->input_dev, GOODIX_MAX_TOUCH,
> +			    INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED);
> +
> +	ts->input_dev->name = goodix_ts_name;
> +	ts->input_dev->phys = "input/ts";
> +	ts->input_dev->id.bustype = BUS_I2C;
> +	ts->input_dev->id.vendor = 0x0416;
> +	ts->input_dev->id.product = 0x1001;
> +	ts->input_dev->id.version = 10427;
> +
> +	ret = input_register_device(ts->input_dev);
> +	if (ret) {
> +		GOODIX_ERROR("Failed to register %s input device",
> +			  ts->input_dev->name);
> +		return -ENODEV;

Why -ENODEV instead of ret?

> +	}
> +
> +	return 0;
> +}
> +
> +static int goodix_ts_probe(struct i2c_client *client,
> +		const struct i2c_device_id *id)
> +{
> +	int ret;
> +	struct goodix_ts_data *ts;
> +	u16 version_info;
> +
> +	GOODIX_INFO("GTP I2C Address: 0x%02x", client->addr);
> +
> +	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
> +		GOODIX_ERROR("I2C check functionality failed.");
> +		return -ENODEV;
> +	}
> +	ts = devm_kzalloc(&client->dev, sizeof(*ts), GFP_KERNEL);
> +	if (ts == NULL) {

	if (!ts)

is a preferred form (by me at least).

> +		GOODIX_ERROR("Alloc GFP_KERNEL memory failed.");
> +		return -ENOMEM;
> +	}
> +
> +	ts->client = client;
> +	i2c_set_clientdata(client, ts);
> +
> +	ret = goodix_i2c_test(client);
> +	if (ret < 0) {
> +		client->addr = 0x5d;

Umm, why? Let's trust board code/i2c core  to configure the i2c device
properly.

> +		ret = goodix_i2c_test(client);
> +		if (ret < 0) {
> +			GOODIX_ERROR("I2C communication ERROR!");
> +			return -ENODEV;
> +		}
> +		GOODIX_INFO("GTP I2C new Address: 0x%02x", client->addr);
> +	}
> +
> +	goodix_read_config(ts);
> +
> +	ret = goodix_request_input_dev(ts);
> +	if (ret < 0) {
> +		GOODIX_ERROR("GTP request input dev failed");
> +		return ret;
> +	}
> +
> +	ret = goodix_request_irq(ts);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = goodix_read_version(client, &version_info);
> +	if (ret < 0) {
> +		GOODIX_ERROR("Read version failed.");
> +		return ret;
> +	}
> +
> +	enable_irq(ts->client->irq);
> +
> +	return 0;
> +}
> +
> +static const struct i2c_device_id goodix_ts_id[] = {
> +	{ "GDIX1001:00", 0 },
> +	{ }

Do we have to have this table?

> +};
> +
> +static const struct acpi_device_id goodix_acpi_match[] = {
> +	{ "GDIX1001", 0 },
> +	{ }
> +};
> +MODULE_DEVICE_TABLE(acpi, goodix_acpi_match);
> +
> +static struct i2c_driver goodix_ts_driver = {
> +	.probe = goodix_ts_probe,
> +	.id_table = goodix_ts_id,
> +	.driver = {
> +		.name = "Goodix-TS",
> +		.owner = THIS_MODULE,
> +		.acpi_match_table = goodix_acpi_match,
> +	},
> +};
> +
> +module_i2c_driver(goodix_ts_driver);
> +
> +MODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@gmail.com>");
> +MODULE_AUTHOR("Bastien Nocera <hadess@hadess.net>");
> +MODULE_DESCRIPTION("Goodix touchscreen driver");
> +MODULE_LICENSE("GPL v2");
> -- 
> 2.1.0
> 
> 

Thanks.

-- 
Dmitry

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox