* [PATCH 3/3] HID: logitech-hidpp: avoid unintended fall-through
From: Peter Wu @ 2014-12-16 0:50 UTC (permalink / raw)
To: Jiri Kosina, Benjamin Tissoires, Nestor Lopez Casado
Cc: linux-input, linux-kernel
In-Reply-To: <1418691016-30681-1-git-send-email-peter@lekensteyn.nl>
Add a return to avoid a fall-through. Introduced in commit
57ac86cf52e903d9e3e0f12b34c814cce6b65550 ("HID: logitech-hidpp: add
support of the first Logitech Wireless Touchpad").
Signed-off-by: Peter Wu <peter@lekensteyn.nl>
---
drivers/hid/hid-logitech-hidpp.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c
index 2315358..09eee17 100644
--- a/drivers/hid/hid-logitech-hidpp.c
+++ b/drivers/hid/hid-logitech-hidpp.c
@@ -811,6 +811,7 @@ static int wtp_raw_event(struct hid_device *hdev, u8 *data, int size)
input_event(wd->input, EV_KEY, BTN_RIGHT,
!!(data[1] & 0x02));
input_sync(wd->input);
+ return 0;
} else {
if (size < 21)
return 1;
--
2.1.3
^ permalink raw reply related
* [PATCH 2/3] HID: logitech-{dj,hidpp}: check report length
From: Peter Wu @ 2014-12-16 0:50 UTC (permalink / raw)
To: Jiri Kosina, Benjamin Tissoires, Nestor Lopez Casado
Cc: linux-input, linux-kernel
In-Reply-To: <1418691016-30681-1-git-send-email-peter@lekensteyn.nl>
Malicious USB devices can send bogus reports smaller than the expected
buffer size. Ensure that the length is valid to avoid reading out of
bounds.
For the old WTP, I do not have a HID descriptor so just check for the
minimum length in hidpp_raw_event (this can be changed to an inequality
later).
Signed-off-by: Peter Wu <peter@lekensteyn.nl>
---
Hi,
If you know that the WTP report (ID 2) has a length of 2, then you can change
"<" to "!=" and remove the paragraph from the commit message.
Kind regards,
Peter
---
drivers/hid/hid-logitech-dj.c | 16 +++++++++++++++-
drivers/hid/hid-logitech-hidpp.c | 12 +++++++++---
2 files changed, 24 insertions(+), 4 deletions(-)
diff --git a/drivers/hid/hid-logitech-dj.c b/drivers/hid/hid-logitech-dj.c
index c917ab6..5bc6d80 100644
--- a/drivers/hid/hid-logitech-dj.c
+++ b/drivers/hid/hid-logitech-dj.c
@@ -962,10 +962,24 @@ static int logi_dj_raw_event(struct hid_device *hdev,
switch (data[0]) {
case REPORT_ID_DJ_SHORT:
+ if (size != DJREPORT_SHORT_LENGTH) {
+ dev_err(&hdev->dev, "DJ report of bad size (%d)", size);
+ return false;
+ }
return logi_dj_dj_event(hdev, report, data, size);
case REPORT_ID_HIDPP_SHORT:
- /* intentional fallthrough */
+ if (size != HIDPP_REPORT_SHORT_LENGTH) {
+ dev_err(&hdev->dev,
+ "Short HID++ report of bad size (%d)", size);
+ return false;
+ }
+ return logi_dj_hidpp_event(hdev, report, data, size);
case REPORT_ID_HIDPP_LONG:
+ if (size != HIDPP_REPORT_LONG_LENGTH) {
+ dev_err(&hdev->dev,
+ "Long HID++ report of bad size (%d)", size);
+ return false;
+ }
return logi_dj_hidpp_event(hdev, report, data, size);
}
diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c
index ae23dec..2315358 100644
--- a/drivers/hid/hid-logitech-hidpp.c
+++ b/drivers/hid/hid-logitech-hidpp.c
@@ -992,11 +992,17 @@ static int hidpp_raw_event(struct hid_device *hdev, struct hid_report *report,
return 1;
}
return hidpp_raw_hidpp_event(hidpp, data, size);
+ case 0x02:
+ if (size < 2) {
+ hid_err(hdev, "Received HID report of bad size (%d)",
+ size);
+ return 1;
+ }
+ if (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP)
+ return wtp_raw_event(hdev, data, size);
+ return 1;
}
- if (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP)
- return wtp_raw_event(hdev, data, size);
-
return 0;
}
--
2.1.3
^ permalink raw reply related
* [PATCH 1/3] HID: logitech-hidpp: detect HID++ 2.0 errors too
From: Peter Wu @ 2014-12-16 0:50 UTC (permalink / raw)
To: Jiri Kosina, Benjamin Tissoires, Nestor Lopez Casado
Cc: linux-input, linux-kernel
In-Reply-To: <1418691016-30681-1-git-send-email-peter@lekensteyn.nl>
Devices speaking HID++ 2.0 report a different error code (0xff). Detect
these errors too to avoid 5 second delays when the device reports an
error. Caught by... well, a bug in the QEMU emulation of this receiver.
Renamed fap to rap for HID++ 1.0 errors because it is more logical,
it has no functional difference.
Signed-off-by: Peter Wu <peter@lekensteyn.nl>
---
drivers/hid/hid-logitech-hidpp.c | 17 ++++++++++++++---
1 file changed, 14 insertions(+), 3 deletions(-)
diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c
index 2f420c0..ae23dec 100644
--- a/drivers/hid/hid-logitech-hidpp.c
+++ b/drivers/hid/hid-logitech-hidpp.c
@@ -105,6 +105,7 @@ struct hidpp_device {
};
+/* HID++ 1.0 error codes */
#define HIDPP_ERROR 0x8f
#define HIDPP_ERROR_SUCCESS 0x00
#define HIDPP_ERROR_INVALID_SUBID 0x01
@@ -119,6 +120,8 @@ struct hidpp_device {
#define HIDPP_ERROR_REQUEST_UNAVAILABLE 0x0a
#define HIDPP_ERROR_INVALID_PARAM_VALUE 0x0b
#define HIDPP_ERROR_WRONG_PIN_CODE 0x0c
+/* HID++ 2.0 error codes */
+#define HIDPP20_ERROR 0xff
static void hidpp_connect_event(struct hidpp_device *hidpp_dev);
@@ -192,9 +195,16 @@ static int hidpp_send_message_sync(struct hidpp_device *hidpp,
}
if (response->report_id == REPORT_ID_HIDPP_SHORT &&
- response->fap.feature_index == HIDPP_ERROR) {
+ response->rap.sub_id == HIDPP_ERROR) {
+ ret = response->rap.params[1];
+ dbg_hid("%s:got hidpp error %02X\n", __func__, ret);
+ goto exit;
+ }
+
+ if (response->report_id == REPORT_ID_HIDPP_LONG &&
+ response->fap.feature_index == HIDPP20_ERROR) {
ret = response->fap.params[1];
- dbg_hid("__hidpp_send_report got hidpp error %02X\n", ret);
+ dbg_hid("%s:got hidpp 2.0 error %02X\n", __func__, ret);
goto exit;
}
@@ -271,7 +281,8 @@ static inline bool hidpp_match_answer(struct hidpp_report *question,
static inline bool hidpp_match_error(struct hidpp_report *question,
struct hidpp_report *answer)
{
- return (answer->fap.feature_index == HIDPP_ERROR) &&
+ return ((answer->rap.sub_id == HIDPP_ERROR) ||
+ (answer->fap.feature_index == HIDPP20_ERROR)) &&
(answer->fap.funcindex_clientid == question->fap.feature_index) &&
(answer->fap.params[0] == question->fap.funcindex_clientid);
}
--
2.1.3
^ permalink raw reply related
* [PATCH 0/3] HID: logitech-{dj,hidpp}: more reliability fixes
From: Peter Wu @ 2014-12-16 0:50 UTC (permalink / raw)
To: Jiri Kosina, Benjamin Tissoires, Nestor Lopez Casado
Cc: linux-input, linux-kernel
Hi Jiri,
Here are more fixes intended for the 3.19 tree after a review. Two bugfixes.
one which was mentioned in a mail with Benjamin ("avoid unintended
fall-through") and a fix to avoid a possible 5 second delay for HID++ 2.0
errors. I haven't encountered a case where the hidpp module generates a HID++
2.0 error though, so maybe that change can go to 3.20 too if you want to keep
the changeset small.
The third (second) patch adds a check to avoid passing a short report. A similar
fix should probably be written for stable kernels (the code was changed in 3.19,
but the length check was already missing in older kernels).
Kind regards,
Peter
Peter Wu (3):
HID: logitech-hidpp: detect HID++ 2.0 errors too
HID: logitech-{dj,hidpp}: check report length
HID: logitech-hidpp: avoid unintended fall-through
drivers/hid/hid-logitech-dj.c | 16 +++++++++++++++-
drivers/hid/hid-logitech-hidpp.c | 30 ++++++++++++++++++++++++------
2 files changed, 39 insertions(+), 7 deletions(-)
--
2.1.3
^ permalink raw reply
* The return value of hid_input_report and raw_event
From: Peter Wu @ 2014-12-15 22:31 UTC (permalink / raw)
To: Jiri Kosina, linux-input
Hi Jiri and list,
The HID core has a hid_input_report function which returns an integer,
but all its callers are not really changing their behavior based on the
return value. The few^Wonly exception that does not completely ignore
the return value is the hid-logitech-dj driver which prints a debugging
message.
Should this method be changed to return void? The kerneldoc does not
document its return value anyway.
Confusion 2: the raw_event callback of the hid_driver structure returns
an int, but over time non-negative values are ignored by
hid_input_report. This happened in the following change:
--------------------------------------------------
commit b1a1442a23776756b254b69786848a94d92445ba
Author: Jiri Kosina <jkosina@suse.cz>
Date: Mon Jun 3 11:27:48 2013 +0200
HID: core: fix reporting of raw events
hdrw->raw event can return three different return value types:
- ret < 0 indicates that the hdrv driver found an error while parsing
- ret == 0 indicates no error has been encountered, and the driver has
processed the report
- ret > 0 indicates that there was no parsing error, and the driver hasn't
processed the event.
Calling hid_report_raw_event() has to be called appropriately so that it
reflects what has been done by ->raw_event() callback, otherwise we might
updates of the in-kernel structure are lost upon arrival of the report, which
is wrong.
Reported-and-tested-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Reported-and-tested-by: Daniel Leung <daniel.leung@linux.intel.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index c272078..8f616bd 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1293,7 +1293,7 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i
if (hdrv && hdrv->raw_event && hid_match_report(hid, report)) {
ret = hdrv->raw_event(hid, report, data, size);
- if (ret != 0) {
+ if (ret < 0) {
ret = ret < 0 ? ret : 0;
goto unlock;
}
--------------------------------------------------
So now it does not matter whether the raw_event method returns 0 or 1.
The documentation says:
raw_event and event should return 0 on no action performed, 1 when
no further processing should be done and negative on error
What does "no further processing" mean? I guess that the intention was
to signal from a HID driver to ignore the packet, but that the above
change was done to update the state and allow hidraw to pick up the
report.
--
Kind regards,
Peter
https://lekensteyn.nl
^ permalink raw reply related
* Re: PROBLEM: [HP Stream Notebook - 11-d010nr] clickpad malfunctions after performing a hardware click
From: Amordea Whiteoak @ 2014-12-15 20:05 UTC (permalink / raw)
To: Benjamin Tissoires; +Cc: linux-input, Peter Hutterer, Andrew Duggan
In-Reply-To: <CAN+gG=GucHKyGB0Z=qP+G2KSej0yoVe3vpa3AzRbBDeP2jw9Qg@mail.gmail.com>
[-- Attachment #1: Type: text/plain, Size: 993 bytes --]
> Strictly speaking, there is no right click button on clickpads. We
> emulate one with the software buttons in Xorg.
> IIRC, there were some "workarounds" in your original bugs which
> consist in disabling the software buttons area. Can you make sure that
> there is no left over from this?
I learn new things about clickpads every day. :)
To my knowledge, those configurations changes should reset upon reboot
and I never committed any of those lines to any of my startup files.
So we should be good there, I think. Just in case, I am enclosing the
output of my synclient -l, which should be the default configuration.
> If this still doesn't work, we wil need to check that the X and Y
> ranges reported by your clickpad are accurate and that the software
> buttons are properly activated.
I don't know the testing methodology to use to provide positioning
data for my trackpad, but let me know if you need that and how you
want me to get it and I will be happy to provide.
Thank you!
[-- Attachment #2: synclient.list --]
[-- Type: application/octet-stream, Size: 1993 bytes --]
Parameter settings:
LeftEdge = 161
RightEdge = 3848
TopEdge = 123
BottomEdge = 2144
FingerLow = 25
FingerHigh = 30
MaxTapTime = 180
MaxTapMove = 202
MaxDoubleTapTime = 180
SingleTapTimeout = 180
ClickTime = 100
EmulateMidButtonTime = 75
EmulateTwoFingerMinZ = 282
EmulateTwoFingerMinW = 7
VertScrollDelta = 92
HorizScrollDelta = 92
VertEdgeScroll = 1
HorizEdgeScroll = 0
CornerCoasting = 0
VertTwoFingerScroll = 1
HorizTwoFingerScroll = 0
MinSpeed = 1
MaxSpeed = 1.75
AccelFactor = 0.0434594
TouchpadOff = 0
LockedDrags = 0
LockedDragTimeout = 5000
RTCornerButton = 2
RBCornerButton = 3
LTCornerButton = 0
LBCornerButton = 0
TapButton1 = 1
TapButton2 = 3
TapButton3 = 0
ClickFinger1 = 1
ClickFinger2 = 1
ClickFinger3 = 0
CircularScrolling = 0
CircScrollDelta = 0.1
CircScrollTrigger = 0
CircularPad = 0
PalmDetect = 0
PalmMinWidth = 10
PalmMinZ = 200
CoastingSpeed = 20
CoastingFriction = 50
PressureMotionMinZ = 30
PressureMotionMaxZ = 160
PressureMotionMinFactor = 1
PressureMotionMaxFactor = 1
ResolutionDetect = 1
GrabEventDevice = 0
TapAndDragGesture = 1
AreaLeftEdge = 0
AreaRightEdge = 0
AreaTopEdge = 0
AreaBottomEdge = 0
HorizHysteresis = 23
VertHysteresis = 23
ClickPad = 0
^ permalink raw reply
* Re: [PATCHv3 0/5] ARM:sunxi:ps2 Added support for A10/A20 ps2 controller.
From: Chen-Yu Tsai @ 2014-12-15 15:41 UTC (permalink / raw)
To: Hans de Goede
Cc: Vishnu Patekar, mark.rutland@arm.com, devicetree@vger.kernel.org,
jdelvare@suse.de, linux@arm.linux.org.uk, pawel.moll@arm.com,
ijc+devicetree@hellion.org.uk, benh@kernel.crashing.org,
Dmitry Torokhov, linux-kernel@vger.kernel.org,
ralf@linux-mips.org, robh+dt@kernel.org, msalter@redhat.com,
linux-input@vger.kernel.org, Grant Likely, Kumar Gala,
maxime.ripard@free-electrons.com, linux-arm-kernel
In-Reply-To: <548EFA9F.4080208@redhat.com>
Hi,
On Mon, Dec 15, 2014 at 11:13 PM, Hans de Goede <hdegoede@redhat.com> wrote:
> Hi,
>
>
> On 15-12-14 15:13, Vishnu Patekar wrote:
>>
>> Hi,
>>
>> On Sun, Dec 14, 2014 at 2:31 PM, Hans de Goede <hdegoede@redhat.com>
>> wrote:
>>>
>>> Hi,
>>>
>>> On 13-12-14 21:01, Vishnu Patekar wrote:
>>>>
>>>>
>>>> Hello Hans,
>>>> Please find my comments inlined.
>>>>
>>>> On 12/13/14, Hans de Goede <hdegoede@redhat.com> wrote:
>>>>>
>>>>>
>>>>> Hi VishnuPatekar,
>>>>>
>>>>> The patch mangling for this set seems to have gone a bit wrong I'm
>>>>> afraid
>>>>
>>>>
>>>>
>>>> No, this time I've corrected it. Infact, last version of patch did not
>>>> used the status bit error macros.
>>>>
>>>>> a lot of the patches have my fixup commit messages (which should have
>>>>> disappeared when squashing in the patches), please replace those by
>>>>> proper
>>>>> commit messages describing what the patch actually does.
>>>>
>>>>
>>>> Yes, [PATCHv3 3/5] uses fixup. I'll correct it.
>>>>>
>>>>>
>>>>>
>>>>> Also the adding of the commented nodes for the lime2 seems to be gone
>>>>> entirely
>>>>> from the set, instead now only a comment about the conflict with the
>>>>> hdmi
>>>>> pins is added, but it is above the i2c node instead of above a ps2
>>>>> node.
>>>>>
>>>> Maxime's suggested that we should not add commented nodes specially
>>>> when its trivial to apply. And just note saying ps20 pins conflict
>>>> with HDMI.
>>>
>>>
>>>
>>> Ah, I see.
>>>
>>>> Should I remove the this comment as well?
>>>> Or
>>>> Put this note in start of DTS file?
>>>
>>>
>>>
>>> The comment should be added to where the pinctrl bits are, not to the
>>> lime2
>>> file, ps0 will conflict with hdmi on all boards.
>>
>>
>> Well, In that case,PS2_0 pins conflicts with HDMI, PS2_1 pins
>> conflicts with LCD. Every pin has multiplexing.
>
>
> Almost every A10 board has a hdmi connector, and only the hdmi ddc pins
> are multiplexed, so this is sort of special, but yes if we do not have
> the commented nodes in the dts file, then this comment can be dropped too
> I guess.
All the HDMI pins have dedicated pins. In addition, the DDC pins are
multiplexed. On the Lime, the dedicated pins (ball # R23, R22) are
used. I just checked the schematics. There should be no conflict.
ChenYu
^ permalink raw reply
* Re: PROBLEM: [HP Stream Notebook - 11-d010nr] clickpad malfunctions after performing a hardware click
From: Benjamin Tissoires @ 2014-12-15 15:27 UTC (permalink / raw)
To: Amordea Whiteoak; +Cc: linux-input, Peter Hutterer, Andrew Duggan
In-Reply-To: <CALmnu0Y0kvU-yqrKvNAQmjUgFJQ-v0NESyV6o_=CuVzc2dx=YQ@mail.gmail.com>
Hey!
On Sat, Dec 13, 2014 at 6:52 PM, Amordea Whiteoak <amordea@gmail.com> wrote:
> Hello gentlemen, I have returned.
>
> After trying to figure out for a few days how to apply the patch and
> not really getting anywhere, I eventually bothered Andrew who very
> helpfully showed me the way (thank you again Andrew!).
>
> The patch works very well. No mouse input lockups anymore when
> depressing hardware mouse button. Left-click performs as it should.
> However right-clicking does not. It performs exactly as if it were
> also a left-click button. It is admittedly hard to tell how many
> buttons should be on this clickpad since there's a trackpad covering
> them up. But this was originally designed to be a Windows machine so
> I'm sure there's at least a separate right-click button.
Strictly speaking, there is no right click button on clickpads. We
emulate one with the software buttons in Xorg.
IIRC, there were some "workarounds" in your original bugs which
consist in disabling the software buttons area. Can you make sure that
there is no left over from this?
If this still doesn't work, we wil need to check that the X and Y
ranges reported by your clickpad are accurate and that the software
buttons are properly activated.
Cheers,
Benjamin
>
> I am enclosing some new evemu-record, hid-recorder, and dmesg debug
> data. Each of these recordings is me using a non-conductive pen to
> click the left mouse button and then the right.
>
> Please let me know if there is anything else I can provide. Thank you.
>
> On Mon, Dec 8, 2014 at 2:33 PM, Amordea Whiteoak <amordea@gmail.com> wrote:
>>> My guess would be:
>>> try open the settings panel, go into mouse (or touchpad, or whatever
>>> it is called), look for an option which should allow you to change
>>> this setting. If there are none, complain to the Ubuntu team by
>>> opening a new bug on their launchpad.
>>
>> Aye, I will be opening a new report on Launchpad it seems. Thank you
>> for all your help!
>>
>>> I hope Andrew will be able to fix your touchpad soonish. Thanks for
>>> the followup BTW Andrew.
>>
>> And yes, thank you Andrew!!
>>
>>
>> On Mon, Dec 8, 2014 at 2:26 PM, Benjamin Tissoires
>> <benjamin.tissoires@gmail.com> wrote:
>>> On Mon, Dec 8, 2014 at 2:16 PM, Amordea Whiteoak <amordea@gmail.com> wrote:
>>>> While I have the ears of the touchpad gods, there is one more tiny
>>>> issue I'd like to report. This may be simply a configuration issue,
>>>> but I would not know how to fix it.
>>>>
>>>> The window for double-tapping (tapping the touchpad twice to simulate
>>>> a double-click) is remarkably brief. Let me be clear, double-tapping
>>>> on the touchpad does work, however if you do not get the second tap
>>>> within about a 200ms window after the first, it seems to fail to
>>>> register as a double-click, counting it as two unrelated single
>>>> clicks--this is an uncomfortably short window of opportunity. A
>>>> temporary workaround seems to be triple-tapping which for whatever
>>>> reason allow for a broader window (much closer to a full second) and
>>>> registers as a double-tap, but that just seems to be a happy accident
>>>> and is certainly not an expected feature. Is there any way to broaden
>>>> that window?
>>>
>>> This is usually an Xorg configuration problem (definitively not a
>>> kernel one). However, you are using ubuntu 14.10 and I don't know if
>>> they decided to switch to MIR yet. If so, I have no clues on what is
>>> driving the touchpad, so I won't be of any help.
>>>
>>> My guess would be:
>>> try open the settings panel, go into mouse (or touchpad, or whatever
>>> it is called), look for an option which should allow you to change
>>> this setting. If there are none, complain to the Ubuntu team by
>>> opening a new bug on their launchpad.
>>>
>>>>
>>>> I did not have this problem on my previous laptop with Lubuntu
>>>> installed (though it had 14.04 not 14.10--it's no longer operational
>>>> after suffering an unfortunate accident so I can't do comparison
>>>> testing with it any longer).
>>>
>>> ouch :/
>>>
>>>>
>>>> I promise this is my last remaining issue with the touchpad. :)
>>>
>>> No problem. We prefer having responsive users who tries to solve their
>>> problems than frustrated users :)
>>>
>>> I hope Andrew will be able to fix your touchpad soonish. Thanks for
>>> the followup BTW Andrew.
>>>
>>> Cheers,
>>> Benjamin
>>>
>>>>
>>>> On Mon, Dec 8, 2014 at 1:39 PM, Amordea Whiteoak <amordea@gmail.com> wrote:
>>>>> My Linux newbieness is showing. :)
>>>>>
>>>>> I attempted to edit and boot the grub configuration, but I don't think
>>>>> I did it right. I went with the seemingly more sure-fire way to get
>>>>> your data and followed the second set of instructions.
>>>>>
>>>>> Enclosed is all the dmesg output once I got that working.
>>>>>
>>>>> On Mon, Dec 8, 2014 at 12:59 PM, Benjamin Tissoires
>>>>> <benjamin.tissoires@gmail.com> wrote:
>>>>>> On Mon, Dec 8, 2014 at 12:14 PM, Amordea Whiteoak <amordea@gmail.com> wrote:
>>>>>>> There may be a thing I am failing to understand about dmesg here, but
>>>>>>> a grep through both dmesg and /var/log/dmesg yielded no hits on
>>>>>>> "i2c_hid.debug=1". I did find plenty of hits on just "i2c_hid", which
>>>>>>> yielded several repetitive lines of what appears to be various
>>>>>>> modules. Please let me know if there is something I am failing to
>>>>>>> understand here, but I could not find the requested phrase in my
>>>>>>> dmesg.
>>>>>>
>>>>>> I meant that when you reboot the laptop, in grub, append
>>>>>> "i2c_hid.debug=1" to the kernel command line.
>>>>>>
>>>>>> This should be seen in one of the first few lines of dmesg (the one
>>>>>> starting by "[ 0.000000] Command line:
>>>>>> BOOT_IMAGE=/boot/vmlinuz-3.18.0-031800rc7-generic "), and a lot of raw
>>>>>> events should be dumped in the dmesg.
>>>>>>
>>>>>>>
>>>>>>> I do have the hid-recorder output though, which I am attaching here.
>>>>>>> This time I used a non-conductive pen to only generate clicks without
>>>>>>> all the positioning data piling in on top. This is a recording of two
>>>>>>> left clicks.
>>>>>>>
>>>>>>
>>>>>> Ok, so at least, the device sends a sane behavior (one event per
>>>>>> click/release, with one bit changed). Unfortunately, I think the
>>>>>> problem lies in the configuration of your device by hid-rmi. So the
>>>>>> dmesg output while i2c_hid.debug=1 is set should help to figure out
>>>>>> the problem.
>>>>>>
>>>>>> If for whatever reasons you do not manage to get the parameter
>>>>>> appended to your command line, the following commands should suffice
>>>>>> (as root):
>>>>>> #> rmmod hid-rmi
>>>>>> #> echo 1 > /sys/module/i2c_hid/parameters/debug
>>>>>> #> modprobe hid-rmi
>>>>>>
>>>>>> do a few events on the touchpad (with clicks)
>>>>>>
>>>>>> #> echo 0 > /sys/module/i2c_hid/parameters/debug
>>>>>>
>>>>>> and send out the dmesg.
>>>>>>
>>>>>> Cheers,
>>>>>> Benjamin
>>>>>>
>>>>>>> If there is anything else I can provide, please let me know.
>>>>>>>
>>>>>>> Thank you for helping with this bug. :)
>>>>>>>
>>>>>>> On Mon, Dec 8, 2014 at 11:44 AM, Benjamin Tissoires
>>>>>>> <benjamin.tissoires@gmail.com> wrote:
>>>>>>>> Hi Amordea,
>>>>>>>>
>>>>>>>> On Mon, Dec 8, 2014 at 11:20 AM, Amordea Whiteoak <amordea@gmail.com> wrote:
>>>>>>>>> My apologies if my bug report was inadequate. It is the first upstream
>>>>>>>>> report I've ever filed, though I did attempt to give all the
>>>>>>>>> information they requested to the best of my ability.
>>>>>>>>
>>>>>>>> Oh, no, I was not complaining about your way of reporting the bug. I
>>>>>>>> know that it can be difficult for users to report _and_ provide all
>>>>>>>> the necessary information unless you already know a little bit about
>>>>>>>> the communities, how they work and what tool they use.
>>>>>>>> My complain was more that the way it was triaged: try an upstream
>>>>>>>> kernel; oh, does not work; send it upstream because it's a "poor
>>>>>>>> driver implementation". Whereas here, there may be any part of the
>>>>>>>> stack involved unless we look at the evemu-record (which is the output
>>>>>>>> of the kernel BTW). And saying that the driver is badly designed
>>>>>>>> really does not help...
>>>>>>>> Last, the "meta bug" they have is either a problem in the kernel
>>>>>>>> drivers they ship, or a not up to date Xorg stack. FWIW, I don't think
>>>>>>>> we have this on Fedora.
>>>>>>>>
>>>>>>>> Anyway, thanks for the explanations that you give in the next
>>>>>>>> paragraph, it gives a more comprehensive bug report :)
>>>>>>>>
>>>>>>>>>
>>>>>>>>> If it helps: to be clear about the design of this clickpad, it is one
>>>>>>>>> where the entire pad is touch-sensitive, even the area over the
>>>>>>>>> hardware click buttons which are on the bottom. The entire pad is one
>>>>>>>>> piece, so the pad itself shifts when you click a button. The
>>>>>>>>> malfunction occurs whenever any of these buttons are clicked, but the
>>>>>>>>> simulated clicks (tapping on the pad) behave adequately and do not
>>>>>>>>> cause any mouse input lock-ups. The malfunction itself causes ALL
>>>>>>>>> subsequent mouse clicks from any source (including a USB mouse) to
>>>>>>>>> only act in the spot where the first hardware click from the clickpad
>>>>>>>>> was performed and cannot be adjusted until the clickpad has been
>>>>>>>>> disabled (xinput disable <id>). The hardware buttons on the clickpad
>>>>>>>>> itself do not register as clicks at all, they only cause all mouse
>>>>>>>>> input to malfunction as previously described.
>>>>>>>>>
>>>>>>>>> I am enclosing the requested evemu-record data. This is a recording of
>>>>>>>>> my clicking the left hardware click button three times in rapid
>>>>>>>>> succession, but failure generally occurs after the first click.
>>>>>>>>
>>>>>>>> Many thanks for the logs. So here, I can see that when you click on
>>>>>>>> the touchpad, both BTN_LEFT and BTN_RIGHT are emitted, but they are
>>>>>>>> never released :) I do not see either the 2 other clicks.
>>>>>>>> So yes, here the driver is at fault and misses to release the clicks.
>>>>>>>> This infers the cross-device problem in X BTW.
>>>>>>>>
>>>>>>>>>
>>>>>>>>> A curious behavior I noticed in the process of getting this recording
>>>>>>>>> is that on the first click, I received a pasted text line in my
>>>>>>>>> terminal. I could not reproduce this behavior by doing an
>>>>>>>>> enable/disable cycle on the trackpad, but to confirm I rebooted a few
>>>>>>>>> times to test and sure enough, the very first click each boot triggers
>>>>>>>>> a clipboard paste event.
>>>>>>>>
>>>>>>>> You must have the middle button emulation enabled in Xorg (hitting
>>>>>>>> both left and right button will trigger a middle button). So when we
>>>>>>>> will be able to fix this bug, the spurious middle click should
>>>>>>>> disappear.
>>>>>>>>
>>>>>>>>>
>>>>>>>>> If there is any more information I can provide, please let me know.
>>>>>>>>
>>>>>>>> Ideally, I'd like to punt this one to Andrew, but I think we would be
>>>>>>>> grateful if you could also provide 2 more things:
>>>>>>>> - the dmesg when "i2c_hid.debug=1" is appended to the kernel boot line
>>>>>>>> (without the quotes)
>>>>>>>> - the hid-recorder output when you trigger the bug
>>>>>>>>
>>>>>>>> hid-recorder should be installed from sources in Ubuntu I guess:
>>>>>>>> http://bentiss.github.io/hid-replay-docs/
>>>>>>>>
>>>>>>>> The hid-recorder output might not be absolutely needed, so as long as
>>>>>>>> we have the dmesg with i2c_hid.debug=1, we should be fine.
>>>>>>>>
>>>>>>>> Cheers,
>>>>>>>> Benjamin
>>>>>>>>
>>>>>>>>>
>>>>>>>>> Thank you!
>>>>>>>>>
>>>>>>>>> On Mon, Dec 8, 2014 at 10:01 AM, Benjamin Tissoires
>>>>>>>>> <benjamin.tissoires@gmail.com> wrote:
>>>>>>>>>> Hi Amordea,
>>>>>>>>>>
>>>>>>>>>> I must say, the bug triaging is worse and worse with ubuntu :(
>>>>>>>>>>
>>>>>>>>>> From the bug description, I can not tell if the problem lies in the
>>>>>>>>>> kernel, or if it is the synaptics input driver or the xserver which is
>>>>>>>>>> in fault. I would be tempted to say that the problem lies in the upper
>>>>>>>>>> layers given the cross-devices problem.
>>>>>>>>>>
>>>>>>>>>> Anyway, to be able to understand the problem, we will need to get an
>>>>>>>>>> evemu-record output of your device when you are reproducing the bug.
>>>>>>>>>> You can find evemu in your distribution channels, or here:
>>>>>>>>>> http://www.freedesktop.org/wiki/Evemu/
>>>>>>>>>>
>>>>>>>>>> Given that you have an hid-rmi/i2c device, I am adding Andrew in CC,
>>>>>>>>>> and Peter for the upper layers if there is anything wrong there.
>>>>>>>>>>
>>>>>>>>>> Cheers,
>>>>>>>>>> Benjamin
>>>>>>>>>>
>>>>>>>>>> On Sun, Dec 7, 2014 at 5:50 PM, Amordea Whiteoak <amordea@gmail.com> wrote:
>>>>>>>>>>> Original Bug Report:
>>>>>>>>>>> https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1398533
>>>>>>>>>>>
>>>>>>>>>>> Bug Description: After clicking once at the bottom of my clickpad on
>>>>>>>>>>> either button, if I move my cursor elsewhere on the screen, and then
>>>>>>>>>>> subsequently click again (with either clickpad or external mouse this
>>>>>>>>>>> time) it registers a click at the location where my cursor icon was
>>>>>>>>>>> originally. I can continue to move my cursor anywhere on the screen,
>>>>>>>>>>> and it still registers the click in the original location.
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> cat /proc/version
>>>>>>>>>>> Linux version 3.18.0-031800rc7-generic (apw@gomeisa) (gcc version
>>>>>>>>>>> 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5) ) #201411302035 SMP Mon Dec 1
>>>>>>>>>>> 01:36:38 UTC 2014
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> lsb_release -rd
>>>>>>>>>>> Description: Ubuntu 14.10
>>>>>>>>>>> Release: 14.10
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> sh /usr/src/linux-headers-3.18.0-031800rc7/scripts/ver_linux
>>>>>>>>>>> If some fields are empty or look unusual you may have an old version.
>>>>>>>>>>> Compare to the current minimal requirements in Documentation/Changes.
>>>>>>>>>>>
>>>>>>>>>>> Linux woprjr 3.18.0-031800rc7-generic #201411302035 SMP Mon Dec 1
>>>>>>>>>>> 01:36:38 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux
>>>>>>>>>>>
>>>>>>>>>>> Gnu C
>>>>>>>>>>> /usr/src/linux-headers-3.18.0-031800rc7/scripts/ver_linux:
>>>>>>>>>>> /usr/src/linux-headers-3.18.0-031800rc7/scripts/ver_linux: 20:
>>>>>>>>>>> /usr/src/linux-headers-3.18.0-031800rc7/scripts/ver_linux: ld: not
>>>>>>>>>>> found
>>>>>>>>>>> binutils
>>>>>>>>>>> util-linux 2.25.1
>>>>>>>>>>> mount debug
>>>>>>>>>>> module-init-tools 18
>>>>>>>>>>> e2fsprogs 1.42.10
>>>>>>>>>>> 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.23
>>>>>>>>>>> wireless-tools 30
>>>>>>>>>>> Modules Loaded snd_hda_codec_hdmi snd_hda_codec_realtek
>>>>>>>>>>> snd_hda_codec_generic ctr ccm joydev hp_wmi hid_rmi sparse_keymap
>>>>>>>>>>> rfcomm bnep arc4 rtl8723be btcoexist rtl8723_common intel_rapl
>>>>>>>>>>> uvcvideo rtl_pci intel_soc_dts_thermal intel_powerclamp
>>>>>>>>>>> videobuf2_vmalloc videobuf2_memops coretemp rtlwifi videobuf2_core
>>>>>>>>>>> v4l2_common videodev mac80211 media kvm cfg80211 btusb
>>>>>>>>>>> crct10dif_pclmul crc32_pclmul bluetooth ghash_clmulni_intel serio_raw
>>>>>>>>>>> cryptd wmi snd_hda_intel snd_hda_controller snd_hda_codec snd_hwdep
>>>>>>>>>>> snd_seq_midi snd_seq_midi_event snd_rawmidi snd_soc_rt5640
>>>>>>>>>>> snd_soc_rl6231 snd_soc_core snd_compress dw_dmac i915
>>>>>>>>>>> snd_pcm_dmaengine dw_dmac_core snd_seq int3400_thermal int3403_thermal
>>>>>>>>>>> acpi_thermal_rel nls_iso8859_1 snd_pcm i2c_hid video
>>>>>>>>>>> intel_smartconnect drm_kms_helper hid drm rfkill_gpio snd_seq_device
>>>>>>>>>>> i2c_designware_platform i2c_algo_bit snd_soc_sst_acpi 8250_dw
>>>>>>>>>>> snd_timer i2c_designware_core hp_wireless shpchp spi_pxa2xx_platform
>>>>>>>>>>> snd pwm_lpss_platform lpc_ich mac_hid mei_txe pwm_lpss iosf_mbi mei
>>>>>>>>>>> soundcore parport_pc ppdev lp parport uas usb_storage mmc_block
>>>>>>>>>>> sdhci_acpi sdhci
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> cat /proc/cpuinfo
>>>>>>>>>>> processor : 0
>>>>>>>>>>> vendor_id : GenuineIntel
>>>>>>>>>>> cpu family : 6
>>>>>>>>>>> model : 55
>>>>>>>>>>> model name : Intel(R) Celeron(R) CPU N2840 @ 2.16GHz
>>>>>>>>>>> stepping : 8
>>>>>>>>>>> microcode : 0x829
>>>>>>>>>>> cpu MHz : 499.741
>>>>>>>>>>> cache size : 1024 KB
>>>>>>>>>>> physical id : 0
>>>>>>>>>>> siblings : 2
>>>>>>>>>>> core id : 0
>>>>>>>>>>> cpu cores : 2
>>>>>>>>>>> apicid : 0
>>>>>>>>>>> initial apicid : 0
>>>>>>>>>>> fpu : yes
>>>>>>>>>>> fpu_exception : yes
>>>>>>>>>>> cpuid level : 11
>>>>>>>>>>> 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
>>>>>>>>>>> rdtscp lm constant_tsc arch_perfmon pebs bts rep_good nopl xtopology
>>>>>>>>>>> nonstop_tsc aperfmperf pni pclmulqdq dtes64 monitor ds_cpl vmx est tm2
>>>>>>>>>>> ssse3 cx16 xtpr pdcm sse4_1 sse4_2 movbe popcnt tsc_deadline_timer
>>>>>>>>>>> rdrand lahf_lm 3dnowprefetch ida arat epb dtherm tpr_shadow vnmi
>>>>>>>>>>> flexpriority ept vpid tsc_adjust smep erms
>>>>>>>>>>> bugs :
>>>>>>>>>>> bogomips : 4326.40
>>>>>>>>>>> clflush size : 64
>>>>>>>>>>> cache_alignment : 64
>>>>>>>>>>> address sizes : 36 bits physical, 48 bits virtual
>>>>>>>>>>> power management:
>>>>>>>>>>>
>>>>>>>>>>> processor : 1
>>>>>>>>>>> vendor_id : GenuineIntel
>>>>>>>>>>> cpu family : 6
>>>>>>>>>>> model : 55
>>>>>>>>>>> model name : Intel(R) Celeron(R) CPU N2840 @ 2.16GHz
>>>>>>>>>>> stepping : 8
>>>>>>>>>>> microcode : 0x829
>>>>>>>>>>> cpu MHz : 499.741
>>>>>>>>>>> cache size : 1024 KB
>>>>>>>>>>> physical id : 0
>>>>>>>>>>> siblings : 2
>>>>>>>>>>> core id : 1
>>>>>>>>>>> cpu cores : 2
>>>>>>>>>>> apicid : 2
>>>>>>>>>>> initial apicid : 2
>>>>>>>>>>> fpu : yes
>>>>>>>>>>> fpu_exception : yes
>>>>>>>>>>> cpuid level : 11
>>>>>>>>>>> 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
>>>>>>>>>>> rdtscp lm constant_tsc arch_perfmon pebs bts rep_good nopl xtopology
>>>>>>>>>>> nonstop_tsc aperfmperf pni pclmulqdq dtes64 monitor ds_cpl vmx est tm2
>>>>>>>>>>> ssse3 cx16 xtpr pdcm sse4_1 sse4_2 movbe popcnt tsc_deadline_timer
>>>>>>>>>>> rdrand lahf_lm 3dnowprefetch ida arat epb dtherm tpr_shadow vnmi
>>>>>>>>>>> flexpriority ept vpid tsc_adjust smep erms
>>>>>>>>>>> bugs :
>>>>>>>>>>> bogomips : 4326.40
>>>>>>>>>>> clflush size : 64
>>>>>>>>>>> cache_alignment : 64
>>>>>>>>>>> address sizes : 36 bits physical, 48 bits virtual
>>>>>>>>>>> power management:
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> cat /proc/modules
>>>>>>>>>>> snd_hda_codec_hdmi 52670 1 - Live 0x0000000000000000
>>>>>>>>>>> snd_hda_codec_realtek 80420 1 - Live 0x0000000000000000
>>>>>>>>>>> snd_hda_codec_generic 69995 1 snd_hda_codec_realtek, Live 0x0000000000000000
>>>>>>>>>>> ctr 13193 1 - Live 0x0000000000000000
>>>>>>>>>>> ccm 17856 1 - Live 0x0000000000000000
>>>>>>>>>>> joydev 17587 0 - Live 0x0000000000000000
>>>>>>>>>>> hp_wmi 14017 0 - Live 0x0000000000000000
>>>>>>>>>>> hid_rmi 18060 0 - Live 0x0000000000000000
>>>>>>>>>>> sparse_keymap 13890 1 hp_wmi, Live 0x0000000000000000
>>>>>>>>>>> rfcomm 75066 8 - Live 0x0000000000000000
>>>>>>>>>>> bnep 23980 2 - Live 0x0000000000000000
>>>>>>>>>>> arc4 12573 2 - Live 0x0000000000000000
>>>>>>>>>>> rtl8723be 96097 0 - Live 0x0000000000000000
>>>>>>>>>>> btcoexist 51822 1 rtl8723be, Live 0x0000000000000000
>>>>>>>>>>> rtl8723_common 23662 1 rtl8723be, Live 0x0000000000000000
>>>>>>>>>>> intel_rapl 19196 0 - Live 0x0000000000000000
>>>>>>>>>>> uvcvideo 86723 0 - Live 0x0000000000000000
>>>>>>>>>>> rtl_pci 27417 1 rtl8723be, Live 0x0000000000000000
>>>>>>>>>>> intel_soc_dts_thermal 13523 0 - Live 0x0000000000000000
>>>>>>>>>>> intel_powerclamp 19099 0 - Live 0x0000000000000000
>>>>>>>>>>> videobuf2_vmalloc 13216 1 uvcvideo, Live 0x0000000000000000
>>>>>>>>>>> videobuf2_memops 13362 1 videobuf2_vmalloc, Live 0x0000000000000000
>>>>>>>>>>> coretemp 13638 0 - Live 0x0000000000000000
>>>>>>>>>>> rtlwifi 74744 2 rtl8723be,rtl_pci, Live 0x0000000000000000
>>>>>>>>>>> videobuf2_core 51547 1 uvcvideo, Live 0x0000000000000000
>>>>>>>>>>> v4l2_common 15715 1 videobuf2_core, Live 0x0000000000000000
>>>>>>>>>>> videodev 163831 3 uvcvideo,videobuf2_core,v4l2_common, Live 0x0000000000000000
>>>>>>>>>>> mac80211 697159 3 rtl8723be,rtl_pci,rtlwifi, Live 0x0000000000000000
>>>>>>>>>>> media 22008 2 uvcvideo,videodev, Live 0x0000000000000000
>>>>>>>>>>> kvm 475237 0 - Live 0x0000000000000000
>>>>>>>>>>> cfg80211 520257 2 rtlwifi,mac80211, Live 0x0000000000000000
>>>>>>>>>>> btusb 32691 0 - Live 0x0000000000000000
>>>>>>>>>>> crct10dif_pclmul 14268 0 - Live 0x0000000000000000
>>>>>>>>>>> crc32_pclmul 13180 0 - Live 0x0000000000000000
>>>>>>>>>>> bluetooth 486890 22 rfcomm,bnep,btusb, Live 0x0000000000000000
>>>>>>>>>>> ghash_clmulni_intel 13230 0 - Live 0x0000000000000000
>>>>>>>>>>> serio_raw 13483 0 - Live 0x0000000000000000
>>>>>>>>>>> cryptd 20531 1 ghash_clmulni_intel, Live 0x0000000000000000
>>>>>>>>>>> wmi 19379 1 hp_wmi, Live 0x0000000000000000
>>>>>>>>>>> snd_hda_intel 30824 1 - Live 0x0000000000000000
>>>>>>>>>>> snd_hda_controller 32234 1 snd_hda_intel, Live 0x0000000000000000
>>>>>>>>>>> snd_hda_codec 144641 5
>>>>>>>>>>> snd_hda_codec_hdmi,snd_hda_codec_realtek,snd_hda_codec_generic,snd_hda_intel,snd_hda_controller,
>>>>>>>>>>> Live 0x0000000000000000
>>>>>>>>>>> snd_hwdep 17709 1 snd_hda_codec, 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_soc_rt5640 93325 0 - Live 0x0000000000000000
>>>>>>>>>>> snd_soc_rl6231 13037 1 snd_soc_rt5640, Live 0x0000000000000000
>>>>>>>>>>> snd_soc_core 207780 1 snd_soc_rt5640, Live 0x0000000000000000
>>>>>>>>>>> snd_compress 19395 1 snd_soc_core, Live 0x0000000000000000
>>>>>>>>>>> dw_dmac 12835 0 - Live 0x0000000000000000
>>>>>>>>>>> i915 1031996 2 - Live 0x0000000000000000
>>>>>>>>>>> snd_pcm_dmaengine 15229 1 snd_soc_core, Live 0x0000000000000000
>>>>>>>>>>> dw_dmac_core 28558 1 dw_dmac, Live 0x0000000000000000
>>>>>>>>>>> snd_seq 63540 2 snd_seq_midi,snd_seq_midi_event, Live 0x0000000000000000
>>>>>>>>>>> int3400_thermal 13040 0 - Live 0x0000000000000000
>>>>>>>>>>> int3403_thermal 13255 0 - Live 0x0000000000000000
>>>>>>>>>>> acpi_thermal_rel 13807 1 int3400_thermal, Live 0x0000000000000000
>>>>>>>>>>> nls_iso8859_1 12713 2 - Live 0x0000000000000000
>>>>>>>>>>> snd_pcm 106273 7
>>>>>>>>>>> snd_hda_codec_hdmi,snd_hda_intel,snd_hda_controller,snd_hda_codec,snd_soc_rt5640,snd_soc_core,snd_pcm_dmaengine,
>>>>>>>>>>> Live 0x0000000000000000
>>>>>>>>>>> i2c_hid 19065 0 - Live 0x0000000000000000
>>>>>>>>>>> video 20649 1 i915, Live 0x0000000000000000
>>>>>>>>>>> intel_smartconnect 12637 0 - Live 0x0000000000000000
>>>>>>>>>>> drm_kms_helper 99802 1 i915, Live 0x0000000000000000
>>>>>>>>>>> hid 110572 2 hid_rmi,i2c_hid, Live 0x0000000000000000
>>>>>>>>>>> drm 323675 4 i915,drm_kms_helper, Live 0x0000000000000000
>>>>>>>>>>> rfkill_gpio 12761 0 - Live 0x0000000000000000
>>>>>>>>>>> snd_seq_device 14497 3 snd_seq_midi,snd_rawmidi,snd_seq, Live 0x0000000000000000
>>>>>>>>>>> i2c_designware_platform 13025 0 - Live 0x0000000000000000
>>>>>>>>>>> i2c_algo_bit 13564 1 i915, Live 0x0000000000000000
>>>>>>>>>>> snd_soc_sst_acpi 13007 0 - Live 0x0000000000000000
>>>>>>>>>>> 8250_dw 13474 0 - Live 0x0000000000000000
>>>>>>>>>>> snd_timer 30118 2 snd_seq,snd_pcm, Live 0x0000000000000000
>>>>>>>>>>> i2c_designware_core 14990 1 i2c_designware_platform, Live 0x0000000000000000
>>>>>>>>>>> hp_wireless 12637 0 - Live 0x0000000000000000
>>>>>>>>>>> shpchp 37216 0 - Live 0x0000000000000000
>>>>>>>>>>> spi_pxa2xx_platform 23256 0 - Live 0x0000000000000000
>>>>>>>>>>> snd 84025 15 snd_hda_codec_hdmi,snd_hda_codec_realtek,snd_hda_codec_generic,snd_hda_intel,snd_hda_codec,snd_hwdep,snd_rawmidi,snd_soc_core,snd_compress,snd_seq,snd_pcm,snd_seq_device,snd_timer,
>>>>>>>>>>> Live 0x0000000000000000
>>>>>>>>>>> pwm_lpss_platform 12703 0 - Live 0x0000000000000000
>>>>>>>>>>> lpc_ich 21176 0 - Live 0x0000000000000000
>>>>>>>>>>> mac_hid 13275 0 - Live 0x0000000000000000
>>>>>>>>>>> mei_txe 19808 0 - Live 0x0000000000000000
>>>>>>>>>>> pwm_lpss 13281 1 pwm_lpss_platform, Live 0x0000000000000000
>>>>>>>>>>> iosf_mbi 13865 1 intel_soc_dts_thermal, Live 0x0000000000000000
>>>>>>>>>>> mei 88473 1 mei_txe, Live 0x0000000000000000
>>>>>>>>>>> soundcore 15091 2 snd_hda_codec,snd, Live 0x0000000000000000
>>>>>>>>>>> parport_pc 32909 0 - Live 0x0000000000000000
>>>>>>>>>>> ppdev 17711 0 - Live 0x0000000000000000
>>>>>>>>>>> lp 17799 0 - Live 0x0000000000000000
>>>>>>>>>>> parport 42481 3 parport_pc,ppdev,lp, Live 0x0000000000000000
>>>>>>>>>>> uas 22673 0 - Live 0x0000000000000000
>>>>>>>>>>> usb_storage 67010 2 uas, Live 0x0000000000000000
>>>>>>>>>>> mmc_block 36596 4 - Live 0x0000000000000000
>>>>>>>>>>> sdhci_acpi 13502 0 - Live 0x0000000000000000
>>>>>>>>>>> sdhci 43929 1 sdhci_acpi, Live 0x0000000000000000
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> /proc/ioports
>>>>>>>>>>> 0000-006f : PCI Bus 0000:00
>>>>>>>>>>> 0000-001f : dma1
>>>>>>>>>>> 0020-0021 : pic1
>>>>>>>>>>> 0040-0043 : timer0
>>>>>>>>>>> 0050-0053 : timer1
>>>>>>>>>>> 0060-0060 : keyboard
>>>>>>>>>>> 0062-0062 : PNP0C09:00
>>>>>>>>>>> 0062-0062 : EC data
>>>>>>>>>>> 0064-0064 : keyboard
>>>>>>>>>>> 0066-0066 : PNP0C09:00
>>>>>>>>>>> 0066-0066 : EC cmd
>>>>>>>>>>> 0070-0077 : rtc0
>>>>>>>>>>> 0078-0cf7 : PCI Bus 0000:00
>>>>>>>>>>> 0080-008f : dma page reg
>>>>>>>>>>> 00a0-00a1 : pic2
>>>>>>>>>>> 00c0-00df : dma2
>>>>>>>>>>> 00f0-00ff : fpu
>>>>>>>>>>> 03f8-03ff : serial
>>>>>>>>>>> 0400-047f : pnp 00:01
>>>>>>>>>>> 0400-0403 : ACPI PM1a_EVT_BLK
>>>>>>>>>>> 0404-0405 : ACPI PM1a_CNT_BLK
>>>>>>>>>>> 0408-040b : ACPI PM_TMR
>>>>>>>>>>> 0420-042f : ACPI GPE0_BLK
>>>>>>>>>>> 0430-0433 : iTCO_wdt
>>>>>>>>>>> 0450-0450 : ACPI PM2_CNT_BLK
>>>>>>>>>>> 0460-047f : iTCO_wdt
>>>>>>>>>>> 0500-05fe : pnp 00:01
>>>>>>>>>>> 0600-061f : pnp 00:01
>>>>>>>>>>> 0680-069f : pnp 00:01
>>>>>>>>>>> 0cf8-0cff : PCI conf1
>>>>>>>>>>> 0d00-ffff : PCI Bus 0000:00
>>>>>>>>>>> 1000-1fff : PCI Bus 0000:01
>>>>>>>>>>> 1000-10ff : 0000:01:00.0
>>>>>>>>>>> 1000-10ff : rtl_pci
>>>>>>>>>>> 2000-201f : 0000:00:1f.3
>>>>>>>>>>> 2050-2057 : 0000:00:02.0
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> cat /proc/iomem
>>>>>>>>>>> 00000000-00000fff : reserved
>>>>>>>>>>> 00001000-0006efff : System RAM
>>>>>>>>>>> 0006f000-0006ffff : ACPI Non-volatile Storage
>>>>>>>>>>> 00070000-00084fff : System RAM
>>>>>>>>>>> 00085000-00086fff : reserved
>>>>>>>>>>> 00087000-00087fff : System RAM
>>>>>>>>>>> 00088000-0009ffff : reserved
>>>>>>>>>>> 000a0000-000bffff : PCI Bus 0000:00
>>>>>>>>>>> 000c0000-000dffff : PCI Bus 0000:00
>>>>>>>>>>> 000e0000-000fffff : PCI Bus 0000:00
>>>>>>>>>>> 000f0000-000fffff : System ROM
>>>>>>>>>>> 00100000-1effffff : System RAM
>>>>>>>>>>> 02000000-027b8537 : Kernel code
>>>>>>>>>>> 027b8538-02d2123f : Kernel data
>>>>>>>>>>> 02e87000-02fcffff : Kernel bss
>>>>>>>>>>> 1f000000-1f0fffff : reserved
>>>>>>>>>>> 1f100000-1fffffff : System RAM
>>>>>>>>>>> 20000000-200fffff : reserved
>>>>>>>>>>> 20100000-75867fff : System RAM
>>>>>>>>>>> 75868000-75892fff : reserved
>>>>>>>>>>> 75893000-78892fff : System RAM
>>>>>>>>>>> 78893000-78922fff : reserved
>>>>>>>>>>> 78923000-791a3fff : reserved
>>>>>>>>>>> 791a4000-792a2fff : ACPI Non-volatile Storage
>>>>>>>>>>> 792a3000-792e2fff : ACPI Tables
>>>>>>>>>>> 792e3000-79ffffff : System RAM
>>>>>>>>>>> 7a000000-7affffff : RAM buffer
>>>>>>>>>>> 7b000000-7effffff : reserved
>>>>>>>>>>> 7b000000-7effffff : Graphics Stolen Memory
>>>>>>>>>>> 80000000-907ffffe : PCI Bus 0000:00
>>>>>>>>>>> 80000000-8fffffff : 0000:00:02.0
>>>>>>>>>>> 90000000-903fffff : 0000:00:02.0
>>>>>>>>>>> 90400000-904fffff : PCI Bus 0000:01
>>>>>>>>>>> 90400000-90403fff : 0000:01:00.0
>>>>>>>>>>> 90400000-90403fff : rtl_pci
>>>>>>>>>>> 90500000-905fffff : 0000:00:1a.0
>>>>>>>>>>> 90500000-905fffff : mei_txe
>>>>>>>>>>> 90600000-906fffff : 0000:00:1a.0
>>>>>>>>>>> 90600000-906fffff : mei_txe
>>>>>>>>>>> 90700000-9070ffff : 0000:00:14.0
>>>>>>>>>>> 90700000-9070ffff : xhci-hcd
>>>>>>>>>>> 90710000-90713fff : 0000:00:1b.0
>>>>>>>>>>> 90710000-90713fff : ICH HD audio
>>>>>>>>>>> 90718000-9071801f : 0000:00:1f.3
>>>>>>>>>>> 90800000-90800fff : 80860F14:01
>>>>>>>>>>> 90800000-90800fff : 80860F14:01
>>>>>>>>>>> 90803000-90803fff : 80860F41:00
>>>>>>>>>>> 90803000-90803fff : 80860F41:00
>>>>>>>>>>> 90804000-90807fff : INTL9C60:01
>>>>>>>>>>> 90804000-90807fff : INTL9C60:01
>>>>>>>>>>> 90c00000-90ffffff : PCI Bus 0000:00
>>>>>>>>>>> e0000000-e3ffffff : PCI MMCONFIG 0000 [bus 00-3f]
>>>>>>>>>>> e00000d0-e00000db : INT33BD:00
>>>>>>>>>>> e00f8000-e00f8fff : reserved
>>>>>>>>>>> fec00000-fec003ff : IOAPIC 0
>>>>>>>>>>> fed00000-fed003ff : HPET 0
>>>>>>>>>>> fed00000-fed003ff : PNP0103:00
>>>>>>>>>>> fed01000-fed01fff : reserved
>>>>>>>>>>> fed01000-fed01fff : pnp 00:03
>>>>>>>>>>> fed03000-fed03fff : pnp 00:03
>>>>>>>>>>> fed03008-fed0300c : iTCO_wdt
>>>>>>>>>>> fed04000-fed04fff : pnp 00:03
>>>>>>>>>>> fed05000-fed057ff : INT3401:00
>>>>>>>>>>> fed08000-fed08fff : pnp 00:03
>>>>>>>>>>> fed0c000-fed0cfff : INT33FC:00
>>>>>>>>>>> fed0c000-fed0cfff : INT33FC:00
>>>>>>>>>>> fed0d000-fed0dfff : INT33FC:01
>>>>>>>>>>> fed0d000-fed0dfff : INT33FC:01
>>>>>>>>>>> fed0e000-fed0efff : INT33FC:02
>>>>>>>>>>> fed0e000-fed0efff : INT33FC:02
>>>>>>>>>>> fed1c000-fed1cfff : pnp 00:03
>>>>>>>>>>> fed40000-fed44fff : pnp 00:01
>>>>>>>>>>> fee00000-feefffff : pnp 00:03
>>>>>>>>>>> fee00000-fee00fff : Local APIC
>>>>>>>>>>> fef00000-feffffff : pnp 00:03
>>>>>>>>>>> ff000000-ffffffff : INT0800:00
>>>>>>>>>>> ffb80000-ffffffff : reserved
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> sudo lspci -vvv
>>>>>>>>>>> 00:00.0 Host bridge: Intel Corporation Atom Processor Z36xxx/Z37xxx
>>>>>>>>>>> Series SoC Transaction Register (rev 0e)
>>>>>>>>>>> Subsystem: Hewlett-Packard Company Device 8023
>>>>>>>>>>> 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
>>>>>>>>>>> Kernel driver in use: iosf_mbi_pci
>>>>>>>>>>>
>>>>>>>>>>> 00:02.0 VGA compatible controller: Intel Corporation Atom Processor
>>>>>>>>>>> Z36xxx/Z37xxx Series Graphics & Display (rev 0e) (prog-if 00 [VGA
>>>>>>>>>>> controller])
>>>>>>>>>>> Subsystem: Hewlett-Packard Company Device 8023
>>>>>>>>>>> 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 263
>>>>>>>>>>> Region 0: Memory at 90000000 (32-bit, non-prefetchable) [size=4M]
>>>>>>>>>>> Region 2: Memory at 80000000 (32-bit, prefetchable) [size=256M]
>>>>>>>>>>> Region 4: I/O ports at 2050 [size=8]
>>>>>>>>>>> Expansion ROM at <unassigned> [disabled]
>>>>>>>>>>> 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: [90] MSI: Enable+ Count=1/1 Maskable- 64bit-
>>>>>>>>>>> Address: fee0300c Data: 4162
>>>>>>>>>>> Capabilities: [b0] Vendor Specific Information: Len=07 <?>
>>>>>>>>>>> Kernel driver in use: i915
>>>>>>>>>>>
>>>>>>>>>>> 00:14.0 USB controller: Intel Corporation Atom Processor Z36xxx/Z37xxx
>>>>>>>>>>> Series USB xHCI (rev 0e) (prog-if 30 [XHCI])
>>>>>>>>>>> Subsystem: Hewlett-Packard Company Device 8023
>>>>>>>>>>> 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 261
>>>>>>>>>>> Region 0: Memory at 90700000 (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: 00000000fee0300c Data: 41d1
>>>>>>>>>>> Kernel driver in use: xhci_hcd
>>>>>>>>>>>
>>>>>>>>>>> 00:1a.0 Encryption controller: Intel Corporation Atom Processor
>>>>>>>>>>> Z36xxx/Z37xxx Series Trusted Execution Engine (rev 0e)
>>>>>>>>>>> Subsystem: Hewlett-Packard Company Device 8023
>>>>>>>>>>> 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 262
>>>>>>>>>>> Region 0: Memory at 90600000 (32-bit, non-prefetchable) [size=1M]
>>>>>>>>>>> Region 1: Memory at 90500000 (32-bit, non-prefetchable) [size=1M]
>>>>>>>>>>> Capabilities: [80] 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: [a0] MSI: Enable+ Count=1/1 Maskable- 64bit-
>>>>>>>>>>> Address: fee0300c Data: 4122
>>>>>>>>>>> Kernel driver in use: mei_txe
>>>>>>>>>>>
>>>>>>>>>>> 00:1b.0 Audio device: Intel Corporation Atom Processor Z36xxx/Z37xxx
>>>>>>>>>>> Series High Definition Audio Controller (rev 0e)
>>>>>>>>>>> Subsystem: Hewlett-Packard Company Device 8023
>>>>>>>>>>> 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 264
>>>>>>>>>>> Region 0: Memory at 90710000 (64-bit, non-prefetchable) [size=16K]
>>>>>>>>>>> Capabilities: [50] Power Management version 2
>>>>>>>>>>> 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: 00000000fee0300c Data: 4182
>>>>>>>>>>> Kernel driver in use: snd_hda_intel
>>>>>>>>>>>
>>>>>>>>>>> 00:1c.0 PCI bridge: Intel Corporation Device 0f48 (rev 0e) (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: 00001000-00001fff
>>>>>>>>>>> Memory behind bridge: 90400000-904fffff
>>>>>>>>>>> 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 #1, Speed 5GT/s, Width x1, ASPM L0s L1, Exit Latency L0s
>>>>>>>>>>> <512ns, L1 <4us
>>>>>>>>>>> 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 #0, 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 BC, 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: 00000000 Data: 0000
>>>>>>>>>>> Capabilities: [90] Subsystem: Hewlett-Packard Company Device 8023
>>>>>>>>>>> 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:1f.0 ISA bridge: Intel Corporation Atom Processor Z36xxx/Z37xxx
>>>>>>>>>>> Series Power Control Unit (rev 0e)
>>>>>>>>>>> Subsystem: Hewlett-Packard Company Device 8023
>>>>>>>>>>> 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.3 SMBus: Intel Corporation Device 0f12 (rev 0e)
>>>>>>>>>>> Subsystem: Hewlett-Packard Company Device 8023
>>>>>>>>>>> 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 B routed to IRQ 255
>>>>>>>>>>> Region 0: Memory at 90718000 (32-bit, non-prefetchable) [size=32]
>>>>>>>>>>> Region 4: I/O ports at 2000 [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-
>>>>>>>>>>>
>>>>>>>>>>> 01:00.0 Network controller: Realtek Semiconductor Co., Ltd. RTL8723BE
>>>>>>>>>>> PCIe Wireless Network Adapter
>>>>>>>>>>> Subsystem: Hewlett-Packard Company Device 2231
>>>>>>>>>>> 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 16
>>>>>>>>>>> Region 0: I/O ports at 1000 [size=256]
>>>>>>>>>>> Region 2: Memory at 90400000 (64-bit, non-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: 0000000000000000 Data: 0000
>>>>>>>>>>> Capabilities: [70] Express (v2) Endpoint, MSI 00
>>>>>>>>>>> DevCap: MaxPayload 128 bytes, PhantFunc 0, Latency L0s <4us, 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 2.5GT/s, Width x1, ASPM L0s L1, Exit Latency
>>>>>>>>>>> L0s <512ns, 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-
>>>>>>>>>>> DevCap2: Completion Timeout: Not Supported, 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: [100 v2] 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: 0d, GenCap+ CGenEn- ChkCap+ ChkEn-
>>>>>>>>>>> Capabilities: [140 v1] Device Serial Number 00-23-b7-fe-ff-4c-e0-00
>>>>>>>>>>> Capabilities: [150 v1] Latency Tolerance Reporting
>>>>>>>>>>> Max snoop latency: 71680ns
>>>>>>>>>>> Max no snoop latency: 71680ns
>>>>>>>>>>> Capabilities: [158 v1] L1 PM Substates
>>>>>>>>>>> L1SubCap: PCI-PM_L1.2+ PCI-PM_L1.1+ ASPM_L1.2+ ASPM_L1.1+ L1_PM_Substates+
>>>>>>>>>>> PortCommonModeRestoreTime=150us PortTPowerOnTime=150us
>>>>>>>>>>> Kernel driver in use: rtl8723be
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> cat /proc/scsi/scsi
>>>>>>>>>>> Attached devices:
>>>>>>>>>>> Host: scsi0 Channel: 00 Id: 00 Lun: 00
>>>>>>>>>>> Vendor: Generic- Model: SD/MMC/MS PRO Rev: 1.00
>>>>>>>>>>> Type: Direct-Access ANSI SCSI revision: 04
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> ls /proc
>>>>>>>>>>> 1 12 14 1667 1745 18 1963 2345 292 35 470 55
>>>>>>>>>>> 7201 asound execdomains kmsg pagetypeinfo sysvipc
>>>>>>>>>>> 10 1218 1410 1685 1761 1804 2 2388 296 3573 471 554
>>>>>>>>>>> 728 buddyinfo fb kpagecount partitions thread-self
>>>>>>>>>>> 1020 125 142 1687 1764 1805 20 24 3 359 473 56
>>>>>>>>>>> 755 bus filesystems kpageflags sched_debug timer_list
>>>>>>>>>>> 1025 126 1420 1690 1767 1818 21 25 30 3623 474 57
>>>>>>>>>>> 76 cgroups fs loadavg schedstat timer_stats
>>>>>>>>>>> 1032 127 1423 17 1769 1828 2169 2528 31 378 485 585
>>>>>>>>>>> 77 cmdline interrupts locks scsi tty
>>>>>>>>>>> 1033 128 143 1701 1771 1853 2187 254 3181 3822 5 606
>>>>>>>>>>> 7886 consoles iomem mdstat self uptime
>>>>>>>>>>> 1038 129 1444 1710 1772 1876 2197 26 33 39 509 654
>>>>>>>>>>> 8 cpuinfo ioports meminfo slabinfo version
>>>>>>>>>>> 1042 13 1485 1718 1781 1883 2198 2670 3309 3932 516 655
>>>>>>>>>>> 8743 crypto irq misc softirqs vmallocinfo
>>>>>>>>>>> 1069 130 15 1722 1787 1893 22 2672 34 40 53 695
>>>>>>>>>>> 9 devices kallsyms modules stat vmstat
>>>>>>>>>>> 1070 131 1568 1725 1789 1896 2202 27 3419 41 539 7
>>>>>>>>>>> 9040 diskstats kcore mounts swaps zoneinfo
>>>>>>>>>>> 11 132 1645 1727 1792 19 2248 28 3433 468 542 709
>>>>>>>>>>> 9056 dma keys mtrr sys
>>>>>>>>>>> 1144 1331 1655 1732 1796 1905 23 29 3437 469 5421 715
>>>>>>>>>>> acpi driver key-users net sysrq-trigger
>>>>>>>>>>> --
>>>>>>>>>>> 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: [PATCHv3 0/5] ARM:sunxi:ps2 Added support for A10/A20 ps2 controller.
From: Hans de Goede @ 2014-12-15 15:13 UTC (permalink / raw)
To: Vishnu Patekar
Cc: linux-input@vger.kernel.org, maxime.ripard@free-electrons.com,
Dmitry Torokhov, devicetree@vger.kernel.org,
linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org, robh+dt@kernel.org,
pawel.moll@arm.com, mark.rutland@arm.com,
ijc+devicetree@hellion.org.uk, Kumar Gala, linux@arm.linux.org.uk,
Grant Likely, benh@kernel.crashing.org, msalter@redhat.com,
ralf@linux-mips.org, jdelvare@suse.de
In-Reply-To: <CAEzqOZsWSpd_r3Oc=PBVw3NQH-_1V9JXtC2H4tZ3U6nCN_Z7aA@mail.gmail.com>
Hi,
On 15-12-14 15:13, Vishnu Patekar wrote:
> Hi,
>
> On Sun, Dec 14, 2014 at 2:31 PM, Hans de Goede <hdegoede@redhat.com> wrote:
>> Hi,
>>
>> On 13-12-14 21:01, Vishnu Patekar wrote:
>>>
>>> Hello Hans,
>>> Please find my comments inlined.
>>>
>>> On 12/13/14, Hans de Goede <hdegoede@redhat.com> wrote:
>>>>
>>>> Hi VishnuPatekar,
>>>>
>>>> The patch mangling for this set seems to have gone a bit wrong I'm afraid
>>>
>>>
>>> No, this time I've corrected it. Infact, last version of patch did not
>>> used the status bit error macros.
>>>
>>>> a lot of the patches have my fixup commit messages (which should have
>>>> disappeared when squashing in the patches), please replace those by
>>>> proper
>>>> commit messages describing what the patch actually does.
>>>
>>> Yes, [PATCHv3 3/5] uses fixup. I'll correct it.
>>>>
>>>>
>>>> Also the adding of the commented nodes for the lime2 seems to be gone
>>>> entirely
>>>> from the set, instead now only a comment about the conflict with the hdmi
>>>> pins is added, but it is above the i2c node instead of above a ps2 node.
>>>>
>>> Maxime's suggested that we should not add commented nodes specially
>>> when its trivial to apply. And just note saying ps20 pins conflict
>>> with HDMI.
>>
>>
>> Ah, I see.
>>
>>> Should I remove the this comment as well?
>>> Or
>>> Put this note in start of DTS file?
>>
>>
>> The comment should be added to where the pinctrl bits are, not to the lime2
>> file, ps0 will conflict with hdmi on all boards.
>
> Well, In that case,PS2_0 pins conflicts with HDMI, PS2_1 pins
> conflicts with LCD. Every pin has multiplexing.
Almost every A10 board has a hdmi connector, and only the hdmi ddc pins
are multiplexed, so this is sort of special, but yes if we do not have
the commented nodes in the dts file, then this comment can be dropped too
I guess.
Regards,
Hans
^ permalink raw reply
* Re: [PATCH v15 12/12] input: cyapa: add acpi device id supported
From: Jeremiah Mahler @ 2014-12-15 14:14 UTC (permalink / raw)
To: Dudley Du; +Cc: dmitry.torokhov, rydberg, bleung, linux-input, linux-kernel
In-Reply-To: <1418624603-19054-13-git-send-email-dudley.dulixin@gmail.com>
Dudley,
On Mon, Dec 15, 2014 at 02:23:23PM +0800, Dudley Du wrote:
> Add acpi device tree supported.
support.
> acpi device id "CYAP0000" is for old gen3 trackpad devices.
> acpi device id "CYAP0001" is for new gen5 trackpad devices.
> TEST=test on Chromebooks.
>
> Signed-off-by: Dudley Du <dudley.dulixin@gmail.com>
> ---
> drivers/input/mouse/cyapa.c | 13 +++++++++++++
> 1 file changed, 13 insertions(+)
>
> diff --git a/drivers/input/mouse/cyapa.c b/drivers/input/mouse/cyapa.c
> index dac3996..9fb97e2 100644
> --- a/drivers/input/mouse/cyapa.c
> +++ b/drivers/input/mouse/cyapa.c
> @@ -24,6 +24,7 @@
> #include <linux/slab.h>
> #include <linux/uaccess.h>
> #include <linux/pm_runtime.h>
> +#include <linux/acpi.h>
> #include "cyapa.h"
>
>
> @@ -1315,11 +1316,23 @@ static const struct i2c_device_id cyapa_id_table[] = {
> };
> MODULE_DEVICE_TABLE(i2c, cyapa_id_table);
>
> +#ifdef CONFIG_ACPI
> +static const struct acpi_device_id cyapa_acpi_id[] = {
> + { "CYAP0000", 0 }, /* Gen3 trackpad with 0x67 I2C address. */
> + { "CYAP0001", 0 }, /* Gen5 trackpad with 0x24 I2C address. */
> + { }
> +};
> +MODULE_DEVICE_TABLE(acpi, cyapa_acpi_id);
> +#endif
> +
> static struct i2c_driver cyapa_driver = {
> .driver = {
> .name = "cyapa",
> .owner = THIS_MODULE,
> .pm = &cyapa_pm_ops,
> +#ifdef CONFIG_ACPI
> + .acpi_match_table = ACPI_PTR(cyapa_acpi_id),
> +#endif
> },
>
> .probe = cyapa_probe,
> --
> 1.9.1
>
> --
> 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
--
- Jeremiah Mahler
^ permalink raw reply
* Re: [PATCH v15 10/12] input: cyapa: add gen5 trackpad device read baseline function support
From: Jeremiah Mahler @ 2014-12-15 14:13 UTC (permalink / raw)
To: Dudley Du; +Cc: dmitry.torokhov, rydberg, bleung, linux-input, linux-kernel
In-Reply-To: <1418624603-19054-11-git-send-email-dudley.dulixin@gmail.com>
Dudley,
On Mon, Dec 15, 2014 at 02:23:21PM +0800, Dudley Du wrote:
> Add read baseline function supported for gen5 trackpad device,
> it can be used through sysfs baseline interface.
> TEST=test on Chromebooks.
>
> Signed-off-by: Dudley Du <dudley.dulixin@gmail.com>
> ---
> drivers/input/mouse/cyapa.h | 2 +
> drivers/input/mouse/cyapa_gen5.c | 621 +++++++++++++++++++++++++++++++++++++++
> 2 files changed, 623 insertions(+)
>
> diff --git a/drivers/input/mouse/cyapa.h b/drivers/input/mouse/cyapa.h
> index bf0bbd9..4f1fc89 100644
> --- a/drivers/input/mouse/cyapa.h
> +++ b/drivers/input/mouse/cyapa.h
> @@ -285,6 +285,8 @@ struct cyapa {
> u8 y_origin; /* Y Axis Origin: 0 = top; 1 = bottom. */
> int electrodes_x; /* Number of electrodes on the X Axis*/
> int electrodes_y; /* Number of electrodes on the Y Axis*/
> + int electrodes_rx; /* Number of Rx electrodes */
> + int algined_electrodes_rx; /* 4 aligned */
aligned
> int max_z;
>
> /*
> diff --git a/drivers/input/mouse/cyapa_gen5.c b/drivers/input/mouse/cyapa_gen5.c
> index e89a952..3c87ad4 100644
> --- a/drivers/input/mouse/cyapa_gen5.c
> +++ b/drivers/input/mouse/cyapa_gen5.c
> @@ -1533,6 +1533,625 @@ static int cyapa_gen5_set_power_mode(struct cyapa *cyapa,
> return 0;
> }
>
> +static int cyapa_gen5_resume_scanning(struct cyapa *cyapa)
> +{
> + u8 cmd[7] = { 0x04, 0x00, 0x05, 0x00, 0x2f, 0x00, 0x04 };
> + u8 resp_data[6];
> + int resp_len;
> + int error;
> +
> + /* Try to dump all buffered data before doing command. */
> + cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
> +
> + resp_len = 6;
> + error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
> + cmd, 7,
> + resp_data, &resp_len,
> + 500, cyapa_gen5_sort_tsg_pip_app_resp_data, true);
> + if (error || !VALID_CMD_RESP_HEADER(resp_data, 0x04))
> + return -EINVAL;
> +
> + /* Try to dump all buffered data when resuming scanning. */
> + cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
> +
> + return 0;
> +}
> +
> +static int cyapa_gen5_suspend_scanning(struct cyapa *cyapa)
> +{
> + u8 cmd[7] = { 0x04, 0x00, 0x05, 0x00, 0x2f, 0x00, 0x03 };
> + u8 resp_data[6];
> + int resp_len;
> + int error;
> +
> + /* Try to dump all buffered data before doing command. */
> + cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
> +
> + resp_len = 6;
> + error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
> + cmd, 7,
> + resp_data, &resp_len,
> + 500, cyapa_gen5_sort_tsg_pip_app_resp_data, true);
> + if (error || !VALID_CMD_RESP_HEADER(resp_data, 0x03))
> + return -EINVAL;
> +
> + /* Try to dump all buffered data when suspending scanning. */
> + cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
> +
> + return 0;
> +}
> +
> +static s32 two_complement_to_s32(s32 value, int num_bits)
twos_* might be a better prefix since it is "Two's compliment".
> +{
> + if (value >> (num_bits - 1))
> + value |= -1 << num_bits;
> + return value;
> +}
> +
> +static s32 cyapa_parse_structure_data(u8 data_format, u8 *buf, int buf_len)
> +{
> + int data_size;
> + bool big_endian;
> + bool unsigned_type;
> + s32 value;
> +
> + data_size = (data_format & 0x07);
> + big_endian = ((data_format & 0x10) == 0x00);
> + unsigned_type = ((data_format & 0x20) == 0x00);
> +
> + if (buf_len < data_size)
> + return 0;
> +
> + switch (data_size) {
> + case 1:
> + value = buf[0];
> + break;
> + case 2:
> + if (big_endian)
> + value = get_unaligned_be16(buf);
> + else
> + value = get_unaligned_le16(buf);
> + break;
> + case 4:
> + if (big_endian)
> + value = get_unaligned_be32(buf);
> + else
> + value = get_unaligned_le32(buf);
> + break;
> + default:
> + /* Should not happen, just as default case here. */
> + value = 0;
> + break;
> + }
> +
> + if (!unsigned_type)
> + value = two_complement_to_s32(value, data_size * 8);
> +
> + return value;
> +}
> +
> +
> +/*
> + * Read all the global mutual or self idac data or mutual or self local PWC
> + * data based on the @idac_data_type.
> + * If the input value of @data_size is 0, then means read global mutual or
> + * self idac data. For read global mutual idac data, @idac_max, @idac_min and
> + * @idac_ave are in order used to return the max value of global mutual idac
> + * data, the min value of global mutual idac and the average value of the
> + * global mutual idac data. For read global self idac data, @idac_max is used
> + * to return the global self cap idac data in Rx direction, @idac_min is used
> + * to return the global self cap idac data in Tx direction. @idac_ave is not
> + * used.
> + * If the input value of @data_size is not 0, than means read the mutual or
> + * self local PWC data. The @idac_max, @idac_min and @idac_ave are used to
> + * return the max, min and average value of the mutual or self local PWC data.
> + * Note, in order to raed mutual local PWC data, must read invoke this function
> + * to read the mutual global idac data firstly to set the correct Rx number
> + * value, otherwise, the read mutual idac and PWC data may not correct.
> + */
> +static int cyapa_gen5_read_idac_data(struct cyapa *cyapa,
> + u8 cmd_code, u8 idac_data_type, int *data_size,
> + int *idac_max, int *idac_min, int *idac_ave)
> +{
> + int i;
> + u8 cmd[12];
> + u8 resp_data[256];
> + int resp_len;
> + int read_len;
> + int value;
> + u16 offset;
> + int read_elements;
> + bool read_global_idac;
> + int sum, count, max_element_cnt;
> + int tmp_max, tmp_min, tmp_ave, tmp_sum, tmp_count;
> + int electrodes_rx, electrodes_tx;
> + int error;
> +
> + if (cmd_code != GEN5_CMD_RETRIEVE_DATA_STRUCTURE ||
> + (idac_data_type != GEN5_RETRIEVE_MUTUAL_PWC_DATA &&
> + idac_data_type != GEN5_RETRIEVE_SELF_CAP_PWC_DATA) ||
> + !data_size || !idac_max || !idac_min || !idac_ave)
> + return -EINVAL;
> +
> + *idac_max = INT_MIN;
> + *idac_min = INT_MAX;
> + sum = count = tmp_count = 0;
> + electrodes_rx = electrodes_tx = 0;
> + if (*data_size == 0) {
> + /*
> + * Read global idac values firstly.
> + * Currently, no idac data exceed 4 bytes.
> + */
> + read_global_idac = true;
> + offset = 0;
> + *data_size = 4;
> + tmp_max = INT_MIN;
> + tmp_min = INT_MAX;
> + tmp_ave = tmp_sum = tmp_count = 0;
> +
> + if (idac_data_type == GEN5_RETRIEVE_MUTUAL_PWC_DATA) {
> + if (cyapa->algined_electrodes_rx == 0) {
s/algined/aligned/
> + if (cyapa->electrodes_rx != 0) {
> + electrodes_rx = cyapa->electrodes_rx;
> + electrodes_tx = (cyapa->electrodes_x ==
> + electrodes_rx) ?
> + cyapa->electrodes_y :
> + cyapa->electrodes_x;
> + } else {
> + electrodes_tx = min(cyapa->electrodes_x,
> + cyapa->electrodes_y);
> + electrodes_rx = max(cyapa->electrodes_x,
> + cyapa->electrodes_y);
> + }
> + cyapa->algined_electrodes_rx =
> + (electrodes_rx + 3) & ~3u;
The right margin is really cramped, maybe it is time for a new function?
> + }
> + max_element_cnt =
> + (cyapa->algined_electrodes_rx + 7) & ~7u;
> + } else {
> + max_element_cnt = 2;
> + }
> + } else {
> + read_global_idac = false;
> + if (*data_size > 4)
> + *data_size = 4;
> + /* Calculate the start offset in bytes of local PWC data. */
> + if (idac_data_type == GEN5_RETRIEVE_MUTUAL_PWC_DATA) {
> + offset = cyapa->algined_electrodes_rx * (*data_size);
> + electrodes_tx =
> + (cyapa->electrodes_rx == cyapa->electrodes_x) ?
> + cyapa->electrodes_y : cyapa->electrodes_x;
> + max_element_cnt = ((cyapa->algined_electrodes_rx + 7) &
> + ~7u) * electrodes_tx;
> + } else if (idac_data_type == GEN5_RETRIEVE_SELF_CAP_PWC_DATA) {
> + offset = 2;
> + max_element_cnt = cyapa->electrodes_x +
> + cyapa->electrodes_y;
> + max_element_cnt = (max_element_cnt + 3) & ~3u;
> + }
> + }
> +
> + do {
> + read_elements = (256 - 10) / (*data_size);
> + read_elements = min(read_elements, max_element_cnt - count);
> + read_len = read_elements * (*data_size);
> +
> + cmd[0] = 0x04;
> + cmd[1] = 0x00;
> + cmd[2] = 0x0a;
> + cmd[3] = 0x00;
> + cmd[4] = GEN5_APP_CMD_REPORT_ID;
> + cmd[5] = 0x00;
> + cmd[6] = cmd_code;
> + put_unaligned_le16(offset, &cmd[7]); /* Read Offset[15:0] */
> + put_unaligned_le16(read_len, &cmd[9]); /* Read Length[15:0] */
> + cmd[11] = idac_data_type;
> + resp_len = 10 + read_len;
> + error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
> + cmd, 12,
> + resp_data, &resp_len,
> + 500, cyapa_gen5_sort_tsg_pip_app_resp_data,
> + true);
> + if (error || resp_len < 10 ||
> + !VALID_CMD_RESP_HEADER(resp_data, cmd_code) ||
> + !GEN5_CMD_COMPLETE_SUCCESS(resp_data[5]) ||
> + resp_data[6] != idac_data_type)
> + return (error < 0) ? error : -EAGAIN;
> + read_len = get_unaligned_le16(&resp_data[7]);
> + if (read_len == 0)
> + break;
> +
> + *data_size = (resp_data[9] & GEN5_PWC_DATA_ELEMENT_SIZE_MASK);
> + if (read_len < *data_size)
> + return -EINVAL;
> +
> + if (read_global_idac &&
> + idac_data_type == GEN5_RETRIEVE_SELF_CAP_PWC_DATA) {
> + /* Rx's self global idac data. */
> + *idac_max = cyapa_parse_structure_data(
> + resp_data[9], &resp_data[10],
> + *data_size);
> + /* Tx's self global idac data. */
> + *idac_min = cyapa_parse_structure_data(
> + resp_data[9],
> + &resp_data[10 + *data_size],
> + *data_size);
> + break;
> + }
> +
> + /* Read mutual global idac or local mutual/self PWC data. */
> + offset += read_len;
> + for (i = 10; i < (read_len + 10); i += *data_size) {
> + value = cyapa_parse_structure_data(resp_data[9],
> + &resp_data[i], *data_size);
> + *idac_min = min(value, *idac_min);
> + *idac_max = max(value, *idac_max);
> +
> + if (idac_data_type == GEN5_RETRIEVE_MUTUAL_PWC_DATA &&
> + tmp_count < cyapa->algined_electrodes_rx &&
> + read_global_idac) {
> + /*
> + * The value gap betwen global and local mutual
> + * idac data must bigger than 50%.
> + * Normally, global value bigger than 50,
> + * local values less than 10.
> + */
> + if (!tmp_ave || value > tmp_ave / 2) {
> + tmp_min = min(value, tmp_min);
> + tmp_max = max(value, tmp_max);
> + tmp_sum += value;
> + tmp_count++;
> +
> + tmp_ave = tmp_sum / tmp_count;
> + }
> + }
> +
> + sum += value;
> + count++;
> +
> + if (count >= max_element_cnt)
> + goto out;
> + }
> + } while (true);
> +
> +out:
> + *idac_ave = count ? (sum / count) : 0;
> +
> + if (read_global_idac &&
> + idac_data_type == GEN5_RETRIEVE_MUTUAL_PWC_DATA) {
> + if (tmp_count == 0)
> + return 0;
> +
> + if (tmp_count == cyapa->algined_electrodes_rx) {
> + cyapa->electrodes_rx = cyapa->electrodes_rx ?
> + cyapa->electrodes_rx : electrodes_rx;
> + } else if (tmp_count == electrodes_rx) {
> + cyapa->electrodes_rx = cyapa->electrodes_rx ?
> + cyapa->electrodes_rx : electrodes_rx;
> + cyapa->algined_electrodes_rx = electrodes_rx;
> + } else {
> + cyapa->electrodes_rx = cyapa->electrodes_rx ?
> + cyapa->electrodes_rx : electrodes_tx;
> + cyapa->algined_electrodes_rx = tmp_count;
> + }
> +
> + *idac_min = tmp_min;
> + *idac_max = tmp_max;
> + *idac_ave = tmp_ave;
> + }
> +
> + return 0;
> +}
> +
> +static int cyapa_gen5_read_mutual_idac_data(struct cyapa *cyapa,
> + int *gidac_mutual_max, int *gidac_mutual_min, int *gidac_mutual_ave,
> + int *lidac_mutual_max, int *lidac_mutual_min, int *lidac_mutual_ave)
> +{
> + int error;
> + int data_size;
> +
> + *gidac_mutual_max = *gidac_mutual_min = *gidac_mutual_ave = 0;
> + *lidac_mutual_max = *lidac_mutual_min = *lidac_mutual_ave = 0;
> +
> + data_size = 0;
> + error = cyapa_gen5_read_idac_data(cyapa,
> + GEN5_CMD_RETRIEVE_DATA_STRUCTURE,
> + GEN5_RETRIEVE_MUTUAL_PWC_DATA,
> + &data_size,
> + gidac_mutual_max, gidac_mutual_min, gidac_mutual_ave);
> + if (error)
> + return error;
> +
> + error = cyapa_gen5_read_idac_data(cyapa,
> + GEN5_CMD_RETRIEVE_DATA_STRUCTURE,
> + GEN5_RETRIEVE_MUTUAL_PWC_DATA,
> + &data_size,
> + lidac_mutual_max, lidac_mutual_min, lidac_mutual_ave);
> + return error;
> +}
> +
> +static int cyapa_gen5_read_self_idac_data(struct cyapa *cyapa,
> + int *gidac_self_rx, int *gidac_self_tx,
> + int *lidac_self_max, int *lidac_self_min, int *lidac_self_ave)
> +{
> + int error;
> + int data_size;
> +
> + *gidac_self_rx = *gidac_self_tx = 0;
> + *lidac_self_max = *lidac_self_min = *lidac_self_ave = 0;
> +
> + data_size = 0;
> + error = cyapa_gen5_read_idac_data(cyapa,
> + GEN5_CMD_RETRIEVE_DATA_STRUCTURE,
> + GEN5_RETRIEVE_SELF_CAP_PWC_DATA,
> + &data_size,
> + lidac_self_max, lidac_self_min, lidac_self_ave);
> + if (error)
> + return error;
> + *gidac_self_rx = *lidac_self_max;
> + *gidac_self_tx = *lidac_self_min;
> +
> + error = cyapa_gen5_read_idac_data(cyapa,
> + GEN5_CMD_RETRIEVE_DATA_STRUCTURE,
> + GEN5_RETRIEVE_SELF_CAP_PWC_DATA,
> + &data_size,
> + lidac_self_max, lidac_self_min, lidac_self_ave);
> + return error;
> +}
> +
> +static ssize_t cyapa_gen5_execute_panel_scan(struct cyapa *cyapa)
> +{
> + int error;
> + u8 cmd[7];
> + u8 resp_data[6];
> + int resp_len;
> +
> + cmd[0] = 0x04;
> + cmd[1] = 0x00;
> + cmd[2] = 0x05;
> + cmd[3] = 0x00;
> + cmd[4] = GEN5_APP_CMD_REPORT_ID;
> + cmd[5] = 0x00;
> + cmd[6] = GEN5_CMD_EXECUTE_PANEL_SCAN; /* Command code */
> + resp_len = 6;
> + error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
> + cmd, 7,
> + resp_data, &resp_len,
> + 500, cyapa_gen5_sort_tsg_pip_app_resp_data, true);
> + if (error || resp_len != 6 ||
> + !VALID_CMD_RESP_HEADER(resp_data,
> + GEN5_CMD_EXECUTE_PANEL_SCAN) ||
> + !GEN5_CMD_COMPLETE_SUCCESS(resp_data[5]))
> + return error ? error : -EAGAIN;
> +
> + return 0;
> +}
> +
> +static int cyapa_gen5_read_panel_scan_raw_data(struct cyapa *cyapa,
> + u8 cmd_code, u8 raw_data_type, int raw_data_max_num,
> + int *raw_data_max, int *raw_data_min, int *raw_data_ave,
> + u8 *buffer)
> +{
> + int i;
> + u8 cmd[12];
> + u8 resp_data[256]; /* Max bytes can transfer one time. */
> + int resp_len;
> + int read_elements;
> + int read_len;
> + u16 offset;
> + s32 value;
> + int sum, count;
> + int data_size;
> + s32 *intp;
> + int error;
> +
> + if (cmd_code != GEN5_CMD_RETRIEVE_PANEL_SCAN ||
> + (raw_data_type > GEN5_PANEL_SCAN_SELF_DIFFCOUNT) ||
> + !raw_data_max || !raw_data_min || !raw_data_ave)
> + return -EINVAL;
> +
> + intp = (s32 *)buffer;
> + *raw_data_max = INT_MIN;
> + *raw_data_min = INT_MAX;
> + sum = count = 0;
> + offset = 0;
> + read_elements = (256 - 10) / 4; /* Currently, max element size is 4. */
> + read_len = read_elements * 4;
> + do {
> + cmd[0] = 0x04;
> + cmd[1] = 0x00;
> + cmd[2] = 0x0a;
> + cmd[3] = 0x00;
> + cmd[4] = GEN5_APP_CMD_REPORT_ID;
> + cmd[5] = 0x00;
> + cmd[6] = cmd_code; /* Command code */
> + put_unaligned_le16(offset, &cmd[7]);
> + put_unaligned_le16(read_elements, &cmd[9]);
> + cmd[11] = raw_data_type;
> + resp_len = 10 + read_len;
> +
> + error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
> + cmd, 12,
> + resp_data, &resp_len,
> + 500, cyapa_gen5_sort_tsg_pip_app_resp_data, true);
> + if (error || resp_len < 10 ||
> + !VALID_CMD_RESP_HEADER(resp_data, cmd_code) ||
> + !GEN5_CMD_COMPLETE_SUCCESS(resp_data[5]) ||
> + resp_data[6] != raw_data_type)
> + return error ? error : -EAGAIN;
> +
> + read_elements = get_unaligned_le16(&resp_data[7]);
> + if (read_elements == 0)
> + break;
> +
> + data_size = (resp_data[9] & GEN5_PWC_DATA_ELEMENT_SIZE_MASK);
> + offset += read_elements;
> + if (read_elements) {
> + for (i = 10;
> + i < (read_elements * data_size + 10);
> + i += data_size) {
> + value = cyapa_parse_structure_data(resp_data[9],
> + &resp_data[i], data_size);
> + *raw_data_min = min(value, *raw_data_min);
> + *raw_data_max = max(value, *raw_data_max);
> +
> + if (intp)
> + put_unaligned_le32(value, &intp[count]);
> +
> + sum += value;
> + count++;
> +
> + }
> + }
> +
> + if (count >= raw_data_max_num)
> + break;
> +
> + read_elements = (sizeof(resp_data) - 10) / data_size;
> + read_len = read_elements * data_size;
> + } while (true);
> +
> + *raw_data_ave = count ? (sum / count) : 0;
> +
> + return 0;
> +}
> +
> +static ssize_t cyapa_gen5_show_baseline(struct device *dev,
> + struct device_attribute *attr, char *buf)
> +{
> + struct cyapa *cyapa = dev_get_drvdata(dev);
> + int gidac_mutual_max, gidac_mutual_min, gidac_mutual_ave;
> + int lidac_mutual_max, lidac_mutual_min, lidac_mutual_ave;
> + int gidac_self_rx, gidac_self_tx;
> + int lidac_self_max, lidac_self_min, lidac_self_ave;
> + int raw_cap_mutual_max, raw_cap_mutual_min, raw_cap_mutual_ave;
> + int raw_cap_self_max, raw_cap_self_min, raw_cap_self_ave;
> + int mutual_diffdata_max, mutual_diffdata_min, mutual_diffdata_ave;
> + int self_diffdata_max, self_diffdata_min, self_diffdata_ave;
> + int mutual_baseline_max, mutual_baseline_min, mutual_baseline_ave;
> + int self_baseline_max, self_baseline_min, self_baseline_ave;
> + int error, resume_error;
> + int size;
> +
> + if (cyapa->state != CYAPA_STATE_GEN5_APP)
> + return -EBUSY;
> +
> + /* 1. Suspend Scanning*/
> + error = cyapa_gen5_suspend_scanning(cyapa);
> + if (error)
> + return error;
> +
> + /* 2. Read global and local mutual IDAC data. */
> + gidac_self_rx = gidac_self_tx = 0;
> + error = cyapa_gen5_read_mutual_idac_data(cyapa,
> + &gidac_mutual_max, &gidac_mutual_min,
> + &gidac_mutual_ave, &lidac_mutual_max,
> + &lidac_mutual_min, &lidac_mutual_ave);
> + if (error)
> + goto resume_scanning;
> +
> + /* 3. Read global and local self IDAC data. */
> + error = cyapa_gen5_read_self_idac_data(cyapa,
> + &gidac_self_rx, &gidac_self_tx,
> + &lidac_self_max, &lidac_self_min,
> + &lidac_self_ave);
> + if (error)
> + goto resume_scanning;
> +
> + /* 4. Execuate panel scan. It must be executed before read data. */
> + error = cyapa_gen5_execute_panel_scan(cyapa);
> + if (error)
> + goto resume_scanning;
> +
> + /* 5. Retrieve panel scan, mutual cap raw data. */
> + error = cyapa_gen5_read_panel_scan_raw_data(cyapa,
> + GEN5_CMD_RETRIEVE_PANEL_SCAN,
> + GEN5_PANEL_SCAN_MUTUAL_RAW_DATA,
> + cyapa->electrodes_x * cyapa->electrodes_y,
> + &raw_cap_mutual_max, &raw_cap_mutual_min,
> + &raw_cap_mutual_ave,
> + NULL);
> + if (error)
> + goto resume_scanning;
> +
> + /* 6. Retrieve panel scan, self cap raw data. */
> + error = cyapa_gen5_read_panel_scan_raw_data(cyapa,
> + GEN5_CMD_RETRIEVE_PANEL_SCAN,
> + GEN5_PANEL_SCAN_SELF_RAW_DATA,
> + cyapa->electrodes_x + cyapa->electrodes_y,
> + &raw_cap_self_max, &raw_cap_self_min,
> + &raw_cap_self_ave,
> + NULL);
> + if (error)
> + goto resume_scanning;
> +
> + /* 7. Retrieve panel scan, mutual cap diffcount raw data. */
> + error = cyapa_gen5_read_panel_scan_raw_data(cyapa,
> + GEN5_CMD_RETRIEVE_PANEL_SCAN,
> + GEN5_PANEL_SCAN_MUTUAL_DIFFCOUNT,
> + cyapa->electrodes_x * cyapa->electrodes_y,
> + &mutual_diffdata_max, &mutual_diffdata_min,
> + &mutual_diffdata_ave,
> + NULL);
> + if (error)
> + goto resume_scanning;
> +
> + /* 8. Retrieve panel scan, self cap diffcount raw data. */
> + error = cyapa_gen5_read_panel_scan_raw_data(cyapa,
> + GEN5_CMD_RETRIEVE_PANEL_SCAN,
> + GEN5_PANEL_SCAN_SELF_DIFFCOUNT,
> + cyapa->electrodes_x + cyapa->electrodes_y,
> + &self_diffdata_max, &self_diffdata_min,
> + &self_diffdata_ave,
> + NULL);
> + if (error)
> + goto resume_scanning;
> +
> + /* 9. Retrieve panel scan, mutual cap baseline raw data. */
> + error = cyapa_gen5_read_panel_scan_raw_data(cyapa,
> + GEN5_CMD_RETRIEVE_PANEL_SCAN,
> + GEN5_PANEL_SCAN_MUTUAL_BASELINE,
> + cyapa->electrodes_x * cyapa->electrodes_y,
> + &mutual_baseline_max, &mutual_baseline_min,
> + &mutual_baseline_ave,
> + NULL);
> + if (error)
> + goto resume_scanning;
> +
> + /* 10. Retrieve panel scan, self cap baseline raw data. */
> + error = cyapa_gen5_read_panel_scan_raw_data(cyapa,
> + GEN5_CMD_RETRIEVE_PANEL_SCAN,
> + GEN5_PANEL_SCAN_SELF_BASELINE,
> + cyapa->electrodes_x + cyapa->electrodes_y,
> + &self_baseline_max, &self_baseline_min,
> + &self_baseline_ave,
> + NULL);
> + if (error)
> + goto resume_scanning;
> +
> +resume_scanning:
> + /* 11. Resume Scanning*/
> + resume_error = cyapa_gen5_resume_scanning(cyapa);
> + if (resume_error || error)
> + return resume_error ? resume_error : error;
> +
> + /* 12. Output data strings */
> + size = scnprintf(buf, PAGE_SIZE, "%d %d %d %d %d %d %d %d %d %d %d ",
> + gidac_mutual_min, gidac_mutual_max, gidac_mutual_ave,
> + lidac_mutual_min, lidac_mutual_max, lidac_mutual_ave,
> + gidac_self_rx, gidac_self_tx,
> + lidac_self_min, lidac_self_max, lidac_self_ave);
> + size += scnprintf(buf + size, PAGE_SIZE - size,
> + "%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n",
> + raw_cap_mutual_min, raw_cap_mutual_max, raw_cap_mutual_ave,
> + raw_cap_self_min, raw_cap_self_max, raw_cap_self_ave,
> + mutual_diffdata_min, mutual_diffdata_max, mutual_diffdata_ave,
> + self_diffdata_min, self_diffdata_max, self_diffdata_ave,
> + mutual_baseline_min, mutual_baseline_max, mutual_baseline_ave,
> + self_baseline_min, self_baseline_max, self_baseline_ave);
> + return size;
> +}
> +
> static bool cyapa_gen5_sort_system_info_data(struct cyapa *cyapa,
> u8 *buf, int len)
> {
> @@ -1938,6 +2557,8 @@ const struct cyapa_dev_ops cyapa_gen5_ops = {
> .bl_initiate = cyapa_gen5_bl_initiate,
> .update_fw = cyapa_gen5_do_fw_update,
>
> + .show_baseline = cyapa_gen5_show_baseline,
> +
> .initialize = cyapa_gen5_initialize,
>
> .state_parse = cyapa_gen5_state_parse,
> --
> 1.9.1
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
--
- Jeremiah Mahler
^ permalink raw reply
* Re: [PATCHv3 0/5] ARM:sunxi:ps2 Added support for A10/A20 ps2 controller.
From: Vishnu Patekar @ 2014-12-15 14:13 UTC (permalink / raw)
To: Hans de Goede
Cc: linux-input-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org,
Dmitry Torokhov,
devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org,
linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org,
pawel.moll-5wv7dgnIgG8@public.gmane.org,
mark.rutland-5wv7dgnIgG8@public.gmane.org,
ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg@public.gmane.org,
Kumar Gala, linux-lFZ/pmaqli7XmaaqVzeoHQ@public.gmane.org,
Grant Likely,
benh-XVmvHMARGAS8U2dJNN8I7kB+6BGkLq7r@public.gmane.org,
msalter-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org,
ralf-6z/3iImG2C8G8FEW9MqTrA@public.gmane.org,
jdelvare-l3A5Bk7waGM@public.gmane.org
In-Reply-To: <548D5207.8030004-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
Hi,
On Sun, Dec 14, 2014 at 2:31 PM, Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org> wrote:
> Hi,
>
> On 13-12-14 21:01, Vishnu Patekar wrote:
>>
>> Hello Hans,
>> Please find my comments inlined.
>>
>> On 12/13/14, Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org> wrote:
>>>
>>> Hi VishnuPatekar,
>>>
>>> The patch mangling for this set seems to have gone a bit wrong I'm afraid
>>
>>
>> No, this time I've corrected it. Infact, last version of patch did not
>> used the status bit error macros.
>>
>>> a lot of the patches have my fixup commit messages (which should have
>>> disappeared when squashing in the patches), please replace those by
>>> proper
>>> commit messages describing what the patch actually does.
>>
>> Yes, [PATCHv3 3/5] uses fixup. I'll correct it.
>>>
>>>
>>> Also the adding of the commented nodes for the lime2 seems to be gone
>>> entirely
>>> from the set, instead now only a comment about the conflict with the hdmi
>>> pins is added, but it is above the i2c node instead of above a ps2 node.
>>>
>> Maxime's suggested that we should not add commented nodes specially
>> when its trivial to apply. And just note saying ps20 pins conflict
>> with HDMI.
>
>
> Ah, I see.
>
>> Should I remove the this comment as well?
>> Or
>> Put this note in start of DTS file?
>
>
> The comment should be added to where the pinctrl bits are, not to the lime2
> file, ps0 will conflict with hdmi on all boards.
Well, In that case,PS2_0 pins conflicts with HDMI, PS2_1 pins
conflicts with LCD. Every pin has multiplexing.
Do we really need to add this comment?
Can't we just keep PS2 pins disabled, without any comment in dtsi or dts file?
Whoever wants, can enable PS2 pins in respective board dts file by
taking care that it does not conflict with any other peripheral.
>
> Regards,
>
> Hans
>
>
>
>>> Regards,
>>>
>>> Hans
>>>
>>>
>>> On 12-12-14 19:25, VishnuPatekar wrote:
>>>>
>>>> v2 --> v3
>>>> 1. changed config to SERIO_SUN4I_PS2 from SERIO_SUNXI_PS2
>>>> 2. changed driver name to sun4i-ps2 from sunxi-ps2.
>>>> 3. changed the function names to sun4i_ps2_*.
>>>> 4. added locking in sun4i_ps2_open.
>>>> 5. kept compatible "sun4i-a10-ps2" for A10 and A20, as A10 is earlier
>>>> SOC.
>>>> 6. corrected the style errors.
>>>> 7. separated the dts patches.
>>>> 8. removed commented ps2 notes from lime2 dts.
>>>> 9. added note that ps2 pins confilt with hdmi.
>>>> 10. corrected the interrupt property for A10.
>>>> 11. moved dt-bindings to Documentation/devicetree/bindings/serio
>>>>
>>>> v1 --> v2:
>>>> 1. added default n depends on ARCH_SUNXI || COMPILE_TEST in Kconfig.
>>>> 2. handled errors and free resources on errors.
>>>> 3. used BIT(x), DIV_ROUND_UP macros.
>>>> 4. corrected style errors.
>>>> 5. added support for A10 also, A10 and A2 have same properties of PS2
>>>> controller.
>>>> 6. by default commented ps20 and ps21 nodes,as ps20 pins conflict with
>>>> HDMI.
>>>> 7. added compatible as allwinner,sun4i-a10-ps2.
>>>> 8. corrected the possible race condition.
>>>>
>>>>
>>>> VishnuPatekar (5):
>>>> sunxi:dts-bindings:input:ps2 bindings for A10/A20 ps2.
>>>> ARM:sunxi:drivers:input Add support for A10/A20 PS2
>>>> ARM: sunxi: dts: Add PS2 nodes to dtsi for A10 and A20
>>>> ARM: sunxi: dts: Add A10/A20 PS2 pin muxing options
>>>> ARM: sunxi: dts: Add note ps2 pins conflict with hdmi
>>>>
>>>> .../bindings/serio/allwinner,sun4i-ps2.txt | 23 ++
>>>> arch/arm/boot/dts/sun4i-a10.dtsi | 31 ++
>>>> arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts | 6 +-
>>>> arch/arm/boot/dts/sun7i-a20.dtsi | 32 ++
>>>> drivers/input/serio/Kconfig | 11 +
>>>> drivers/input/serio/Makefile | 1 +
>>>> drivers/input/serio/sun4i-ps2.c | 362
>>>> ++++++++++++++++++++
>>>> 7 files changed, 465 insertions(+), 1 deletion(-)
>>>> create mode 100644
>>>> Documentation/devicetree/bindings/serio/allwinner,sun4i-ps2.txt
>>>> create mode 100644 drivers/input/serio/sun4i-ps2.c
>>>>
>>>
>
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH v15 09/12] input: cyapa: add gen5 trackpad device firmware update function support
From: Jeremiah Mahler @ 2014-12-15 14:12 UTC (permalink / raw)
To: Dudley Du; +Cc: dmitry.torokhov, rydberg, bleung, linux-input, linux-kernel
In-Reply-To: <1418624603-19054-10-git-send-email-dudley.dulixin@gmail.com>
Dudley,
On Mon, Dec 15, 2014 at 02:23:20PM +0800, Dudley Du wrote:
> Add firmware image update function supported for gen5 trackpad device,
> it can be used through sysfs update_fw interface.
> TEST=test on Chromebooks.
>
> Signed-off-by: Dudley Du <dudley.dulixin@gmail.com>
> ---
> drivers/input/mouse/Kconfig | 1 +
> drivers/input/mouse/cyapa_gen5.c | 292 ++++++++++++++++++++++++++++++++++++++-
> 2 files changed, 292 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig
> index d8b46b0..728490e 100644
> --- a/drivers/input/mouse/Kconfig
> +++ b/drivers/input/mouse/Kconfig
> @@ -206,6 +206,7 @@ config MOUSE_BCM5974
> config MOUSE_CYAPA
> tristate "Cypress APA I2C Trackpad support"
> depends on I2C
> + select CRC_ITU_T
> help
> This driver adds support for Cypress All Points Addressable (APA)
> I2C Trackpads, including the ones used in 2012 Samsung Chromebooks.
> diff --git a/drivers/input/mouse/cyapa_gen5.c b/drivers/input/mouse/cyapa_gen5.c
> index 1ac264d..e89a952 100644
> --- a/drivers/input/mouse/cyapa_gen5.c
> +++ b/drivers/input/mouse/cyapa_gen5.c
> @@ -18,6 +18,7 @@
> #include <linux/completion.h>
> #include <linux/slab.h>
> #include <linux/unaligned/access_ok.h>
> +#include <linux/crc-itu-t.h>
> #include "cyapa.h"
>
>
> @@ -911,7 +912,87 @@ static int cyapa_gen5_state_parse(struct cyapa *cyapa, u8 *reg_data, int len)
> return -EAGAIN;
> }
>
> -bool cyapa_gen5_sort_bl_exit_data(struct cyapa *cyapa, u8 *buf, int len)
> +static int cyapa_gen5_bl_initiate(struct cyapa *cyapa,
> + const struct firmware *fw)
> +{
> + u16 length = 0;
> + u16 data_len = 0;
> + u16 meta_data_crc = 0;
> + u16 cmd_crc = 0;
> + u8 bl_gen5_activate[18 + CYAPA_TSG_FLASH_MAP_BLOCK_SIZE + 3];
> + int bl_gen5_activate_size = 0;
> + u8 resp_data[11];
> + int resp_len;
> + struct cyapa_tsg_bin_image *image;
> + int records_num;
> + u8 *data;
> + int error;
> +
> + /* Try to dump all buffered report data before send any command. */
any send command.
> + cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
> +
> + bl_gen5_activate_size = sizeof(bl_gen5_activate);
> + memset(bl_gen5_activate, 0, bl_gen5_activate_size);
> +
> + /* Output Report Register Address[15:0] = 0004h */
> + bl_gen5_activate[0] = 0x04;
> + bl_gen5_activate[1] = 0x00;
> +
> + /* Total command length[15:0] */
> + length = bl_gen5_activate_size - 2;
> + put_unaligned_le16(length, &bl_gen5_activate[2]);
> + bl_gen5_activate[4] = 0x40; /* Report ID = 40h */
> + bl_gen5_activate[5] = 0x00; /* RSVD = 00h */
> +
> + bl_gen5_activate[6] = GEN5_SOP_KEY; /* SOP = 01h */
> + bl_gen5_activate[7] = 0x48; /* Command Code = 48h */
> +
> + /* 8 Key bytes and block size */
> + data_len = CYAPA_TSG_BL_KEY_SIZE + CYAPA_TSG_FLASH_MAP_BLOCK_SIZE;
> + /* Data Length[15:0] */
> + put_unaligned_le16(data_len, &bl_gen5_activate[8]);
> + bl_gen5_activate[10] = 0xa5; /* Key Byte 0 */
> + bl_gen5_activate[11] = 0x01;
> + bl_gen5_activate[12] = 0x02; /* . */
> + bl_gen5_activate[13] = 0x03; /* . */
> + bl_gen5_activate[14] = 0xff; /* . */
> + bl_gen5_activate[15] = 0xfe;
> + bl_gen5_activate[16] = 0xfd;
> + bl_gen5_activate[17] = 0x5a; /* Key Byte 7 */
> +
I like the descriptions of what these magic values are.
I just wish there was a cleaner way to build up these buffers.
> + /* Copy 60 bytes Meta Data Row Parameters */
> + image = (struct cyapa_tsg_bin_image *)fw->data;
> + records_num = (fw->size - sizeof(struct cyapa_tsg_bin_image_head)) /
> + sizeof(struct cyapa_tsg_bin_image_data_record);
> + /* APP_INTEGRITY row is always the last row block */
> + data = image->records[records_num - 1].record_data;
> + memcpy(&bl_gen5_activate[18], data, CYAPA_TSG_FLASH_MAP_METADATA_SIZE);
> +
> + meta_data_crc = crc_itu_t(0xffff, &bl_gen5_activate[18],
> + CYAPA_TSG_FLASH_MAP_METADATA_SIZE);
> + /* Meta Data CRC[15:0] */
> + put_unaligned_le16(meta_data_crc,
> + &bl_gen5_activate[18 + CYAPA_TSG_FLASH_MAP_METADATA_SIZE]);
> +
> + cmd_crc = crc_itu_t(0xffff, &bl_gen5_activate[6], 4 + data_len);
> + put_unaligned_le16(cmd_crc,
> + &bl_gen5_activate[bl_gen5_activate_size - 3]); /* CRC[15:0] */
> + bl_gen5_activate[bl_gen5_activate_size - 1] = GEN5_EOP_KEY;
> +
> + resp_len = sizeof(resp_data);
> + error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
> + bl_gen5_activate, sizeof(bl_gen5_activate),
> + resp_data, &resp_len, 12000,
> + cyapa_gen5_sort_tsg_pip_bl_resp_data, true);
> + if (error || resp_len != GEN5_BL_INITIATE_RESP_LEN ||
> + resp_data[2] != GEN5_BL_RESP_REPORT_ID ||
> + !GEN5_CMD_COMPLETE_SUCCESS(resp_data[5]))
> + return error ? error : -EAGAIN;
> +
> + return 0;
> +}
> +
> +static bool cyapa_gen5_sort_bl_exit_data(struct cyapa *cyapa, u8 *buf, int len)
> {
> if (buf == NULL || len < GEN5_RESP_LENGTH_SIZE)
> return false;
> @@ -960,6 +1041,210 @@ static int cyapa_gen5_bl_exit(struct cyapa *cyapa)
> return -ENODEV;
> }
>
> +static int cyapa_gen5_bl_enter(struct cyapa *cyapa)
> +{
> + int error;
> + u8 cmd[] = { 0x04, 0x00, 0x05, 0x00, 0x2F, 0x00, 0x01 };
> + u8 resp_data[2];
> + int resp_len;
> +
> + error = cyapa_poll_state(cyapa, 500);
> + if (error < 0)
> + return error;
> + if (cyapa->gen != CYAPA_GEN5)
> + return -EINVAL;
> +
> + /* Already in Gen5 BL. Skipping exit. */
> + if (cyapa->state == CYAPA_STATE_GEN5_BL)
> + return 0;
> +
> + if (cyapa->state != CYAPA_STATE_GEN5_APP)
> + return -EAGAIN;
> +
> + /* Try to dump all buffered report data before send any command. */
> + cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
> +
> + /*
> + * Send bootloader enter command to trackpad device,
> + * after enter bootloader, the response data is two bytes of 0x00 0x00.
> + */
> + resp_len = sizeof(resp_data);
> + memset(resp_data, 0, resp_len);
> + error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
> + cmd, sizeof(cmd),
> + resp_data, &resp_len,
> + 5000, cyapa_gen5_sort_application_launch_data,
> + true);
> + if (error || resp_data[0] != 0x00 || resp_data[1] != 0x00)
> + return error < 0 ? error : -EAGAIN;
> +
> + cyapa->state = CYAPA_STATE_GEN5_BL;
> + return 0;
> +}
> +
> +static int cyapa_gen5_check_fw(struct cyapa *cyapa, const struct firmware *fw)
> +{
> + int i;
> + struct cyapa_tsg_bin_image *image;
> + int flash_records_count;
> + u16 expected_app_crc;
> + u16 expected_app_integrity_crc;
> + u16 app_crc = 0;
> + u16 app_integrity_crc = 0;
> + u16 row_num;
> + u8 *data;
> + u32 app_start;
> + u16 app_len;
> + u32 img_start;
> + u16 img_len;
> + int record_index;
> + struct device *dev = &cyapa->client->dev;
> +
> + image = (struct cyapa_tsg_bin_image *)fw->data;
> + flash_records_count = (fw->size -
> + sizeof(struct cyapa_tsg_bin_image_head)) /
> + sizeof(struct cyapa_tsg_bin_image_data_record);
> +
> + /* APP_INTEGRITY row is always the last row block,
> + * and the row id must be 0x01ff */
> + row_num = get_unaligned_be16(
> + &image->records[flash_records_count - 1].row_number);
> + if (image->records[flash_records_count - 1].flash_array_id != 0x00 &&
> + row_num != 0x01ff) {
> + dev_err(dev, "%s: invalid app_integrity data.\n", __func__);
> + return -EINVAL;
> + }
> + data = image->records[flash_records_count - 1].record_data;
> + app_start = get_unaligned_le32(&data[4]);
> + app_len = get_unaligned_le16(&data[8]);
> + expected_app_crc = get_unaligned_le16(&data[10]);
> + img_start = get_unaligned_le32(&data[16]);
> + img_len = get_unaligned_le16(&data[20]);
> + expected_app_integrity_crc = get_unaligned_le16(&data[60]);
I wish there was a cleaner and more descriptive way to avoid these magic
constants. Not sure if there is though :-)
> +
> + if ((app_start + app_len + img_start + img_len) %
> + CYAPA_TSG_FW_ROW_SIZE) {
> + dev_err(dev, "%s: invalid image alignment.\n", __func__);
> + return -EINVAL;
> + }
> +
> + /* Verify app_integrity crc */
> + app_integrity_crc = crc_itu_t(0xffff, data,
> + CYAPA_TSG_APP_INTEGRITY_SIZE);
> + if (app_integrity_crc != expected_app_integrity_crc) {
> + dev_err(dev, "%s: invalid app_integrity crc.\n", __func__);
> + return -EINVAL;
> + }
> +
> + /*
> + * Verify application image CRC
> + */
> + record_index = app_start / CYAPA_TSG_FW_ROW_SIZE -
> + CYAPA_TSG_IMG_START_ROW_NUM;
> + data = (u8 *)&image->records[record_index].record_data;
> + app_crc = crc_itu_t(0xffff, data, CYAPA_TSG_FW_ROW_SIZE);
> + for (i = 1; i < (app_len / CYAPA_TSG_FW_ROW_SIZE); i++) {
> + data = (u8 *)&image->records[++record_index].record_data;
> + app_crc = crc_itu_t(app_crc, data, CYAPA_TSG_FW_ROW_SIZE);
> + }
> +
> + if (app_crc != expected_app_crc) {
> + dev_err(dev, "%s: invalid firmware app crc check.\n", __func__);
> + return -EINVAL;
> + }
> +
> + return 0;
> +}
> +
> +static int cyapa_gen5_write_fw_block(struct cyapa *cyapa,
> + struct cyapa_tsg_bin_image_data_record *flash_record)
> +{
> + u8 flash_array_id;
> + u16 flash_row_id;
> + u16 record_len;
> + u8 *record_data;
> + u8 cmd[144]; /* 13 + 128+ 3 */
^
space
What does does 144 have to do with?
> + u16 cmd_len;
> + u16 data_len;
> + u16 crc;
> + u8 resp_data[11];
> + int resp_len;
> + int error;
> +
> + flash_array_id = flash_record->flash_array_id;
> + flash_row_id = get_unaligned_be16(&flash_record->row_number);
> + record_len = get_unaligned_be16(&flash_record->record_len);
> + record_data = flash_record->record_data;
> +
> + cmd_len = sizeof(cmd) - 2; /* Not include 2 bytes regisetr address. */
register
/* Don't include 2 byte register address. */
> + memset(cmd, 0, cmd_len + 2);
> + cmd[0] = 0x04; /* Register address */
> + cmd[1] = 0x00;
> +
> + put_unaligned_le16(cmd_len, &cmd[2]);
> + cmd[4] = 0x40; /* Report id 40h */
> + cmd[5] = 0x00;
> +
> + cmd[6] = GEN5_SOP_KEY; /* SOP = 01h */
> + cmd[7] = 0x39; /* Command code = 39h */
> + /* 1 (Flash Array ID) + 2 (Flash Row ID) + 128 (flash data) */
> + data_len = 3 + record_len;
> + put_unaligned_le16(data_len, &cmd[8]);
> + cmd[10] = flash_array_id; /* Flash Array ID = 00h */
> + put_unaligned_le16(flash_row_id, &cmd[11]);
> +
> + memcpy(&cmd[13], record_data, record_len);
> + crc = crc_itu_t(0xffff, &cmd[6], 4 + data_len);
> + put_unaligned_le16(crc, &cmd[2 + cmd_len - 3]);
> + cmd[2 + cmd_len - 1] = GEN5_EOP_KEY;
> +
> + resp_len = sizeof(resp_data);
> + error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
> + cmd, sizeof(cmd),
> + resp_data, &resp_len,
> + 500, cyapa_gen5_sort_tsg_pip_bl_resp_data, true);
> + if (error || resp_len != GEN5_BL_BLOCK_WRITE_RESP_LEN ||
> + resp_data[2] != GEN5_BL_RESP_REPORT_ID ||
> + !GEN5_CMD_COMPLETE_SUCCESS(resp_data[5]))
> + return error < 0 ? error : -EAGAIN;
> +
> + return 0;
> +}
> +
> +static int cyapa_gen5_do_fw_update(struct cyapa *cyapa,
> + const struct firmware *fw)
> +{
> + struct device *dev = &cyapa->client->dev;
> + struct cyapa_tsg_bin_image *image =
> + (struct cyapa_tsg_bin_image *)fw->data;
> + struct cyapa_tsg_bin_image_data_record *flash_record;
> + int flash_records_count;
> + int i;
> + int error;
> +
> + /* Try to dump all buffered data if exists before send commands. */
> + cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
> +
> + flash_records_count =
> + (fw->size - sizeof(struct cyapa_tsg_bin_image_head)) /
> + sizeof(struct cyapa_tsg_bin_image_data_record);
> + /*
> + * The last flash row 0x01ff has been written through bl_initiate
> + * command, so DO NOT write flash 0x01ff to trackpad device.
> + */
> + for (i = 0; i < (flash_records_count - 1); i++) {
> + flash_record = &image->records[i];
> + error = cyapa_gen5_write_fw_block(cyapa, flash_record);
> + if (error) {
> + dev_err(dev, "%s: Gen5 FW update aborted: %d\n",
> + __func__, error);
> + return error;
> + }
> + }
> +
> + return 0;
> +}
> +
> static int cyapa_gen5_change_power_state(struct cyapa *cyapa, u8 power_state)
> {
> u8 cmd[8] = { 0x04, 0x00, 0x06, 0x00, 0x2f, 0x00, 0x08, 0x01 };
> @@ -1648,6 +1933,11 @@ static int cyapa_gen5_irq_handler(struct cyapa *cyapa)
> }
>
> const struct cyapa_dev_ops cyapa_gen5_ops = {
> + .check_fw = cyapa_gen5_check_fw,
> + .bl_enter = cyapa_gen5_bl_enter,
> + .bl_initiate = cyapa_gen5_bl_initiate,
> + .update_fw = cyapa_gen5_do_fw_update,
> +
> .initialize = cyapa_gen5_initialize,
>
> .state_parse = cyapa_gen5_state_parse,
> --
> 1.9.1
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
--
- Jeremiah Mahler
^ permalink raw reply
* Re: [PATCH v15 08/12] input: cyapa: add gen3 trackpad device force re-calibrate function support
From: Jeremiah Mahler @ 2014-12-15 14:12 UTC (permalink / raw)
To: Dudley Du; +Cc: dmitry.torokhov, rydberg, bleung, linux-input, linux-kernel
In-Reply-To: <1418624603-19054-9-git-send-email-dudley.dulixin@gmail.com>
Dudley,
On Mon, Dec 15, 2014 at 02:23:19PM +0800, Dudley Du wrote:
> Add force re-calibrate function supported for gen3 trackpad device,
> it can be used through sysfs calibrate interface.
> TEST=test on Chromebooks.
>
> Signed-off-by: Dudley Du <dudley.dulixin@gmail.com>
> ---
> drivers/input/mouse/cyapa_gen3.c | 58 ++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 58 insertions(+)
>
> diff --git a/drivers/input/mouse/cyapa_gen3.c b/drivers/input/mouse/cyapa_gen3.c
> index f42e008..836a00b 100644
> --- a/drivers/input/mouse/cyapa_gen3.c
> +++ b/drivers/input/mouse/cyapa_gen3.c
> @@ -754,6 +754,63 @@ static int cyapa_gen3_do_fw_update(struct cyapa *cyapa,
> return 0;
> }
>
> +static ssize_t cyapa_gen3_do_calibrate(struct device *dev,
> + struct device_attribute *attr,
> + const char *buf, size_t count)
> +{
> + struct cyapa *cyapa = dev_get_drvdata(dev);
> + int tries = 20; /* max recalibration timeout 2s. */
Where this timeout is used is not obvious here.
Maybe move it to the loop where it is used?
+ int tries;
> + int ret;
> +
> + ret = cyapa_read_byte(cyapa, CYAPA_CMD_DEV_STATUS);
> + if (ret < 0) {
> + dev_err(dev, "Error reading dev status: %d\n", ret);
> + goto out;
> + }
> + if ((ret & CYAPA_DEV_NORMAL) != CYAPA_DEV_NORMAL) {
> + dev_warn(dev, "Trackpad device is busy, device state: 0x%02x\n",
> + ret);
> + ret = -EAGAIN;
> + goto out;
> + }
> +
> + ret = cyapa_write_byte(cyapa, CYAPA_CMD_SOFT_RESET,
> + OP_RECALIBRATION_MASK);
> + if (ret < 0) {
> + dev_err(dev, "Failed to send calibrate command: %d\n",
> + ret);
> + goto out;
> + }
> +
Set tries here since it is used in this loop.
+ tries = 20; /* max recalibration timeout 2s. */
> + do {
> + /*
> + * For this recalibration, the max time will not exceed 2s.
> + * The average time is approximately 500 - 700 ms, and we
> + * will check the status every 100 - 200ms.
> + */
> + usleep_range(100000, 200000);
> +
> + ret = cyapa_read_byte(cyapa, CYAPA_CMD_DEV_STATUS);
> + if (ret < 0) {
> + dev_err(dev, "Error reading dev status: %d\n",
> + ret);
> + goto out;
> + }
> + if ((ret & CYAPA_DEV_NORMAL) == CYAPA_DEV_NORMAL)
> + break;
> + } while (--tries);
> +
> + if (tries == 0) {
> + dev_err(dev, "Failed to calibrate. Timeout.\n");
> + ret = -ETIMEDOUT;
> + goto out;
> + }
> + dev_dbg(dev, "Calibration successful.\n");
> +
> +out:
> + return ret < 0 ? ret : count;
> +}
> +
> static ssize_t cyapa_gen3_show_baseline(struct device *dev,
> struct device_attribute *attr, char *buf)
> {
> @@ -1137,6 +1194,7 @@ const struct cyapa_dev_ops cyapa_gen3_ops = {
> .bl_deactivate = cyapa_gen3_bl_deactivate,
>
> .show_baseline = cyapa_gen3_show_baseline,
> + .calibrate_store = cyapa_gen3_do_calibrate,
>
> .state_parse = cyapa_gen3_state_parse,
> .operational_check = cyapa_gen3_do_operational_check,
> --
> 1.9.1
>
> --
> 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
--
- Jeremiah Mahler
^ permalink raw reply
* Re: [PATCH v15 07/12] input: cyapa: add gen3 trackpad device read baseline function support
From: Jeremiah Mahler @ 2014-12-15 14:11 UTC (permalink / raw)
To: Dudley Du; +Cc: dmitry.torokhov, rydberg, bleung, linux-input, linux-kernel
In-Reply-To: <1418624603-19054-8-git-send-email-dudley.dulixin@gmail.com>
Dudley,
On Mon, Dec 15, 2014 at 02:23:18PM +0800, Dudley Du wrote:
> Add read baseline function supported for gen3 trackpad device,
> it can be used through sysfs baseline interface.
> TEST=test on Chromebooks.
>
> Signed-off-by: Dudley Du <dudley.dulixin@gmail.com>
> ---
> drivers/input/mouse/cyapa_gen3.c | 71 ++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 71 insertions(+)
>
> diff --git a/drivers/input/mouse/cyapa_gen3.c b/drivers/input/mouse/cyapa_gen3.c
> index 9851337..f42e008 100644
> --- a/drivers/input/mouse/cyapa_gen3.c
> +++ b/drivers/input/mouse/cyapa_gen3.c
> @@ -754,6 +754,75 @@ static int cyapa_gen3_do_fw_update(struct cyapa *cyapa,
> return 0;
> }
>
> +static ssize_t cyapa_gen3_show_baseline(struct device *dev,
> + struct device_attribute *attr, char *buf)
> +{
> + struct cyapa *cyapa = dev_get_drvdata(dev);
> + int max_baseline, min_baseline;
> + int tries = 3;
Perhaps just declare tries here, then initialize and document it near
where it will be used.
+ int tries;
> + int ret;
> +
> + ret = cyapa_read_byte(cyapa, CYAPA_CMD_DEV_STATUS);
> + if (ret < 0) {
> + dev_err(dev, "Error reading dev status. err = %d\n", ret);
> + goto out;
> + }
> + if ((ret & CYAPA_DEV_NORMAL) != CYAPA_DEV_NORMAL) {
> + dev_warn(dev, "Trackpad device is busy. device state = 0x%x\n",
> + ret);
> + ret = -EAGAIN;
> + goto out;
> + }
> +
> + ret = cyapa_write_byte(cyapa, CYAPA_CMD_SOFT_RESET,
> + OP_REPORT_BASELINE_MASK);
> + if (ret < 0) {
> + dev_err(dev, "Failed to send report baseline command. %d\n",
> + ret);
> + goto out;
> + }
> +
+ tries = 3; /* try for 30 to 60 ms */
> + do {
> + usleep_range(10000, 20000);
> +
> + ret = cyapa_read_byte(cyapa, CYAPA_CMD_DEV_STATUS);
> + if (ret < 0) {
> + dev_err(dev, "Error reading dev status. err = %d\n",
> + ret);
> + goto out;
> + }
> + if ((ret & CYAPA_DEV_NORMAL) == CYAPA_DEV_NORMAL)
> + break;
> + } while (--tries);
> +
> + if (tries == 0) {
> + dev_err(dev, "Device timed out going to Normal state.\n");
> + ret = -ETIMEDOUT;
> + goto out;
> + }
> +
> + ret = cyapa_read_byte(cyapa, CYAPA_CMD_MAX_BASELINE);
> + if (ret < 0) {
> + dev_err(dev, "Failed to read max baseline. err = %d\n", ret);
> + goto out;
> + }
> + max_baseline = ret;
> +
> + ret = cyapa_read_byte(cyapa, CYAPA_CMD_MIN_BASELINE);
> + if (ret < 0) {
> + dev_err(dev, "Failed to read min baseline. err = %d\n", ret);
> + goto out;
> + }
> + min_baseline = ret;
> +
> + dev_dbg(dev, "Baseline report successful. Max: %d Min: %d\n",
> + max_baseline, min_baseline);
> + ret = scnprintf(buf, PAGE_SIZE, "%d %d\n", max_baseline, min_baseline);
> +
> +out:
> + return ret;
> +}
> +
> /*
> * cyapa_get_wait_time_for_pwr_cmd
> *
> @@ -1067,6 +1136,8 @@ const struct cyapa_dev_ops cyapa_gen3_ops = {
> .update_fw = cyapa_gen3_do_fw_update,
> .bl_deactivate = cyapa_gen3_bl_deactivate,
>
> + .show_baseline = cyapa_gen3_show_baseline,
> +
> .state_parse = cyapa_gen3_state_parse,
> .operational_check = cyapa_gen3_do_operational_check,
>
> --
> 1.9.1
>
> --
> 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
--
- Jeremiah Mahler
^ permalink raw reply
* Re: [PATCH v15 06/12] input: cyapa: add gen3 trackpad device firmware update function support
From: Jeremiah Mahler @ 2014-12-15 14:11 UTC (permalink / raw)
To: Dudley Du; +Cc: dmitry.torokhov, rydberg, bleung, linux-input, linux-kernel
In-Reply-To: <1418624603-19054-7-git-send-email-dudley.dulixin@gmail.com>
Dudley,
On Mon, Dec 15, 2014 at 02:23:17PM +0800, Dudley Du wrote:
> Add firmware image update function supported for gen3 trackpad device,
> it can be used through sysfs update_fw interface.
> TEST=test on Chromebooks.
>
> Signed-off-by: Dudley Du <dudley.dulixin@gmail.com>
> ---
> drivers/input/mouse/cyapa_gen3.c | 284 +++++++++++++++++++++++++++++++++++++++
> 1 file changed, 284 insertions(+)
>
> diff --git a/drivers/input/mouse/cyapa_gen3.c b/drivers/input/mouse/cyapa_gen3.c
> index 433c5b1..9851337 100644
> --- a/drivers/input/mouse/cyapa_gen3.c
> +++ b/drivers/input/mouse/cyapa_gen3.c
> @@ -416,6 +416,72 @@ static int cyapa_gen3_state_parse(struct cyapa *cyapa, u8 *reg_data, int len)
> return -EAGAIN;
> }
>
> +/*
> + * Enter bootloader by soft resetting the device.
> + *
> + * If device is already in the bootloader, the function just returns.
> + * Otherwise, reset the device; after reset, device enters bootloader idle
> + * state immediately.
> + *
> + * Also, if device was unregister device from input core. Device will
> + * re-register after it is detected following resumption of operational mode.
> + *
I don't quite understand this. Tell me if the following re-wording is
correct.
+ * Also, if the device was unregistered from the input core, the device
+ * will re-register after it is detected following resumption of
+ * operational mode.
> + * Returns:
> + * 0 on success
> + * -EAGAIN device was reset, but is not now in bootloader idle state
> + * < 0 if the device never responds within the timeout
Could be formatted nicer. Tell me if the re-wording makes sense.
+ * 0 on success
+ * -EAGAIN if device was reset, but it is not in bootloader idle state
+ * < 0 if the device never responds within the timeout
> + */
> +static int cyapa_gen3_bl_enter(struct cyapa *cyapa)
> +{
> + int error;
> +
> + error = cyapa_poll_state(cyapa, 500);
> + if (error)
> + return error;
> + if (cyapa->state == CYAPA_STATE_BL_IDLE) {
> + /* Already in BL_IDLE. Skipping reset. */
> + return 0;
> + }
> +
> + if (cyapa->state != CYAPA_STATE_OP)
> + return -EAGAIN;
> +
> + cyapa->state = CYAPA_STATE_NO_DEVICE;
> + error = cyapa_write_byte(cyapa, CYAPA_CMD_SOFT_RESET, 0x01);
> + if (error)
> + return -EIO;
> +
> + usleep_range(25000, 50000);
> + error = cyapa_poll_state(cyapa, 500);
> + if (error)
> + return error;
> + if ((cyapa->state != CYAPA_STATE_BL_IDLE) ||
> + (cyapa->status[REG_BL_STATUS] & BL_STATUS_WATCHDOG))
> + return -EAGAIN;
> +
> + return 0;
> +}
> +
> +static int cyapa_gen3_bl_activate(struct cyapa *cyapa)
> +{
> + int error;
> +
> + error = cyapa_i2c_reg_write_block(cyapa, 0, sizeof(bl_activate),
> + bl_activate);
> + if (error)
> + return error;
> +
> + /* Wait for bootloader to activate; takes between 2 and 12 seconds */
> + msleep(2000);
> + error = cyapa_poll_state(cyapa, 11000);
> + if (error)
> + return error;
> + if (cyapa->state != CYAPA_STATE_BL_ACTIVE)
> + return -EAGAIN;
> +
> + return 0;
> +}
> +
> static int cyapa_gen3_bl_deactivate(struct cyapa *cyapa)
> {
> int error;
> @@ -476,6 +542,218 @@ static int cyapa_gen3_bl_exit(struct cyapa *cyapa)
> return 0;
> }
>
> +/* Used in gen3 bootloader commands. */
We should be able to figure out where it is used. Unnecessary comment?
> +static u16 cyapa_gen3_csum(const u8 *buf, size_t count)
> +{
> + int i;
> + u16 csum = 0;
> +
> + for (i = 0; i < count; i++)
> + csum += buf[i];
> +
> + return csum;
> +}
> +
> +/*
> + * Verify the integrity of a CYAPA firmware image file.
> + *
> + * The firmware image file is 30848 bytes, composed of 482 64-byte blocks.
> + *
> + * The first 2 blocks are the firmware header.
> + * The next 480 blocks are the firmware image.
> + *
> + * The first two bytes of the header hold the header checksum, computed by
> + * summing the other 126 bytes of the header.
> + * The last two bytes of the header hold the firmware image checksum, computed
> + * by summing the 30720 bytes of the image modulo 0xffff.
> + *
> + * Both checksums are stored little-endian.
> + */
> +static int cyapa_gen3_check_fw(struct cyapa *cyapa, const struct firmware *fw)
> +{
> + struct device *dev = &cyapa->client->dev;
> + u16 csum;
> + u16 csum_expected;
> +
> + /* Firmware must match exact 30848 bytes = 482 64-byte blocks. */
> + if (fw->size != CYAPA_FW_SIZE) {
> + dev_err(dev, "invalid firmware size = %zu, expected %u.\n",
> + fw->size, CYAPA_FW_SIZE);
> + return -EINVAL;
> + }
> +
> + /* Verify header block */
> + csum_expected = (fw->data[0] << 8) | fw->data[1];
> + csum = cyapa_gen3_csum(&fw->data[2], CYAPA_FW_HDR_SIZE - 2);
> + if (csum != csum_expected) {
> + dev_err(dev, "%s %04x, expected: %04x\n",
> + "invalid firmware header checksum = ",
> + csum, csum_expected);
> + return -EINVAL;
> + }
> +
> + /* Verify firmware image */
> + csum_expected = (fw->data[CYAPA_FW_HDR_SIZE - 2] << 8) |
> + fw->data[CYAPA_FW_HDR_SIZE - 1];
> + csum = cyapa_gen3_csum(&fw->data[CYAPA_FW_HDR_SIZE],
> + CYAPA_FW_DATA_SIZE);
> + if (csum != csum_expected) {
> + dev_err(dev, "%s %04x, expected: %04x\n",
> + "invalid firmware header checksum = ",
> + csum, csum_expected);
> + return -EINVAL;
> + }
> + return 0;
> +}
> +
> +/*
> + * Write a |len| byte long buffer |buf| to the device, by chopping it up into a
> + * sequence of smaller |CYAPA_CMD_LEN|-length write commands.
> + *
> + * The data bytes for a write command are prepended with the 1-byte offset
> + * of the data relative to the start of |buf|.
> + */
> +static int cyapa_gen3_write_buffer(struct cyapa *cyapa,
> + const u8 *buf, size_t len)
> +{
> + int error;
> + size_t i;
> + unsigned char cmd[CYAPA_CMD_LEN + 1];
> + size_t cmd_len;
> +
> + for (i = 0; i < len; i += CYAPA_CMD_LEN) {
> + const u8 *payload = &buf[i];
> +
> + cmd_len = (len - i >= CYAPA_CMD_LEN) ? CYAPA_CMD_LEN : len - i;
> + cmd[0] = i;
> + memcpy(&cmd[1], payload, cmd_len);
> +
> + error = cyapa_i2c_reg_write_block(cyapa, 0, cmd_len + 1, cmd);
> + if (error)
> + return error;
> + }
> + return 0;
> +}
> +
> +/*
> + * A firmware block write command writes 64 bytes of data to a single flash
> + * page in the device. The 78-byte block write command has the format:
> + * <0xff> <CMD> <Key> <Start> <Data> <Data-Checksum> <CMD Checksum>
> + *
> + * <0xff> - every command starts with 0xff
> + * <CMD> - the write command value is 0x39
> + * <Key> - write commands include an 8-byte key: { 00 01 02 03 04 05 06 07 }
> + * <Block> - Memory Block number (address / 64) (16-bit, big-endian)
> + * <Data> - 64 bytes of firmware image data
> + * <Data Checksum> - sum of 64 <Data> bytes, modulo 0xff
> + * <CMD Checksum> - sum of 77 bytes, from 0xff to <Data Checksum>
> + *
> + * Each write command is split into 5 i2c write transactions of up to 16 bytes.
> + * Each transaction starts with an i2c register offset: (00, 10, 20, 30, 40).
> + */
> +static int cyapa_gen3_write_fw_block(struct cyapa *cyapa,
> + u16 block, const u8 *data)
> +{
> + int ret;
> + u8 cmd[78];
> + u8 status[BL_STATUS_SIZE];
> + /* Programming for one block can take about 100ms. */
> + int tries = 11;
> + u8 bl_status, bl_error;
> +
> + /* Set write command and security key bytes. */
> + cmd[0] = 0xff;
> + cmd[1] = 0x39;
> + cmd[2] = 0x00;
> + cmd[3] = 0x01;
> + cmd[4] = 0x02;
> + cmd[5] = 0x03;
> + cmd[6] = 0x04;
> + cmd[7] = 0x05;
> + cmd[8] = 0x06;
> + cmd[9] = 0x07;
> + cmd[10] = block >> 8;
> + cmd[11] = block;
> + memcpy(&cmd[12], data, CYAPA_FW_BLOCK_SIZE);
> + cmd[76] = cyapa_gen3_csum(data, CYAPA_FW_BLOCK_SIZE);
> + cmd[77] = cyapa_gen3_csum(cmd, sizeof(cmd) - 1);
> +
Sequences like these are used all over this code. I wish there was a
cleaner and more descriptive way to describe what is being constructed.
Perhaps using a struct?
> + ret = cyapa_gen3_write_buffer(cyapa, cmd, sizeof(cmd));
> + if (ret)
> + return ret;
> +
> + /* Wait for write to finish */
> + do {
> + usleep_range(10000, 20000);
> +
> + /* Check block write command result status. */
> + ret = cyapa_i2c_reg_read_block(cyapa, BL_HEAD_OFFSET,
> + BL_STATUS_SIZE, status);
> + if (ret != BL_STATUS_SIZE)
> + return (ret < 0) ? ret : -EIO;
> + } while ((status[REG_BL_STATUS] & BL_STATUS_BUSY) && --tries);
> +
> + /* Ignore WATCHDOG bit and reserved bits. */
> + bl_status = status[REG_BL_STATUS] & ~BL_STATUS_REV_MASK;
> + bl_error = status[REG_BL_ERROR] & ~BL_ERROR_RESERVED;
> +
> + if (bl_status & BL_STATUS_BUSY)
> + ret = -ETIMEDOUT;
> + else if (bl_status != BL_STATUS_RUNNING ||
> + bl_error != BL_ERROR_BOOTLOADING)
> + ret = -EIO;
> + else
> + ret = 0;
> +
> + return ret;
> +}
> +
> +static int cyapa_gen3_write_blocks(struct cyapa *cyapa,
> + size_t start_block, size_t block_count,
> + const u8 *image_data)
> +{
> + int error;
> + int i;
> +
> + for (i = 0; i < block_count; i++) {
> + size_t block = start_block + i;
> + size_t addr = i * CYAPA_FW_BLOCK_SIZE;
> + const u8 *data = &image_data[addr];
> +
> + error = cyapa_gen3_write_fw_block(cyapa, block, data);
> + if (error)
> + return error;
> + }
> + return 0;
> +}
> +
> +static int cyapa_gen3_do_fw_update(struct cyapa *cyapa,
> + const struct firmware *fw)
> +{
> + struct device *dev = &cyapa->client->dev;
> + int error;
> +
> + /* First write data, starting at byte 128 of fw->data */
^
extra space
> + error = cyapa_gen3_write_blocks(cyapa,
> + CYAPA_FW_DATA_BLOCK_START, CYAPA_FW_DATA_BLOCK_COUNT,
> + &fw->data[CYAPA_FW_HDR_BLOCK_COUNT * CYAPA_FW_BLOCK_SIZE]);
> + if (error) {
> + dev_err(dev, "FW update aborted, write image: %d\n", error);
> + return error;
> + }
> +
> + /* Then write checksum */
> + error = cyapa_gen3_write_blocks(cyapa,
> + CYAPA_FW_HDR_BLOCK_START, CYAPA_FW_HDR_BLOCK_COUNT,
> + &fw->data[0]);
> + if (error) {
> + dev_err(dev, "FW update aborted, write checksum: %d\n", error);
> + return error;
> + }
> +
> + return 0;
> +}
> +
> /*
> * cyapa_get_wait_time_for_pwr_cmd
> *
> @@ -783,6 +1061,12 @@ static int cyapa_gen3_irq_handler(struct cyapa *cyapa)
> }
>
> const struct cyapa_dev_ops cyapa_gen3_ops = {
> + .check_fw = cyapa_gen3_check_fw,
> + .bl_enter = cyapa_gen3_bl_enter,
> + .bl_activate = cyapa_gen3_bl_activate,
> + .update_fw = cyapa_gen3_do_fw_update,
> + .bl_deactivate = cyapa_gen3_bl_deactivate,
> +
> .state_parse = cyapa_gen3_state_parse,
> .operational_check = cyapa_gen3_do_operational_check,
>
> --
> 1.9.1
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
--
- Jeremiah Mahler
^ permalink raw reply
* Re: [PATCH v15 05/12] input: cyapa: add sysfs interfaces supported in the cyapa driver
From: Jeremiah Mahler @ 2014-12-15 14:11 UTC (permalink / raw)
To: Dudley Du; +Cc: dmitry.torokhov, rydberg, bleung, linux-input, linux-kernel
In-Reply-To: <1418624603-19054-6-git-send-email-dudley.dulixin@gmail.com>
Dudley,
On Mon, Dec 15, 2014 at 02:23:16PM +0800, Dudley Du wrote:
> Add device's basic control and features supported in cyapa driver through
> sysfs file system interfaces. These interfaces are commonly used in
> pre- and after production, for trackpad device state checking, managing
> and firmware image updating.
> These interfaces including mode, firmware_version and product_id interfaces
> for reading firmware version and trackpad device product id values,
> and including update_fw interface to command firmware image update
> process. Also including baseline and calibrate interfaces for
> reading and checking trackpad device's sensors states.
This paragraph isn't aligned very well and is hard to read.
If you use Vim the 'gq' command can help with this.
> TEST=test on Chromebooks.
>
> Signed-off-by: Dudley Du <dudley.dulixin@gmail.com>
> ---
> drivers/input/mouse/cyapa.c | 327 ++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 327 insertions(+)
>
> diff --git a/drivers/input/mouse/cyapa.c b/drivers/input/mouse/cyapa.c
> index 3bcfce3..dac3996 100644
> --- a/drivers/input/mouse/cyapa.c
> +++ b/drivers/input/mouse/cyapa.c
> @@ -32,6 +32,8 @@
> #define CYAPA_ADAPTER_FUNC_SMBUS 2
> #define CYAPA_ADAPTER_FUNC_BOTH 3
>
> +#define CYAPA_FW_NAME "cyapa.bin"
> +
> const char product_id[] = "CYTRA";
Yes, I like that better than unique_str :-)
>
> static int cyapa_reinitialize(struct cyapa *cyapa);
> @@ -442,6 +444,29 @@ static int cyapa_create_input_dev(struct cyapa *cyapa)
> return 0;
> }
>
> +static void cyapa_enable_irq_for_cmd(struct cyapa *cyapa)
> +{
> + struct input_dev *input = cyapa->input;
> +
> + if (!input || !input->users) {
> + if (!CYAPA_BOOTLOADER(cyapa) && cyapa->ops->set_power_mode)
> + cyapa->ops->set_power_mode(cyapa,
> + PWR_MODE_FULL_ACTIVE, 0);
> + enable_irq(cyapa->client->irq);
> + }
> +}
> +
> +static void cyapa_disable_irq_for_cmd(struct cyapa *cyapa)
> +{
> + struct input_dev *input = cyapa->input;
> +
> + if (!input || !input->users) {
> + disable_irq(cyapa->client->irq);
> + if (!CYAPA_BOOTLOADER(cyapa) && cyapa->ops->set_power_mode)
> + cyapa->ops->set_power_mode(cyapa, PWR_MODE_OFF, 0);
> + }
> +}
> +
> /*
> * cyapa_sleep_time_to_pwr_cmd and cyapa_pwr_cmd_to_sleep_time
> *
> @@ -783,6 +808,295 @@ static int cyapa_start_runtime(struct cyapa *cyapa)
> }
> #endif /* CONFIG_PM_RUNTIME */
>
> +static ssize_t cyapa_show_fm_ver(struct device *dev,
> + struct device_attribute *attr, char *buf)
> +{
> + int error;
> + struct cyapa *cyapa = dev_get_drvdata(dev);
> +
> + error = mutex_lock_interruptible(&cyapa->state_sync_lock);
> + if (error)
> + return error;
> + error = scnprintf(buf, PAGE_SIZE, "%d.%d\n", cyapa->fw_maj_ver,
> + cyapa->fw_min_ver);
> + mutex_unlock(&cyapa->state_sync_lock);
> + return error;
> +}
> +
> +static ssize_t cyapa_show_product_id(struct device *dev,
> + struct device_attribute *attr, char *buf)
> +{
> + struct cyapa *cyapa = dev_get_drvdata(dev);
> + int size;
> + int error;
> +
> + error = mutex_lock_interruptible(&cyapa->state_sync_lock);
> + if (error)
> + return error;
> + size = scnprintf(buf, PAGE_SIZE, "%s\n", cyapa->product_id);
> + mutex_unlock(&cyapa->state_sync_lock);
> + return size;
> +}
> +
> +static int cyapa_firmware(struct cyapa *cyapa, const char *fw_name)
> +{
> + struct device *dev = &cyapa->client->dev;
> + const struct firmware *fw;
> + int error;
> +
> + error = request_firmware(&fw, fw_name, dev);
> + if (error) {
> + dev_err(dev, "Could not load firmware from %s: %d\n",
> + fw_name, error);
> + return error;
> + }
> +
> + if (cyapa->ops->check_fw) {
> + error = cyapa->ops->check_fw(cyapa, fw);
> + if (error) {
> + dev_err(dev, "Invalid CYAPA firmware image: %s\n",
> + fw_name);
> + goto done;
> + }
> + } else {
> + dev_err(dev, "No valid device ops->check_fw handler set.\n");
> + error = -ENODEV;
> + goto done;
> + }
> +
> + /*
> + * Resume the potentially suspended device because doing FW
> + * update on a device not in the FULL mode has a chance to
> + * fail.
> + */
> + pm_runtime_get_sync(dev);
> +
> + /* Require IRQ support for firmware update commands. */
> + cyapa_enable_irq_for_cmd(cyapa);
> +
> + if (cyapa->ops->bl_enter) {
> + error = cyapa->ops->bl_enter(cyapa);
> + if (error) {
> + dev_err(dev, "bl_enter failed, %d\n", error);
> + goto err_detect;
> + }
> + }
> +
> + if (cyapa->ops->bl_activate) {
> + error = cyapa->ops->bl_activate(cyapa);
> + if (error) {
> + dev_err(dev, "bl_activate failed, %d\n", error);
> + goto err_detect;
> + }
> + }
> +
> + if (cyapa->ops->bl_initiate) {
> + error = cyapa->ops->bl_initiate(cyapa, fw);
> + if (error) {
> + dev_err(dev, "bl_initiate failed, %d\n", error);
> + goto err_detect;
> + }
> + }
> +
> + if (cyapa->ops->update_fw) {
> + error = cyapa->ops->update_fw(cyapa, fw);
> + if (error) {
> + dev_err(dev, "update_fw failed, %d\n", error);
> + goto err_detect;
> + }
> + }
> +
> + if (cyapa->ops->bl_verify_app_integrity) {
> + error = cyapa->ops->bl_verify_app_integrity(cyapa);
> + if (error) {
> + dev_err(dev, "bl_verify_app_integrity failed, %d\n",
> + error);
> + goto err_detect;
> + }
> + }
> +
> +err_detect:
> + cyapa_disable_irq_for_cmd(cyapa);
> + pm_runtime_put_noidle(dev);
> +
> +done:
> + release_firmware(fw);
> + return error;
> +}
> +
> +static ssize_t cyapa_update_fw_store(struct device *dev,
> + struct device_attribute *attr,
> + const char *buf, size_t count)
> +{
> + struct cyapa *cyapa = dev_get_drvdata(dev);
> + char fw_name[64];
> + int ret, error;
> +
What is the significance of 64?
Should it be NAME_MAX or PATH_MAX (see linux/limits.h)?
> + if (count > 64) {
> + dev_err(dev, "File name too long\n");
> + return -EINVAL;
> + }
> +
> + memcpy(fw_name, buf, count);
> + if (fw_name[count - 1] == '\n')
> + fw_name[count - 1] = '\0';
> + else
> + fw_name[count] = '\0';
> +
> + if (cyapa->input) {
> + /*
> + * Force the input device to be registered after the firmware
> + * image is updated, so if the corresponding parameters updated
> + * in the new firmware image can taken effect immediately.
> + */
> + input_unregister_device(cyapa->input);
> + cyapa->operational = false;
> + cyapa->input = NULL;
> + }
> +
> + error = mutex_lock_interruptible(&cyapa->state_sync_lock);
> + if (error) {
> + /*
> + * Whatever, do reinitialize to try to recover TP state to
> + * previous state just as it entered fw update entrance.
> + */
> + cyapa_reinitialize(cyapa);
> + return error;
> + }
> +
> + error = cyapa_firmware(cyapa, fw_name);
> + if (error)
> + dev_err(dev, "firmware update failed: %d\n", error);
> + else
> + dev_dbg(dev, "firmware update successfully done.\n");
> +
> + /*
> + * Redetect trackpad device states because firmware update process
> + * will reset trackpad device into bootloader mode.
> + */
> + ret = cyapa_reinitialize(cyapa);
> + if (ret) {
> + dev_err(dev, "failed to redetect after updated: %d\n", ret);
> + error = error ? error : ret;
> + }
> +
> + mutex_unlock(&cyapa->state_sync_lock);
> +
> + return error ? error : count;
> +}
> +
> +static ssize_t cyapa_calibrate_store(struct device *dev,
> + struct device_attribute *attr,
> + const char *buf, size_t count)
> +{
> + struct cyapa *cyapa = dev_get_drvdata(dev);
> + int error;
> +
> + error = mutex_lock_interruptible(&cyapa->state_sync_lock);
> + if (error)
> + return error;
> +
> + if (!cyapa->ops->calibrate_store) {
> + dev_err(dev, "Calibrate operation not supported.\n");
> + error = -ENOTSUPP;
> + } else {
> + cyapa_enable_irq_for_cmd(cyapa);
> + error = cyapa->ops->calibrate_store(dev, attr, buf, count);
> + cyapa_disable_irq_for_cmd(cyapa);
> + }
> +
> + mutex_unlock(&cyapa->state_sync_lock);
> + return error < 0 ? error : count;
> +}
> +
> +static ssize_t cyapa_show_baseline(struct device *dev,
> + struct device_attribute *attr, char *buf)
> +{
> + struct cyapa *cyapa = dev_get_drvdata(dev);
> + ssize_t error;
> +
> + error = mutex_lock_interruptible(&cyapa->state_sync_lock);
> + if (error)
> + return error;
> +
> + if (!cyapa->ops->show_baseline) {
> + dev_err(dev, "Calibrate operation not supported.\n");
> + error = -ENOTSUPP;
> + } else {
> + cyapa_enable_irq_for_cmd(cyapa);
> + error = cyapa->ops->show_baseline(dev, attr, buf);
> + cyapa_disable_irq_for_cmd(cyapa);
> + }
> +
> + mutex_unlock(&cyapa->state_sync_lock);
> + return error;
> +}
> +
> +static char *cyapa_state_to_string(struct cyapa *cyapa)
> +{
> + switch (cyapa->state) {
> + case CYAPA_STATE_BL_BUSY:
> + return "bootloader busy";
> + case CYAPA_STATE_BL_IDLE:
> + return "bootloader idle";
> + case CYAPA_STATE_BL_ACTIVE:
> + return "bootloader active";
> + case CYAPA_STATE_GEN5_BL:
> + return "bootloader";
> + case CYAPA_STATE_OP:
> + case CYAPA_STATE_GEN5_APP:
> + return "operational"; /* Normal valid state. */
> + default:
> + return "invalid mode";
> + }
> +}
> +
> +static ssize_t cyapa_show_mode(struct device *dev,
> + struct device_attribute *attr, char *buf)
> +{
> + struct cyapa *cyapa = dev_get_drvdata(dev);
> + int size;
> + int error;
> +
> + error = mutex_lock_interruptible(&cyapa->state_sync_lock);
> + if (error)
> + return error;
> +
> + size = scnprintf(buf, PAGE_SIZE, "gen%d %s\n",
> + cyapa->gen, cyapa_state_to_string(cyapa));
> +
> + mutex_unlock(&cyapa->state_sync_lock);
> + return size;
> +}
> +
> +static DEVICE_ATTR(firmware_version, S_IRUGO, cyapa_show_fm_ver, NULL);
> +static DEVICE_ATTR(product_id, S_IRUGO, cyapa_show_product_id, NULL);
> +static DEVICE_ATTR(update_fw, S_IWUSR, NULL, cyapa_update_fw_store);
> +static DEVICE_ATTR(baseline, S_IRUGO, cyapa_show_baseline, NULL);
> +static DEVICE_ATTR(calibrate, S_IWUSR, NULL, cyapa_calibrate_store);
> +static DEVICE_ATTR(mode, S_IRUGO, cyapa_show_mode, NULL);
> +
> +static struct attribute *cyapa_sysfs_entries[] = {
> + &dev_attr_firmware_version.attr,
> + &dev_attr_product_id.attr,
> + &dev_attr_update_fw.attr,
> + &dev_attr_baseline.attr,
> + &dev_attr_calibrate.attr,
> + &dev_attr_mode.attr,
> + NULL,
> +};
> +
> +static const struct attribute_group cyapa_sysfs_group = {
> + .attrs = cyapa_sysfs_entries,
> +};
> +
> +static void cyapa_remove_sysfs_group(void *data)
> +{
> + struct cyapa *cyapa = data;
> +
> + sysfs_remove_group(&cyapa->client->dev.kobj, &cyapa_sysfs_group);
> +}
> +
> static int cyapa_probe(struct i2c_client *client,
> const struct i2c_device_id *dev_id)
> {
> @@ -822,6 +1136,19 @@ static int cyapa_probe(struct i2c_client *client,
> return error;
> }
>
> + error = sysfs_create_group(&client->dev.kobj, &cyapa_sysfs_group);
> + if (error) {
> + dev_err(dev, "failed to create sysfs entries: %d\n", error);
> + return error;
> + }
> +
> + error = devm_add_action(dev, cyapa_remove_sysfs_group, cyapa);
> + if (error) {
> + cyapa_remove_sysfs_group(cyapa);
> + dev_err(dev, "failed to add sysfs cleanup action: %d\n", error);
> + return error;
> + }
> +
> #ifdef CONFIG_PM_SLEEP
> if (device_can_wakeup(dev)) {
> error = sysfs_merge_group(&client->dev.kobj,
> --
> 1.9.1
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
--
- Jeremiah Mahler
^ permalink raw reply
* Re: [PATCH v15 02/12] input: cyapa: add gen5 trackpad device basic functions support
From: Jeremiah Mahler @ 2014-12-15 14:10 UTC (permalink / raw)
To: Dudley Du; +Cc: dmitry.torokhov, rydberg, bleung, linux-input, linux-kernel
In-Reply-To: <1418624603-19054-3-git-send-email-dudley.dulixin@gmail.com>
Dudley,
On Mon, Dec 15, 2014 at 02:23:13PM +0800, Dudley Du wrote:
> Based on the cyapa core, add the gen5 trackpad device's basic functions
> supported, so gen5 trackpad device can work with kernel input system.
> And also based on the state parse interface, the cyapa driver can
> automatically determine the attached is gen3 or gen5 protocol trackpad
> device, then set the correct protocol to work with the attached
> trackpad device.
> TEST=test on Chromebooks.
>
> Signed-off-by: Dudley Du <dudley.dulixin@gmail.com>
> ---
> drivers/input/mouse/Makefile | 2 +-
> drivers/input/mouse/cyapa.c | 13 +
> drivers/input/mouse/cyapa.h | 1 +
> drivers/input/mouse/cyapa_gen5.c | 1660 ++++++++++++++++++++++++++++++++++++++
> 4 files changed, 1675 insertions(+), 1 deletion(-)
> create mode 100644 drivers/input/mouse/cyapa_gen5.c
>
> diff --git a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile
> index 8bd950d..8a9c98e 100644
> --- a/drivers/input/mouse/Makefile
> +++ b/drivers/input/mouse/Makefile
> @@ -24,7 +24,7 @@ obj-$(CONFIG_MOUSE_SYNAPTICS_I2C) += synaptics_i2c.o
> obj-$(CONFIG_MOUSE_SYNAPTICS_USB) += synaptics_usb.o
> obj-$(CONFIG_MOUSE_VSXXXAA) += vsxxxaa.o
>
> -cyapatp-objs := cyapa.o cyapa_gen3.o
> +cyapatp-objs := cyapa.o cyapa_gen3.o cyapa_gen5.o
> psmouse-objs := psmouse-base.o synaptics.o focaltech.o
>
> psmouse-$(CONFIG_MOUSE_PS2_ALPS) += alps.o
> diff --git a/drivers/input/mouse/cyapa.c b/drivers/input/mouse/cyapa.c
> index ae1df15..d4560a3 100644
> --- a/drivers/input/mouse/cyapa.c
> +++ b/drivers/input/mouse/cyapa.c
> @@ -157,6 +157,14 @@ static int cyapa_get_state(struct cyapa *cyapa)
> if (!error)
> goto out_detected;
> }
> + if ((cyapa->gen == CYAPA_GEN_UNKNOWN ||
> + cyapa->gen == CYAPA_GEN5) &&
> + !smbus && even_addr) {
> + error = cyapa_gen5_ops.state_parse(cyapa,
> + status, BL_STATUS_SIZE);
> + if (!error)
> + goto out_detected;
> + }
>
> /*
> * Write 0x00 0x00 to trackpad device to force update its
> @@ -240,6 +248,9 @@ static int cyapa_check_is_operational(struct cyapa *cyapa)
> return error;
>
> switch (cyapa->gen) {
> + case CYAPA_GEN5:
> + cyapa->ops = &cyapa_gen5_ops;
> + break;
> case CYAPA_GEN3:
> cyapa->ops = &cyapa_gen3_ops;
> break;
> @@ -476,6 +487,8 @@ static int cyapa_initialize(struct cyapa *cyapa)
>
> if (cyapa_gen3_ops.initialize)
> error = cyapa_gen3_ops.initialize(cyapa);
> + if (!error && cyapa_gen5_ops.initialize)
> + error = cyapa_gen5_ops.initialize(cyapa);
> if (error)
> return error;
>
> diff --git a/drivers/input/mouse/cyapa.h b/drivers/input/mouse/cyapa.h
> index 709ad47..d7d4f11 100644
> --- a/drivers/input/mouse/cyapa.h
> +++ b/drivers/input/mouse/cyapa.h
> @@ -312,5 +312,6 @@ u16 cyapa_pwr_cmd_to_sleep_time(u8 pwr_mode);
>
> extern const char product_id[];
> extern const struct cyapa_dev_ops cyapa_gen3_ops;
> +extern const struct cyapa_dev_ops cyapa_gen5_ops;
>
> #endif
> diff --git a/drivers/input/mouse/cyapa_gen5.c b/drivers/input/mouse/cyapa_gen5.c
> new file mode 100644
> index 0000000..1ac264d
> --- /dev/null
> +++ b/drivers/input/mouse/cyapa_gen5.c
> @@ -0,0 +1,1660 @@
> +/*
> + * Cypress APA trackpad with I2C interface
> + *
> + * Author: Dudley Du <dudl@cypress.com>
> + *
> + * Copyright (C) 2014 Cypress Semiconductor, Inc.
> + *
> + * This file is subject to the terms and conditions of the GNU General Public
> + * License. See the file COPYING in the main directory of this archive for
> + * more details.
> + */
> +
> +#include <linux/delay.h>
> +#include <linux/i2c.h>
> +#include <linux/input.h>
> +#include <linux/input/mt.h>
> +#include <linux/mutex.h>
> +#include <linux/completion.h>
> +#include <linux/slab.h>
> +#include <linux/unaligned/access_ok.h>
> +#include "cyapa.h"
> +
> +
> +/* Macro of Gen5 */
> +#define RECORD_EVENT_NONE 0
> +#define RECORD_EVENT_TOUCHDOWN 1
> +#define RECORD_EVENT_DISPLACE 2
> +#define RECORD_EVENT_LIFTOFF 3
> +
> +#define CYAPA_TSG_FLASH_MAP_BLOCK_SIZE 0x80
> +#define CYAPA_TSG_IMG_FW_HDR_SIZE 13
> +#define CYAPA_TSG_FW_ROW_SIZE (CYAPA_TSG_FLASH_MAP_BLOCK_SIZE)
> +#define CYAPA_TSG_IMG_START_ROW_NUM 0x002e
> +#define CYAPA_TSG_IMG_END_ROW_NUM 0x01fe
> +#define CYAPA_TSG_IMG_APP_INTEGRITY_ROW_NUM 0x01ff
> +#define CYAPA_TSG_IMG_MAX_RECORDS (CYAPA_TSG_IMG_END_ROW_NUM - \
> + CYAPA_TSG_IMG_START_ROW_NUM + 1 + 1)
> +#define CYAPA_TSG_IMG_READ_SIZE (CYAPA_TSG_FLASH_MAP_BLOCK_SIZE / 2)
> +#define CYAPA_TSG_START_OF_APPLICATION 0x1700
> +#define CYAPA_TSG_APP_INTEGRITY_SIZE 60
> +#define CYAPA_TSG_FLASH_MAP_METADATA_SIZE 60
> +#define CYAPA_TSG_BL_KEY_SIZE 8
> +
> +/* Macro definitions for Gen5 trackpad device. */
> +#define GEN5_TOUCH_REPORT_HEAD_SIZE 7
> +#define GEN5_TOUCH_REPORT_MAX_SIZE 127
> +#define GEN5_BTN_REPORT_HEAD_SIZE 6
> +#define GEN5_BTN_REPORT_MAX_SIZE 14
> +#define GEN5_WAKEUP_EVENT_SIZE 4
> +#define GEN5_RAW_DATA_HEAD_SIZE 24
> +
> +#define GEN5_BL_CMD_REPORT_ID 0x40
> +#define GEN5_BL_RESP_REPORT_ID 0x30
> +#define GEN5_APP_CMD_REPORT_ID 0x2f
> +#define GEN5_APP_RESP_REPORT_ID 0x1f
> +
> +#define GEN5_APP_DEEP_SLEEP_REPORT_ID 0xf0
> +#define GEN5_DEEP_SLEEP_RESP_LENGTH 5
> +
> +#define GEN5_PARAMETER_ACT_INTERVL_ID 0x4d
> +#define GEN5_PARAMETER_ACT_INTERVL_SIZE 1
> +#define GEN5_PARAMETER_ACT_LFT_INTERVL_ID 0x4f
> +#define GEN5_PARAMETER_ACT_LFT_INTERVL_SIZE 2
> +#define GEN5_PARAMETER_LP_INTRVL_ID 0x4c
> +#define GEN5_PARAMETER_LP_INTRVL_SIZE 2
> +
> +#define GEN5_PARAMETER_DISABLE_PIP_REPORT 0x08
> +
> +#define GEN5_POWER_STATE_ACTIVE 0x01
> +#define GEN5_POWER_STATE_LOOK_FOR_TOUCH 0x02
> +#define GEN5_POWER_STATE_READY 0x03
> +#define GEN5_POWER_STATE_IDLE 0x04
> +#define GEN5_POWER_STATE_BTN_ONLY 0x05
> +#define GEN5_POWER_STATE_OFF 0x06
> +
> +#define GEN5_DEEP_SLEEP_STATE_MASK 0x03
> +#define GEN5_DEEP_SLEEP_STATE_ON 0x00
> +#define GEN5_DEEP_SLEEP_STATE_OFF 0x01
> +
> +#define GEN5_DEEP_SLEEP_OPCODE 0x08
> +#define GEN5_DEEP_SLEEP_OPCODE_MASK 0x0f
> +
> +#define GEN5_POWER_READY_MAX_INTRVL_TIME 50 /* Unit: ms */
> +#define GEN5_POWER_IDLE_MAX_INTRVL_TIME 250 /* Unit: ms */
> +
> +#define GEN5_CMD_REPORT_ID_OFFSET 4
> +
> +#define GEN5_RESP_REPORT_ID_OFFSET 2
> +#define GEN5_RESP_RSVD_OFFSET 3
> +#define GEN5_RESP_RSVD_KEY 0x00
> +#define GEN5_RESP_BL_SOP_OFFSET 4
> +#define GEN5_SOP_KEY 0x01 /* Start of Packet */
> +#define GEN5_EOP_KEY 0x17 /* End of Packet */
> +#define GEN5_RESP_APP_CMD_OFFSET 4
> +#define GET_GEN5_CMD_CODE(reg) ((reg) & 0x7f)
> +
> +#define VALID_CMD_RESP_HEADER(resp, cmd) \
> + (((resp)[GEN5_RESP_REPORT_ID_OFFSET] == GEN5_APP_RESP_REPORT_ID) && \
> + ((resp)[GEN5_RESP_RSVD_OFFSET] == GEN5_RESP_RSVD_KEY) && \
> + (GET_GEN5_CMD_CODE((resp)[GEN5_RESP_APP_CMD_OFFSET]) == (cmd)))
> +
> +#define GEN5_MIN_BL_CMD_LENGTH 13
> +#define GEN5_MIN_BL_RESP_LENGTH 11
> +#define GEN5_MIN_APP_CMD_LENGTH 7
> +#define GEN5_MIN_APP_RESP_LENGTH 5
> +#define GEN5_UNSUPPORTED_CMD_RESP_LENGTH 6
> +
> +#define GEN5_RESP_LENGTH_OFFSET 0x00
> +#define GEN5_RESP_LENGTH_SIZE 2
> +
> +#define GEN5_HID_DESCRIPTOR_SIZE 32
> +#define GEN5_BL_HID_REPORT_ID 0xff
> +#define GEN5_APP_HID_REPORT_ID 0xf7
> +#define GEN5_BL_MAX_OUTPUT_LENGTH 0x0100
> +#define GEN5_APP_MAX_OUTPUT_LENGTH 0x00fe
> +
> +#define GEN5_BL_REPORT_DESCRIPTOR_SIZE 0x1d
> +#define GEN5_BL_REPORT_DESCRIPTOR_ID 0xfe
> +#define GEN5_APP_REPORT_DESCRIPTOR_SIZE 0xee
> +#define GEN5_APP_CONTRACT_REPORT_DESCRIPTOR_SIZE 0xfa
> +#define GEN5_APP_REPORT_DESCRIPTOR_ID 0xf6
> +
> +#define GEN5_TOUCH_REPORT_ID 0x01
> +#define GEN5_BTN_REPORT_ID 0x03
> +#define GEN5_WAKEUP_EVENT_REPORT_ID 0x04
> +#define GEN5_OLD_PUSH_BTN_REPORT_ID 0x05
> +#define GEN5_PUSH_BTN_REPORT_ID 0x06
> +
> +#define GEN5_CMD_COMPLETE_SUCCESS(status) ((status) == 0x00)
> +
> +#define GEN5_BL_INITIATE_RESP_LEN 11
> +#define GEN5_BL_FAIL_EXIT_RESP_LEN 11
> +#define GEN5_BL_FAIL_EXIT_STATUS_CODE 0x0c
> +#define GEN5_BL_VERIFY_INTEGRITY_RESP_LEN 12
> +#define GEN5_BL_INTEGRITY_CHEKC_PASS 0x00
> +#define GEN5_BL_BLOCK_WRITE_RESP_LEN 11
> +#define GEN5_BL_READ_APP_INFO_RESP_LEN 31
> +#define GEN5_CMD_CALIBRATE 0x28
> +#define CYAPA_SENSING_MODE_MUTUAL_CAP_FINE 0x00
> +#define CYAPA_SENSING_MODE_SELF_CAP 0x02
> +
> +#define GEN5_CMD_RETRIEVE_DATA_STRUCTURE 0x24
> +#define GEN5_RETRIEVE_MUTUAL_PWC_DATA 0x00
> +#define GEN5_RETRIEVE_SELF_CAP_PWC_DATA 0x01
> +
> +#define GEN5_RETRIEVE_DATA_ELEMENT_SIZE_MASK 0x07
> +
> +#define GEN5_CMD_EXECUTE_PANEL_SCAN 0x2a
> +#define GEN5_CMD_RETRIEVE_PANEL_SCAN 0x2b
> +#define GEN5_PANEL_SCAN_MUTUAL_RAW_DATA 0x00
> +#define GEN5_PANEL_SCAN_MUTUAL_BASELINE 0x01
> +#define GEN5_PANEL_SCAN_MUTUAL_DIFFCOUNT 0x02
> +#define GEN5_PANEL_SCAN_SELF_RAW_DATA 0x03
> +#define GEN5_PANEL_SCAN_SELF_BASELINE 0x04
> +#define GEN5_PANEL_SCAN_SELF_DIFFCOUNT 0x05
> +
> +#define GEN5_PWC_DATA_ELEMENT_SIZE_MASK 0x07
> +
> +#define GEN5_NUMBER_OF_TOUCH_OFFSET 5
> +#define GEN5_NUMBER_OF_TOUCH_MASK 0x1f
> +#define GEN5_BUTTONS_OFFSET 5
> +#define GEN5_BUTTONS_MASK 0x0f
> +#define GEN5_GET_EVENT_ID(reg) (((reg) >> 5) & 0x03)
> +#define GEN5_GET_TOUCH_ID(reg) ((reg) & 0x1f)
> +
> +#define GEN5_PRODUCT_FAMILY_MASK 0xf000
> +#define GEN5_PRODUCT_FAMILY_TRACKPAD 0x1000
> +
> +#define TSG_INVALID_CMD 0xff
> +
> +struct cyapa_gen5_touch_record {
> + /*
> + * Bit 7 - 3: reserved
> + * Bit 2 - 0: touch type;
> + * 0 : standard finger;
> + * 1 - 15 : reserved.
> + */
> + u8 touch_type;
> +
> + /*
> + * Bit 7: indicates touch liftoff status.
> + * 0 : touch is currently on the panel.
> + * 1 : touch record indicates a liftoff.
> + * Bit 6 - 5: indicates an event associated with this touch instance
> + * 0 : no event
> + * 1 : touchdown
> + * 2 : significant displacement (> active distance)
> + * 3 : liftoff (record reports last known coordinates)
> + * Bit 4 - 0: An arbitrary ID tag associated with a finger
> + * to allow tracking a touch as it moves around the panel.
> + */
> + u8 touch_tip_event_id;
> +
> + /* Bit 7 - 0 of X-axis corrinate of the touch in pixel. */
coordinate
and more below...
> + u8 x_lo;
> +
> + /* Bit 15 - 8 of X-axis corrinate of the touch in pixel. */
> + u8 x_hi;
> +
> + /* Bit 7 - 0 of Y-axis corrinate of the touch in pixel. */
> + u8 y_lo;
> +
> + /* Bit 15 - 8 of Y-axis corrinate of the touch in pixel. */
> + u8 y_hi;
> +
> + /* Touch intensity in counts, pressure value. */
> + u8 z;
> +
> + /*
> + * The length of the major axis of the ellipse of contact between
> + * the finger and the panel (ABS_MT_TOUCH_MAJOR).
> + */
> + u8 major_axis_len;
> +
> + /*
> + * The length of the minor axis of the ellipse of contact between
> + * the finger and the panel (ABS_MT_TOUCH_MINOR).
> + */
> + u8 minor_axis_len;
> +
> + /*
> + * The length of the major axis of the approaching tool.
> + * (ABS_MT_WIDTH_MAJOR)
> + */
> + u8 major_tool_len;
> +
> + /*
> + * The length of the minor axis of the approaching tool.
> + * (ABS_MT_WIDTH_MINOR)
> + */
> + u8 minor_tool_len;
> +
> + /*
> + * The angle between the panel vertical axis and
> + * the major axis of the contact ellipse. This value is an 8-bit
> + * signed integer. The range is -127 to +127 (corresponding to
> + * -90 degree and +90 degree respectively).
> + * The positive direction is clockwise from the vertical axis.
> + * If the ellipse of contact degenerates into a circle,
> + * orientation is reported as 0.
> + */
> + u8 orientation;
> +} __packed;
> +
> +struct cyapa_gen5_report_data {
> + u8 report_head[GEN5_TOUCH_REPORT_HEAD_SIZE];
> + struct cyapa_gen5_touch_record touch_records[10];
> +} __packed;
> +
> +struct cyapa_tsg_bin_image_data_record {
> + u8 flash_array_id;
> + __be16 row_number;
> + /* The number of bytes of flash data contained in this record. */
> + __be16 record_len;
> + /* The flash program data. */
> + u8 record_data[CYAPA_TSG_FW_ROW_SIZE];
> +} __packed;
> +
> +struct cyapa_tsg_bin_image {
> + struct cyapa_tsg_bin_image_head image_head;
> + struct cyapa_tsg_bin_image_data_record records[0];
> +} __packed;
> +
> +/* Variables to record latest gen5 trackpad power states. */
> +#define GEN5_DEV_SET_PWR_STATE(cyapa, s) ((cyapa)->dev_pwr_mode = (s))
> +#define GEN5_DEV_GET_PWR_STATE(cyapa) ((cyapa)->dev_pwr_mode)
> +#define GEN5_DEV_SET_SLEEP_TIME(cyapa, t) ((cyapa)->dev_sleep_time = (t))
> +#define GEN5_DEV_GET_SLEEP_TIME(cyapa) ((cyapa)->dev_sleep_time)
> +#define GEN5_DEV_UNINIT_SLEEP_TIME(cyapa) \
> + (((cyapa)->dev_sleep_time) == UNINIT_SLEEP_TIME)
> +
> +
> +static int cyapa_gen5_initialize(struct cyapa *cyapa)
> +{
> + struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5;
> +
> + init_completion(&gen5_pip->cmd_ready);
> + atomic_set(&gen5_pip->cmd_issued, 0);
> + mutex_init(&gen5_pip->cmd_lock);
> +
> + gen5_pip->resp_sort_func = NULL;
> + gen5_pip->in_progress_cmd = TSG_INVALID_CMD;
> + gen5_pip->resp_data = NULL;
> + gen5_pip->resp_len = NULL;
> +
> + cyapa->dev_pwr_mode = UNINIT_PWR_MODE;
> + cyapa->dev_sleep_time = UNINIT_SLEEP_TIME;
> +
> + return 0;
> +}
> +
> +/* Return negative errno, or else the number of bytes read. */
> +static ssize_t cyapa_i2c_pip_read(struct cyapa *cyapa, u8 *buf, size_t size)
> +{
> + int ret;
> +
> + if (size == 0)
> + return 0;
> +
> + if (!buf || size > CYAPA_REG_MAP_SIZE)
> + return -EINVAL;
> +
> + ret = i2c_master_recv(cyapa->client, buf, size);
> +
> + if (ret != size)
> + return (ret < 0) ? ret : -EIO;
> +
> + return size;
> +}
> +
> +/**
> + * Return a negative errno code else zero on success.
> + */
> +static ssize_t cyapa_i2c_pip_write(struct cyapa *cyapa, u8 *buf, size_t size)
> +{
> + int ret;
> +
> + if (!buf || !size)
> + return -EINVAL;
> +
> + ret = i2c_master_send(cyapa->client, buf, size);
> +
> + if (ret != size)
> + return (ret < 0) ? ret : -EIO;
> +
> + return 0;
> +}
> +
> +/**
> + * This function is aimed to dump all not read data in Gen5 trackpad
> + * before send any command, otherwise, the interrupt line will be blocked.
> + */
> +static int cyapa_empty_pip_output_data(struct cyapa *cyapa,
> + u8 *buf, int *len, cb_sort func)
> +{
> + struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5;
> + int length;
> + int report_count;
> + int empty_count;
> + int buf_len;
> + int error;
> +
> + buf_len = 0;
> + if (len) {
> + buf_len = (*len < CYAPA_REG_MAP_SIZE) ?
> + *len : CYAPA_REG_MAP_SIZE;
> + *len = 0;
> + }
> +
> + report_count = 8; /* max 7 pending data before command response data */
> + empty_count = 0;
> + do {
> + /*
> + * Depnding on testing in cyapa driver, there are max 5 "02 00"
Depending
> + * packets between two valid buffered data report in firmware.
> + * So in order to dump all buffered data out and
> + * make interrupt line release for reassert again,
> + * we must set the empty_count check value bigger than 5 to
> + * make it work. Otherwise, in some situation,
> + * the interrupt line may unable to reactive again,
> + * which will cause trackpad device unable to
> + * report data any more.
> + * for example, it may happen in EFT and ESD testing.
> + */
> + if (empty_count > 5)
> + return 0;
> +
> + error = cyapa_i2c_pip_read(cyapa, gen5_pip->empty_buf,
> + GEN5_RESP_LENGTH_SIZE);
> + if (error < 0)
> + return error;
> +
> + length = get_unaligned_le16(gen5_pip->empty_buf);
> + if (length == GEN5_RESP_LENGTH_SIZE) {
> + empty_count++;
> + continue;
> + } else if (length > CYAPA_REG_MAP_SIZE) {
> + /* Should not happen */
> + return -EINVAL;
> + } else if (length == 0) {
> + /* Application or bootloader launch data polled out. */
> + length = GEN5_RESP_LENGTH_SIZE;
> + if (buf && buf_len && func &&
> + func(cyapa, gen5_pip->empty_buf, length)) {
> + length = min(buf_len, length);
> + memcpy(buf, gen5_pip->empty_buf, length);
> + *len = length;
> + /* Response found, success. */
> + return 0;
> + }
> + continue;
> + }
> +
> + error = cyapa_i2c_pip_read(cyapa, gen5_pip->empty_buf, length);
> + if (error < 0)
> + return error;
> +
> + report_count--;
> + empty_count = 0;
> + length = get_unaligned_le16(gen5_pip->empty_buf);
> + if (length <= GEN5_RESP_LENGTH_SIZE) {
> + empty_count++;
> + } else if (buf && buf_len && func &&
> + func(cyapa, gen5_pip->empty_buf, length)) {
> + length = min(buf_len, length);
> + memcpy(buf, gen5_pip->empty_buf, length);
> + *len = length;
> + /* Response found, success. */
> + return 0;
> + }
> +
> + error = -EINVAL;
> + } while (report_count);
> +
> + return error;
> +}
> +
> +static int cyapa_do_i2c_pip_cmd_irq_sync(
> + struct cyapa *cyapa,
> + u8 *cmd, size_t cmd_len,
> + unsigned long timeout)
> +{
> + int error;
> + struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5;
> +
> + /* Wait for interrupt to set ready completion */
> + init_completion(&gen5_pip->cmd_ready);
> +
> + atomic_inc(&gen5_pip->cmd_issued);
> + error = cyapa_i2c_pip_write(cyapa, cmd, cmd_len);
> + if (error) {
> + atomic_dec(&gen5_pip->cmd_issued);
> + return (error < 0) ? error : -EIO;
> + }
> +
> + /* Wait for interrupt to indicate command is completed. */
> + timeout = wait_for_completion_timeout(&gen5_pip->cmd_ready,
> + msecs_to_jiffies(timeout));
> + if (timeout == 0) {
> + atomic_dec(&gen5_pip->cmd_issued);
> + return -ETIMEDOUT;
> + }
> +
> + return 0;
> +}
> +
> +static int cyapa_do_i2c_pip_cmd_polling(
> + struct cyapa *cyapa,
> + u8 *cmd, size_t cmd_len,
> + u8 *resp_data, int *resp_len,
> + unsigned long timeout,
> + cb_sort func)
> +{
> + int error;
> + int tries;
> + int length;
> + struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5;
> +
> + atomic_inc(&gen5_pip->cmd_issued);
> + error = cyapa_i2c_pip_write(cyapa, cmd, cmd_len);
> + if (error) {
> + atomic_dec(&gen5_pip->cmd_issued);
> + return error < 0 ? error : -EIO;
> + }
> +
> + tries = timeout / 5;
> + length = resp_len ? *resp_len : 0;
> + if (resp_data && resp_len && length != 0 && func) {
> + do {
> + usleep_range(3000, 5000);
> + *resp_len = length;
> + error = cyapa_empty_pip_output_data(cyapa,
> + resp_data, resp_len, func);
> + if (error || *resp_len == 0)
> + continue;
> + else
> + break;
> + } while (--tries > 0);
> + if ((error || *resp_len == 0) || tries <= 0)
> + error = error ? error : -ETIMEDOUT;
> + }
> +
> + atomic_dec(&gen5_pip->cmd_issued);
> + return error;
> +}
> +
> +static int cyapa_i2c_pip_cmd_irq_sync(
> + struct cyapa *cyapa,
> + u8 *cmd, int cmd_len,
> + u8 *resp_data, int *resp_len,
> + unsigned long timeout,
> + cb_sort func,
> + bool irq_mode)
> +{
> + int error;
> + struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5;
> +
> + if (!cmd || !cmd_len)
> + return -EINVAL;
> +
> + /* Commands must be serialized. */
> + error = mutex_lock_interruptible(&gen5_pip->cmd_lock);
> + if (error)
> + return error;
> +
> + gen5_pip->resp_sort_func = func;
> + gen5_pip->resp_data = resp_data;
> + gen5_pip->resp_len = resp_len;
> +
> + if (cmd_len >= GEN5_MIN_APP_CMD_LENGTH &&
> + cmd[4] == GEN5_APP_CMD_REPORT_ID) {
> + /* Application command */
> + gen5_pip->in_progress_cmd = cmd[6] & 0x7f;
> + } else if (cmd_len >= GEN5_MIN_BL_CMD_LENGTH &&
> + cmd[4] == GEN5_BL_CMD_REPORT_ID) {
> + /* Bootloader command */
> + gen5_pip->in_progress_cmd = cmd[7];
> + }
> +
> + /* Send command data, wait and read output response data's length. */
> + if (irq_mode) {
> + gen5_pip->is_irq_mode = true;
> + error = cyapa_do_i2c_pip_cmd_irq_sync(cyapa, cmd, cmd_len,
> + timeout);
> + if (error == -ETIMEDOUT && resp_data &&
> + resp_len && *resp_len != 0 && func) {
> + /*
> + * For some old version, there was no interrupt for
> + * the command response data, so need to poll here
> + * to try to get the response data.
> + */
> + error = cyapa_empty_pip_output_data(cyapa,
> + resp_data, resp_len, func);
> + if (error || *resp_len == 0)
> + error = error ? error : -ETIMEDOUT;
> + }
> + } else {
> + gen5_pip->is_irq_mode = false;
> + error = cyapa_do_i2c_pip_cmd_polling(cyapa, cmd, cmd_len,
> + resp_data, resp_len, timeout, func);
> + }
> +
> + gen5_pip->resp_sort_func = NULL;
> + gen5_pip->resp_data = NULL;
> + gen5_pip->resp_len = NULL;
> + gen5_pip->in_progress_cmd = TSG_INVALID_CMD;
> +
> + mutex_unlock(&gen5_pip->cmd_lock);
> + return error;
> +}
> +
> +static bool cyapa_gen5_sort_tsg_pip_bl_resp_data(struct cyapa *cyapa,
> + u8 *data, int len)
> +{
> + if (!data || len < GEN5_MIN_BL_RESP_LENGTH)
> + return false;
> +
> + /* Bootloader input report id 30h */
> + if (data[GEN5_RESP_REPORT_ID_OFFSET] == GEN5_BL_RESP_REPORT_ID &&
> + data[GEN5_RESP_RSVD_OFFSET] == GEN5_RESP_RSVD_KEY &&
> + data[GEN5_RESP_BL_SOP_OFFSET] == GEN5_SOP_KEY)
> + return true;
> +
> + return false;
> +}
> +
> +static bool cyapa_gen5_sort_tsg_pip_app_resp_data(struct cyapa *cyapa,
> + u8 *data, int len)
> +{
> + int resp_len;
> + struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5;
> +
> + if (!data || len < GEN5_MIN_APP_RESP_LENGTH)
> + return false;
> +
> + if (data[GEN5_RESP_REPORT_ID_OFFSET] == GEN5_APP_RESP_REPORT_ID &&
> + data[GEN5_RESP_RSVD_OFFSET] == GEN5_RESP_RSVD_KEY) {
> + resp_len = get_unaligned_le16(&data[GEN5_RESP_LENGTH_OFFSET]);
> + if (GET_GEN5_CMD_CODE(data[GEN5_RESP_APP_CMD_OFFSET]) == 0x00 &&
> + resp_len == GEN5_UNSUPPORTED_CMD_RESP_LENGTH &&
> + data[5] == gen5_pip->in_progress_cmd) {
> + /* Unsupported command code */
> + return false;
> + } else if (GET_GEN5_CMD_CODE(data[GEN5_RESP_APP_CMD_OFFSET]) ==
> + gen5_pip->in_progress_cmd) {
> + /* Correct command response received */
> + return true;
> + }
> + }
> +
> + return false;
> +}
> +
> +static bool cyapa_gen5_sort_application_launch_data(struct cyapa *cyapa,
> + u8 *buf, int len)
> +{
> + if (buf == NULL || len < GEN5_RESP_LENGTH_SIZE)
> + return false;
> +
> + /*
> + * After reset or power on, trackpad device always sets to 0x00 0x00
> + * to indicate a reset or power on event.
> + */
> + if (buf[0] == 0 && buf[1] == 0)
> + return true;
> +
> + return false;
> +}
> +
> +static bool cyapa_gen5_sort_hid_descriptor_data(struct cyapa *cyapa,
> + u8 *buf, int len)
> +{
> + int resp_len;
> + int max_output_len;
> +
> + /* Check hid descriptor. */
> + if (len != GEN5_HID_DESCRIPTOR_SIZE)
> + return false;
> +
> + resp_len = get_unaligned_le16(&buf[GEN5_RESP_LENGTH_OFFSET]);
> + max_output_len = get_unaligned_le16(&buf[16]);
> + if (resp_len == GEN5_HID_DESCRIPTOR_SIZE) {
> + if (buf[GEN5_RESP_REPORT_ID_OFFSET] == GEN5_BL_HID_REPORT_ID &&
> + max_output_len == GEN5_BL_MAX_OUTPUT_LENGTH) {
> + /* BL mode HID Descriptor */
> + return true;
> + } else if (buf[2] == GEN5_APP_HID_REPORT_ID &&
> + max_output_len == GEN5_APP_MAX_OUTPUT_LENGTH) {
> + /* APP mode HID Descriptor */
> + return true;
> + }
> + }
> +
> + return false;
> +}
> +
> +static bool cyapa_gen5_sort_deep_sleep_data(struct cyapa *cyapa,
> + u8 *buf, int len)
> +{
> + if (len == GEN5_DEEP_SLEEP_RESP_LENGTH &&
> + buf[GEN5_RESP_REPORT_ID_OFFSET] ==
> + GEN5_APP_DEEP_SLEEP_REPORT_ID &&
> + (buf[4] & GEN5_DEEP_SLEEP_OPCODE_MASK) ==
> + GEN5_DEEP_SLEEP_OPCODE)
> + return true;
> + return false;
> +}
> +
> +static int gen5_idle_state_parse(struct cyapa *cyapa)
> +{
> + int ret;
> + int error;
> + int length;
> + u8 cmd[2];
> + u8 resp_data[GEN5_HID_DESCRIPTOR_SIZE];
> + int max_output_len;
> +
> + /*
> + * Dump all buffered data firstly for the situation
> + * when the trackpad is just power on the cyapa go here.
> + */
> + cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
> +
> + memset(resp_data, 0, sizeof(resp_data));
> + ret = cyapa_i2c_pip_read(cyapa, resp_data, 3);
> + if (ret != 3)
> + return ret < 0 ? ret : -EIO;
> +
> + length = get_unaligned_le16(&resp_data[GEN5_RESP_LENGTH_OFFSET]);
> + if (length == GEN5_RESP_LENGTH_SIZE) {
> + /* Normal state of Gen5 with no data to respose */
> + cyapa->gen = CYAPA_GEN5;
> +
> + cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
> +
> + /* Read description from trackpad device */
> + cmd[0] = 0x01;
> + cmd[1] = 0x00;
> + length = GEN5_HID_DESCRIPTOR_SIZE;
> + error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
> + cmd, GEN5_RESP_LENGTH_SIZE,
> + resp_data, &length,
> + 300,
> + cyapa_gen5_sort_hid_descriptor_data,
> + false);
> + if (error)
> + return error;
> +
> + length = get_unaligned_le16(
> + &resp_data[GEN5_RESP_LENGTH_OFFSET]);
> + max_output_len = get_unaligned_le16(&resp_data[16]);
> + if ((length == GEN5_HID_DESCRIPTOR_SIZE ||
> + length == GEN5_RESP_LENGTH_SIZE) &&
> + (resp_data[GEN5_RESP_REPORT_ID_OFFSET] ==
> + GEN5_BL_HID_REPORT_ID) &&
> + max_output_len == GEN5_BL_MAX_OUTPUT_LENGTH) {
> + /* BL mode HID Description read */
> + cyapa->state = CYAPA_STATE_GEN5_BL;
> + } else if ((length == GEN5_HID_DESCRIPTOR_SIZE ||
> + length == GEN5_RESP_LENGTH_SIZE) &&
> + (resp_data[GEN5_RESP_REPORT_ID_OFFSET] ==
> + GEN5_APP_HID_REPORT_ID) &&
> + max_output_len == GEN5_APP_MAX_OUTPUT_LENGTH) {
> + /* APP mode HID Description read */
> + cyapa->state = CYAPA_STATE_GEN5_APP;
> + } else {
> + /* Should not happen!!! */
> + cyapa->state = CYAPA_STATE_NO_DEVICE;
> + }
> + }
> +
> + return 0;
> +}
> +
> +static int gen5_hid_description_header_parse(struct cyapa *cyapa, u8 *reg_data)
> +{
> + int ret;
> + int length;
> + u8 resp_data[32];
> + int max_output_len;
> +
> + /* 0x20 0x00 0xF7 is Gen5 Application HID Description Header;
> + * 0x20 0x00 0xFF is Gen5 Booloader HID Description Header.
> + *
> + * Must read HID Description content through out,
> + * otherwise Gen5 trackpad cannot response next command
> + * or report any touch or button data.
> + */
> + ret = cyapa_i2c_pip_read(cyapa, resp_data,
> + GEN5_HID_DESCRIPTOR_SIZE);
> + if (ret != GEN5_HID_DESCRIPTOR_SIZE)
> + return ret < 0 ? ret : -EIO;
> + length = get_unaligned_le16(&resp_data[GEN5_RESP_LENGTH_OFFSET]);
> + max_output_len = get_unaligned_le16(&resp_data[16]);
> + if (length == GEN5_RESP_LENGTH_SIZE) {
> + if (reg_data[GEN5_RESP_REPORT_ID_OFFSET] ==
> + GEN5_BL_HID_REPORT_ID) {
> + /*
> + * BL mode HID Description has been previously
> + * read out.
> + */
> + cyapa->gen = CYAPA_GEN5;
> + cyapa->state = CYAPA_STATE_GEN5_BL;
> + } else {
> + /*
> + * APP mode HID Description has been previously
> + * read out.
> + */
> + cyapa->gen = CYAPA_GEN5;
> + cyapa->state = CYAPA_STATE_GEN5_APP;
> + }
> + } else if (length == GEN5_HID_DESCRIPTOR_SIZE &&
> + resp_data[2] == GEN5_BL_HID_REPORT_ID &&
> + max_output_len == GEN5_BL_MAX_OUTPUT_LENGTH) {
> + /* BL mode HID Description read. */
> + cyapa->gen = CYAPA_GEN5;
> + cyapa->state = CYAPA_STATE_GEN5_BL;
> + } else if (length == GEN5_HID_DESCRIPTOR_SIZE &&
> + (resp_data[GEN5_RESP_REPORT_ID_OFFSET] ==
> + GEN5_APP_HID_REPORT_ID) &&
> + max_output_len == GEN5_APP_MAX_OUTPUT_LENGTH) {
> + /* APP mode HID Description read. */
> + cyapa->gen = CYAPA_GEN5;
> + cyapa->state = CYAPA_STATE_GEN5_APP;
> + } else {
> + /* Should not happen!!! */
> + cyapa->state = CYAPA_STATE_NO_DEVICE;
> + }
> +
> + return 0;
> +}
> +
> +static int gen5_report_data_header_parse(struct cyapa *cyapa, u8 *reg_data)
> +{
> + int length;
> +
> + length = get_unaligned_le16(®_data[GEN5_RESP_LENGTH_OFFSET]);
> + switch (reg_data[GEN5_RESP_REPORT_ID_OFFSET]) {
> + case GEN5_TOUCH_REPORT_ID:
> + if (length < GEN5_TOUCH_REPORT_HEAD_SIZE ||
> + length > GEN5_TOUCH_REPORT_MAX_SIZE)
> + return -EINVAL;
> + break;
> + case GEN5_BTN_REPORT_ID:
> + case GEN5_OLD_PUSH_BTN_REPORT_ID:
> + case GEN5_PUSH_BTN_REPORT_ID:
> + if (length < GEN5_BTN_REPORT_HEAD_SIZE ||
> + length > GEN5_BTN_REPORT_MAX_SIZE)
> + return -EINVAL;
> + break;
> + case GEN5_WAKEUP_EVENT_REPORT_ID:
> + if (length != GEN5_WAKEUP_EVENT_SIZE)
> + return -EINVAL;
> + break;
> + default:
> + return -EINVAL;
> + }
> +
> + cyapa->gen = CYAPA_GEN5;
> + cyapa->state = CYAPA_STATE_GEN5_APP;
> + return 0;
> +}
> +
> +static int gen5_cmd_resp_header_parse(struct cyapa *cyapa, u8 *reg_data)
> +{
> + int ret;
> + int length;
> + struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5;
> +
> + /*
> + * Must read report data through out,
> + * otherwise Gen5 trackpad cannot response next command
> + * or report any touch or button data.
> + */
> + length = get_unaligned_le16(®_data[GEN5_RESP_LENGTH_OFFSET]);
> + ret = cyapa_i2c_pip_read(cyapa, gen5_pip->empty_buf, length);
> + if (ret != length)
> + return ret < 0 ? ret : -EIO;
> +
> + if (length == GEN5_RESP_LENGTH_SIZE) {
> + /* Previous command has read the data through out. */
> + if (reg_data[GEN5_RESP_REPORT_ID_OFFSET] ==
> + GEN5_BL_RESP_REPORT_ID) {
> + /* Gen5 BL command response data detected */
> + cyapa->gen = CYAPA_GEN5;
> + cyapa->state = CYAPA_STATE_GEN5_BL;
> + } else {
> + /* Gen5 APP command response data detected */
> + cyapa->gen = CYAPA_GEN5;
> + cyapa->state = CYAPA_STATE_GEN5_APP;
> + }
> + } else if ((gen5_pip->empty_buf[GEN5_RESP_REPORT_ID_OFFSET] ==
> + GEN5_BL_RESP_REPORT_ID) &&
> + (gen5_pip->empty_buf[GEN5_RESP_RSVD_OFFSET] ==
> + GEN5_RESP_RSVD_KEY) &&
> + (gen5_pip->empty_buf[GEN5_RESP_BL_SOP_OFFSET] ==
> + GEN5_SOP_KEY) &&
> + (gen5_pip->empty_buf[length - 1] ==
> + GEN5_EOP_KEY)) {
> + /* Gen5 BL command response data detected */
> + cyapa->gen = CYAPA_GEN5;
> + cyapa->state = CYAPA_STATE_GEN5_BL;
> + } else if (gen5_pip->empty_buf[GEN5_RESP_REPORT_ID_OFFSET] ==
> + GEN5_APP_RESP_REPORT_ID &&
> + gen5_pip->empty_buf[GEN5_RESP_RSVD_OFFSET] ==
> + GEN5_RESP_RSVD_KEY) {
> + /* Gen5 APP command response data detected */
> + cyapa->gen = CYAPA_GEN5;
> + cyapa->state = CYAPA_STATE_GEN5_APP;
> + } else {
> + /* Should not happen!!! */
> + cyapa->state = CYAPA_STATE_NO_DEVICE;
> + }
> +
> + return 0;
> +}
> +
> +static int cyapa_gen5_state_parse(struct cyapa *cyapa, u8 *reg_data, int len)
> +{
> + int length;
> +
> + if (!reg_data || len < 3)
> + return -EINVAL;
> +
> + cyapa->state = CYAPA_STATE_NO_DEVICE;
> +
> + /* Parse based on Gen5 characteristic registers and bits */
> + length = get_unaligned_le16(®_data[GEN5_RESP_LENGTH_OFFSET]);
> + if (length == 0 || length == GEN5_RESP_LENGTH_SIZE) {
> + gen5_idle_state_parse(cyapa);
> + } else if (length == GEN5_HID_DESCRIPTOR_SIZE &&
> + (reg_data[2] == GEN5_BL_HID_REPORT_ID ||
> + reg_data[2] == GEN5_APP_HID_REPORT_ID)) {
> + gen5_hid_description_header_parse(cyapa, reg_data);
> + } else if ((length == GEN5_APP_REPORT_DESCRIPTOR_SIZE ||
> + length == GEN5_APP_CONTRACT_REPORT_DESCRIPTOR_SIZE) &&
> + reg_data[2] == GEN5_APP_REPORT_DESCRIPTOR_ID) {
> + /* 0xEE 0x00 0xF6 is Gen5 APP Report Description header. */
> + cyapa->gen = CYAPA_GEN5;
> + cyapa->state = CYAPA_STATE_GEN5_APP;
> + } else if (length == GEN5_BL_REPORT_DESCRIPTOR_SIZE &&
> + reg_data[2] == GEN5_BL_REPORT_DESCRIPTOR_ID) {
> + /* 0x1D 0x00 0xFE is Gen5 BL Report Descriptior header. */
> + cyapa->gen = CYAPA_GEN5;
> + cyapa->state = CYAPA_STATE_GEN5_BL;
> + } else if (reg_data[2] == GEN5_TOUCH_REPORT_ID ||
> + reg_data[2] == GEN5_BTN_REPORT_ID ||
> + reg_data[2] == GEN5_OLD_PUSH_BTN_REPORT_ID ||
> + reg_data[2] == GEN5_PUSH_BTN_REPORT_ID ||
> + reg_data[2] == GEN5_WAKEUP_EVENT_REPORT_ID) {
> + gen5_report_data_header_parse(cyapa, reg_data);
> + } else if (reg_data[2] == GEN5_BL_RESP_REPORT_ID ||
> + reg_data[2] == GEN5_APP_RESP_REPORT_ID) {
> + gen5_cmd_resp_header_parse(cyapa, reg_data);
> + }
> +
> + if (cyapa->gen == CYAPA_GEN5) {
> + /*
> + * Must read the content (e.g.: Report Description and so on)
> + * from trackpad device through out. Otherwise,
> + * Gen5 trackpad cannot response to next command or
> + * report any touch or button data later.
> + */
> + cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
> +
> + if (cyapa->state == CYAPA_STATE_GEN5_APP ||
> + cyapa->state == CYAPA_STATE_GEN5_BL)
> + return 0;
> + }
> +
> + return -EAGAIN;
> +}
> +
> +bool cyapa_gen5_sort_bl_exit_data(struct cyapa *cyapa, u8 *buf, int len)
> +{
> + if (buf == NULL || len < GEN5_RESP_LENGTH_SIZE)
> + return false;
> +
> + if (buf[0] == 0 && buf[1] == 0)
> + return true;
> +
> + /* Exit bootloader failed for some reason. */
> + if (len == GEN5_BL_FAIL_EXIT_RESP_LEN &&
> + buf[GEN5_RESP_REPORT_ID_OFFSET] ==
> + GEN5_BL_RESP_REPORT_ID &&
> + buf[GEN5_RESP_RSVD_OFFSET] == GEN5_RESP_RSVD_KEY &&
> + buf[GEN5_RESP_BL_SOP_OFFSET] == GEN5_SOP_KEY &&
> + buf[10] == GEN5_EOP_KEY)
> + return true;
> +
> + return false;
> +}
> +
> +static int cyapa_gen5_bl_exit(struct cyapa *cyapa)
> +{
> + int error;
> + u8 resp_data[11];
> + int resp_len;
> + u8 bl_gen5_bl_exit[] = { 0x04, 0x00,
> + 0x0B, 0x00, 0x40, 0x00, 0x01, 0x3b, 0x00, 0x00,
> + 0x20, 0xc7, 0x17
> + };
> +
> + resp_len = sizeof(resp_data);
> + error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
> + bl_gen5_bl_exit, sizeof(bl_gen5_bl_exit),
> + resp_data, &resp_len,
> + 5000, cyapa_gen5_sort_bl_exit_data, false);
> + if (error)
> + return error;
> +
> + if (resp_len == GEN5_BL_FAIL_EXIT_RESP_LEN ||
> + resp_data[GEN5_RESP_REPORT_ID_OFFSET] ==
> + GEN5_BL_RESP_REPORT_ID)
> + return -EAGAIN;
> +
> + if (resp_data[0] == 0x00 && resp_data[1] == 0x00)
> + return 0;
> +
> + return -ENODEV;
> +}
> +
> +static int cyapa_gen5_change_power_state(struct cyapa *cyapa, u8 power_state)
> +{
> + u8 cmd[8] = { 0x04, 0x00, 0x06, 0x00, 0x2f, 0x00, 0x08, 0x01 };
> + u8 resp_data[6];
> + int resp_len;
> + int error;
> +
> + cmd[7] = power_state;
> + resp_len = sizeof(resp_data);
> + error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, sizeof(cmd),
> + resp_data, &resp_len,
> + 500, cyapa_gen5_sort_tsg_pip_app_resp_data, false);
> + if (error || !VALID_CMD_RESP_HEADER(resp_data, 0x08) ||
> + !GEN5_CMD_COMPLETE_SUCCESS(resp_data[5]))
> + return error < 0 ? error : -EINVAL;
> +
> + return 0;
> +}
> +
> +static int cyapa_gen5_set_interval_time(struct cyapa *cyapa,
> + u8 parameter_id, u16 interval_time)
> +{
> + u8 cmd[13];
> + int cmd_len;
> + u8 resp_data[7];
> + int resp_len;
> + u8 parameter_size;
> + int error;
> +
> + switch (parameter_id) {
> + case GEN5_PARAMETER_ACT_INTERVL_ID:
> + parameter_size = GEN5_PARAMETER_ACT_INTERVL_SIZE;
> + break;
> + case GEN5_PARAMETER_ACT_LFT_INTERVL_ID:
> + parameter_size = GEN5_PARAMETER_ACT_LFT_INTERVL_SIZE;
> + break;
> + case GEN5_PARAMETER_LP_INTRVL_ID:
> + parameter_size = GEN5_PARAMETER_LP_INTRVL_SIZE;
> + break;
> + default:
> + return -EINVAL;
> + }
> + cmd_len = 7 + parameter_size; /* Not incuding 2 bytes address */
> + cmd[0] = 0x04;
> + cmd[1] = 0x00;
> + put_unaligned_le16(cmd_len, &cmd[2]);
> + cmd[4] = 0x2f;
> + cmd[5] = 0x00;
> + cmd[6] = 0x06; /* Set parameter command code */
> + cmd[7] = parameter_id;
> + cmd[8] = parameter_size;
> + put_unaligned_le16(interval_time, &cmd[9]);
> + resp_len = sizeof(resp_data);
> + error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, cmd_len + 2,
> + resp_data, &resp_len,
> + 500, cyapa_gen5_sort_tsg_pip_app_resp_data, false);
> + if (error || !VALID_CMD_RESP_HEADER(resp_data, 0x06) ||
> + resp_data[5] != parameter_id ||
> + resp_data[6] != parameter_size)
> + return error < 0 ? error : -EINVAL;
> +
> + return 0;
> +}
> +
> +static int cyapa_gen5_get_interval_time(struct cyapa *cyapa,
> + u8 parameter_id, u16 *interval_time)
> +{
> + u8 cmd[8];
> + u8 resp_data[11];
> + int resp_len;
> + u8 parameter_size;
> + u16 mask, i;
> + int error;
> +
> + *interval_time = 0;
> + switch (parameter_id) {
> + case GEN5_PARAMETER_ACT_INTERVL_ID:
> + parameter_size = GEN5_PARAMETER_ACT_INTERVL_SIZE;
> + break;
> + case GEN5_PARAMETER_ACT_LFT_INTERVL_ID:
> + parameter_size = GEN5_PARAMETER_ACT_LFT_INTERVL_SIZE;
> + break;
> + case GEN5_PARAMETER_LP_INTRVL_ID:
> + parameter_size = GEN5_PARAMETER_LP_INTRVL_SIZE;
> + break;
> + default:
> + return -EINVAL;
> + }
> +
> + cmd[0] = 0x04;
> + cmd[1] = 0x00;
> + cmd[2] = 0x06;
> + cmd[3] = 0x00;
> + cmd[4] = 0x2f;
> + cmd[5] = 0x00;
> + cmd[6] = 0x05; /* Get parameter command code */
> + cmd[7] = parameter_id;
> + resp_len = sizeof(resp_data);
> + error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, sizeof(cmd),
> + resp_data, &resp_len,
> + 500, cyapa_gen5_sort_tsg_pip_app_resp_data, false);
> + if (error || !VALID_CMD_RESP_HEADER(resp_data, 0x05) ||
> + resp_data[5] != parameter_id ||
> + resp_data[6] == 0)
> + return error < 0 ? error : -EINVAL;
> +
> + mask = 0;
> + for (i = 0; i < parameter_size; i++)
> + mask |= (0xff << (i * 8));
> + *interval_time = get_unaligned_le16(&resp_data[7]) & mask;
> +
> + return 0;
> +}
> +
> +static int cyapa_gen5_disable_pip_report(struct cyapa *cyapa)
> +{
> + u8 cmd[10];
> + u8 resp_data[7];
> + int resp_len;
> + int error;
> +
> + cmd[0] = 0x04;
> + cmd[1] = 0x00;
> + put_unaligned_le16(8, &cmd[2]);
> + cmd[4] = 0x2f;
> + cmd[5] = 0x00;
> + cmd[6] = 0x06; /* Set parameter command code */
> + cmd[7] = GEN5_PARAMETER_DISABLE_PIP_REPORT;
> + cmd[8] = 0x01;
> + cmd[9] = 0x01;
> + resp_len = sizeof(resp_data);
> + error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, 10,
> + resp_data, &resp_len,
> + 500, cyapa_gen5_sort_tsg_pip_app_resp_data, false);
> + if (error || !VALID_CMD_RESP_HEADER(resp_data, 0x06) ||
> + resp_data[5] != GEN5_PARAMETER_DISABLE_PIP_REPORT ||
> + resp_data[6] != 0x01)
> + return error < 0 ? error : -EINVAL;
> +
> + return 0;
> +}
> +
> +static int cyapa_gen5_deep_sleep(struct cyapa *cyapa, u8 state)
> +{
> + u8 cmd[4] = { 0x05, 0x00, 0x00, 0x08};
> + u8 resp_data[5];
> + int resp_len;
> + int error;
> +
> + cmd[0] = 0x05;
> + cmd[1] = 0x00;
> + cmd[2] = state & GEN5_DEEP_SLEEP_STATE_MASK;
> + cmd[3] = 0x08;
> + resp_len = sizeof(resp_data);
> + error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, sizeof(cmd),
> + resp_data, &resp_len,
> + 500, cyapa_gen5_sort_deep_sleep_data, false);
> + if (error || ((resp_data[3] & GEN5_DEEP_SLEEP_STATE_MASK) != state))
> + return -EINVAL;
> +
> + return 0;
> +}
> +
> +static int cyapa_gen5_set_power_mode(struct cyapa *cyapa,
> + u8 power_mode, u16 sleep_time)
> +{
> + struct device *dev = &cyapa->client->dev;
> + u8 power_state;
> + int error;
> +
> + if (cyapa->state != CYAPA_STATE_GEN5_APP)
> + return 0;
> +
> + /* Dump all the report data before do power mode commmands. */
> + cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
> +
> + if (GEN5_DEV_GET_PWR_STATE(cyapa) == UNINIT_PWR_MODE) {
> + /*
> + * Assume TP in deep sleep mode when driver is loaded,
> + * avoid driver unload and reload command IO issue caused by TP
> + * has been set into deep sleep mode when unloading.
> + */
> + GEN5_DEV_SET_PWR_STATE(cyapa, PWR_MODE_OFF);
> + }
> +
> + if (GEN5_DEV_UNINIT_SLEEP_TIME(cyapa) &&
> + GEN5_DEV_GET_PWR_STATE(cyapa) != PWR_MODE_OFF)
> + if (cyapa_gen5_get_interval_time(cyapa,
> + GEN5_PARAMETER_LP_INTRVL_ID,
> + &cyapa->dev_sleep_time) != 0)
> + GEN5_DEV_SET_SLEEP_TIME(cyapa, UNINIT_SLEEP_TIME);
> +
> + if (GEN5_DEV_GET_PWR_STATE(cyapa) == power_mode) {
> + if (power_mode == PWR_MODE_OFF ||
> + power_mode == PWR_MODE_FULL_ACTIVE ||
> + power_mode == PWR_MODE_BTN_ONLY ||
> + GEN5_DEV_GET_SLEEP_TIME(cyapa) == sleep_time) {
> + /* Has in correct power mode state, early return. */
> + return 0;
> + }
> + }
> +
> + if (power_mode == PWR_MODE_OFF) {
> + error = cyapa_gen5_deep_sleep(cyapa, GEN5_DEEP_SLEEP_STATE_OFF);
> + if (error) {
> + dev_err(dev, "enter deep sleep fail: %d\n", error);
> + return error;
> + }
> +
> + GEN5_DEV_SET_PWR_STATE(cyapa, PWR_MODE_OFF);
> + return 0;
> + }
> +
> + /*
> + * When trackpad in power off mode, it cannot change to other power
> + * state directly, must be wake up from sleep firstly, then
> + * continue to do next power sate change.
> + */
> + if (GEN5_DEV_GET_PWR_STATE(cyapa) == PWR_MODE_OFF) {
> + error = cyapa_gen5_deep_sleep(cyapa, GEN5_DEEP_SLEEP_STATE_ON);
> + if (error) {
> + dev_err(dev, "deep sleep wake fail: %d\n", error);
> + return error;
> + }
> + }
> +
> + if (power_mode == PWR_MODE_FULL_ACTIVE) {
> + error = cyapa_gen5_change_power_state(cyapa,
> + GEN5_POWER_STATE_ACTIVE);
> + if (error) {
> + dev_err(dev, "change to active fail: %d\n", error);
> + return error;
> + }
> +
> + GEN5_DEV_SET_PWR_STATE(cyapa, PWR_MODE_FULL_ACTIVE);
> + } else if (power_mode == PWR_MODE_BTN_ONLY) {
> + error = cyapa_gen5_change_power_state(cyapa,
> + GEN5_POWER_STATE_BTN_ONLY);
> + if (error) {
> + dev_err(dev, "fail to button only mode: %d\n", error);
> + return error;
> + }
> +
> + GEN5_DEV_SET_PWR_STATE(cyapa, PWR_MODE_BTN_ONLY);
> + } else {
> + /*
> + * Continue to change power mode even failed to set
> + * interval time, it won't affect the power mode change.
> + * except the sleep interval time is not correct.
> + */
> + if (GEN5_DEV_UNINIT_SLEEP_TIME(cyapa) ||
> + sleep_time != GEN5_DEV_GET_SLEEP_TIME(cyapa))
> + if (cyapa_gen5_set_interval_time(cyapa,
> + GEN5_PARAMETER_LP_INTRVL_ID,
> + sleep_time) == 0)
> + GEN5_DEV_SET_SLEEP_TIME(cyapa, sleep_time);
> +
> + if (sleep_time <= GEN5_POWER_READY_MAX_INTRVL_TIME)
> + power_state = GEN5_POWER_STATE_READY;
> + else
> + power_state = GEN5_POWER_STATE_IDLE;
> + error = cyapa_gen5_change_power_state(cyapa, power_state);
> + if (error) {
> + dev_err(dev, "set power state to 0x%02x failed: %d\n",
> + power_state, error);
> + return error;
> + }
> +
> + /*
> + * Disable pip report for a little time, firmware will
> + * re-enable it automatically. It's used to fix the issue
> + * that trackpad unable to report signal to wake system up
> + * in the special situation that system is in suspending, and
> + * at the same time, user touch trackpad to wake system up.
> + * This function can avoid the data to be buffured when system
> + * is suspending which may cause interrput line unable to be
> + * asserted again.
> + */
> + cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
> + cyapa_gen5_disable_pip_report(cyapa);
> +
> + GEN5_DEV_SET_PWR_STATE(cyapa,
> + cyapa_sleep_time_to_pwr_cmd(sleep_time));
> + }
> +
> + return 0;
> +}
> +
> +static bool cyapa_gen5_sort_system_info_data(struct cyapa *cyapa,
> + u8 *buf, int len)
> +{
> + /* Check the report id and command code */
> + if (VALID_CMD_RESP_HEADER(buf, 0x02))
> + return true;
> +
> + return false;
> +}
> +
> +static int cyapa_gen5_bl_query_data(struct cyapa *cyapa)
> +{
> + u8 cmd[16];
> + int cmd_len;
> + u8 resp_data[GEN5_BL_READ_APP_INFO_RESP_LEN];
> + int resp_len;
> + int error;
> +
> + /* Read application information. */
> + cmd[0] = 0x04;
> + cmd[1] = 0x00;
> + cmd[2] = 0x0b;
> + cmd[3] = 0x00;
> + cmd[4] = 0x40;
> + cmd[5] = 0x00;
> + cmd[6] = GEN5_SOP_KEY;
> + cmd[7] = 0x3c; /* Read application information command code */
> + cmd[8] = 0x00;
> + cmd[9] = 0x00;
> + cmd[10] = 0xb0;
> + cmd[11] = 0x42;
> + cmd[12] = GEN5_EOP_KEY;
> + cmd_len = 13;
> + resp_len = GEN5_BL_READ_APP_INFO_RESP_LEN;
> + error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
> + cmd, cmd_len,
> + resp_data, &resp_len,
> + 500, cyapa_gen5_sort_tsg_pip_bl_resp_data, false);
> + if (error || resp_len != GEN5_BL_READ_APP_INFO_RESP_LEN ||
> + !GEN5_CMD_COMPLETE_SUCCESS(resp_data[5]))
> + return error ? error : -EIO;
> +
> + memcpy(&cyapa->product_id[0], &resp_data[8], 5);
> + cyapa->product_id[5] = '-';
> + memcpy(&cyapa->product_id[6], &resp_data[13], 6);
> + cyapa->product_id[12] = '-';
> + memcpy(&cyapa->product_id[13], &resp_data[19], 2);
> + cyapa->product_id[15] = '\0';
> +
> + cyapa->fw_maj_ver = resp_data[22];
> + cyapa->fw_min_ver = resp_data[23];
> +
> + return 0;
> +}
> +
> +static int cyapa_gen5_get_query_data(struct cyapa *cyapa)
> +{
> + u8 resp_data[71];
> + int resp_len;
> + u8 get_system_information[] = {
> + 0x04, 0x00, 0x05, 0x00, 0x2f, 0x00, 0x02
> + };
> + u16 product_family;
> + int error;
> +
> + resp_len = sizeof(resp_data);
> + error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
> + get_system_information, sizeof(get_system_information),
> + resp_data, &resp_len,
> + 2000, cyapa_gen5_sort_system_info_data, false);
> + if (error || resp_len < sizeof(resp_data))
> + return error ? error : -EIO;
> +
> + product_family = get_unaligned_le16(&resp_data[7]);
> + if ((product_family & GEN5_PRODUCT_FAMILY_MASK) !=
> + GEN5_PRODUCT_FAMILY_TRACKPAD)
> + return -EINVAL;
> +
> + cyapa->fw_maj_ver = resp_data[15];
> + cyapa->fw_min_ver = resp_data[16];
> +
> + cyapa->electrodes_x = resp_data[52];
> + cyapa->electrodes_y = resp_data[53];
> +
> + cyapa->physical_size_x = get_unaligned_le16(&resp_data[54]) / 100;
> + cyapa->physical_size_y = get_unaligned_le16(&resp_data[56]) / 100;
> +
> + cyapa->max_abs_x = get_unaligned_le16(&resp_data[58]);
> + cyapa->max_abs_y = get_unaligned_le16(&resp_data[60]);
> +
> + cyapa->max_z = get_unaligned_le16(&resp_data[62]);
> +
> + cyapa->x_origin = resp_data[64] & 0x01;
> + cyapa->y_origin = resp_data[65] & 0x01;
> +
> + cyapa->btn_capability = (resp_data[70] << 3) & CAPABILITY_BTN_MASK;
> +
> + memcpy(&cyapa->product_id[0], &resp_data[33], 5);
> + cyapa->product_id[5] = '-';
> + memcpy(&cyapa->product_id[6], &resp_data[38], 6);
> + cyapa->product_id[12] = '-';
> + memcpy(&cyapa->product_id[13], &resp_data[44], 2);
> + cyapa->product_id[15] = '\0';
> +
> + if (!cyapa->electrodes_x || !cyapa->electrodes_y ||
> + !cyapa->physical_size_x || !cyapa->physical_size_y ||
> + !cyapa->max_abs_x || !cyapa->max_abs_y || !cyapa->max_z)
> + return -EINVAL;
> +
> + return 0;
> +}
> +
> +static int cyapa_gen5_do_operational_check(struct cyapa *cyapa)
> +{
> + struct device *dev = &cyapa->client->dev;
> + int error;
> +
> + if (cyapa->gen != CYAPA_GEN5)
> + return -ENODEV;
> +
> + switch (cyapa->state) {
> + case CYAPA_STATE_GEN5_BL:
> + error = cyapa_gen5_bl_exit(cyapa);
> + if (error) {
> + /* Rry to update trackpad product information. */
> + cyapa_gen5_bl_query_data(cyapa);
> + goto out;
> + }
> +
> + cyapa->state = CYAPA_STATE_GEN5_APP;
> +
> + case CYAPA_STATE_GEN5_APP:
> + /*
> + * If trackpad device in deep sleep mode,
> + * the app command will fail.
> + * So always try to reset trackpad device to full active when
> + * the device state is requeried.
> + */
> + error = cyapa_gen5_set_power_mode(cyapa,
> + PWR_MODE_FULL_ACTIVE, 0);
> + if (error)
> + dev_warn(dev, "%s: failed to set power active mode.\n",
> + __func__);
> +
> + /* Get trackpad product information. */
> + error = cyapa_gen5_get_query_data(cyapa);
> + if (error)
> + goto out;
> + /* Only support product ID starting with CYTRA */
> + if (memcmp(cyapa->product_id, product_id,
> + strlen(product_id)) != 0) {
> + dev_err(dev, "%s: unknown product ID (%s)\n",
> + __func__, cyapa->product_id);
> + error = -EINVAL;
> + }
> + break;
> + default:
> + error = -EINVAL;
> + }
> +
> +out:
> + return error;
> +}
> +
> +/*
> + * Return false, do not continue process
> + * Return true, continue process.
> + */
> +static bool cyapa_gen5_irq_cmd_handler(struct cyapa *cyapa)
> +{
> + int length;
> + struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5;
> +
> + if (atomic_read(&gen5_pip->cmd_issued)) {
> + /* Polling command response data. */
> + if (gen5_pip->is_irq_mode == false)
> + return false;
> +
> + /*
> + * Read out all none command response data.
> + * these output data may caused by user put finger on
> + * trackpad when host waiting the command response.
> + */
> + cyapa_i2c_pip_read(cyapa, gen5_pip->irq_cmd_buf,
> + GEN5_RESP_LENGTH_SIZE);
> + length = get_unaligned_le16(gen5_pip->irq_cmd_buf);
> + length = (length <= GEN5_RESP_LENGTH_SIZE) ?
> + GEN5_RESP_LENGTH_SIZE : length;
> + if (length > GEN5_RESP_LENGTH_SIZE)
> + cyapa_i2c_pip_read(cyapa,
> + gen5_pip->irq_cmd_buf, length);
> +
> + if (!(gen5_pip->resp_sort_func &&
> + gen5_pip->resp_sort_func(cyapa,
> + gen5_pip->irq_cmd_buf, length))) {
> + /*
> + * Cover the Gen5 V1 firmware issue.
> + * The issue is there is no interrut will be
> + * asserted to notityf host to read a command
> + * data out when always has finger touch on
> + * trackpad during the command is issued to
> + * trackad device.
> + * This issue has the scenario is that,
> + * user always has his fingers touched on
> + * trackpad device when booting/rebooting
> + * their chrome book.
> + */
> + length = *gen5_pip->resp_len;
> + cyapa_empty_pip_output_data(cyapa,
> + gen5_pip->resp_data,
> + &length,
> + gen5_pip->resp_sort_func);
> + if (gen5_pip->resp_len && length != 0) {
> + *gen5_pip->resp_len = length;
> + atomic_dec(&gen5_pip->cmd_issued);
> + complete(&gen5_pip->cmd_ready);
> + }
> + return false;
> + }
> +
> + if (gen5_pip->resp_data && gen5_pip->resp_len) {
> + *gen5_pip->resp_len = (*gen5_pip->resp_len < length) ?
> + *gen5_pip->resp_len : length;
> + memcpy(gen5_pip->resp_data, gen5_pip->irq_cmd_buf,
> + *gen5_pip->resp_len);
> + }
> + atomic_dec(&gen5_pip->cmd_issued);
> + complete(&gen5_pip->cmd_ready);
> + return false;
> + }
> +
> + return true;
> +}
> +
> +static void cyapa_gen5_report_buttons(struct cyapa *cyapa,
> + const struct cyapa_gen5_report_data *report_data)
> +{
> + struct input_dev *input = cyapa->input;
> + u8 buttons = report_data->report_head[GEN5_BUTTONS_OFFSET];
> +
> + buttons = (buttons << CAPABILITY_BTN_SHIFT) & CAPABILITY_BTN_MASK;
> +
> + if (cyapa->btn_capability & CAPABILITY_LEFT_BTN_MASK) {
> + input_report_key(input, BTN_LEFT,
> + !!(buttons & CAPABILITY_LEFT_BTN_MASK));
> + }
> + if (cyapa->btn_capability & CAPABILITY_MIDDLE_BTN_MASK) {
> + input_report_key(input, BTN_MIDDLE,
> + !!(buttons & CAPABILITY_MIDDLE_BTN_MASK));
> + }
> + if (cyapa->btn_capability & CAPABILITY_RIGHT_BTN_MASK) {
> + input_report_key(input, BTN_RIGHT,
> + !!(buttons & CAPABILITY_RIGHT_BTN_MASK));
> + }
> +
> + input_sync(input);
> +}
> +
> +static void cyapa_gen5_report_slot_data(struct cyapa *cyapa,
> + const struct cyapa_gen5_touch_record *touch)
> +{
> + struct input_dev *input = cyapa->input;
> + u8 event_id = GEN5_GET_EVENT_ID(touch->touch_tip_event_id);
> + int slot = GEN5_GET_TOUCH_ID(touch->touch_tip_event_id);
> + int x, y;
> +
> + if (event_id == RECORD_EVENT_LIFTOFF)
> + return;
> +
> + input_mt_slot(input, slot);
> + input_mt_report_slot_state(input, MT_TOOL_FINGER, true);
> + x = (touch->x_hi << 8) | touch->x_lo;
> + if (cyapa->x_origin)
> + x = cyapa->max_abs_x - x;
> + input_report_abs(input, ABS_MT_POSITION_X, x);
> + y = (touch->y_hi << 8) | touch->y_lo;
> + if (cyapa->y_origin)
> + y = cyapa->max_abs_y - y;
> + input_report_abs(input, ABS_MT_POSITION_Y, y);
> + input_report_abs(input, ABS_MT_PRESSURE,
> + touch->z);
> + input_report_abs(input, ABS_MT_TOUCH_MAJOR,
> + touch->major_axis_len);
> + input_report_abs(input, ABS_MT_TOUCH_MINOR,
> + touch->minor_axis_len);
> +
> + input_report_abs(input, ABS_MT_WIDTH_MAJOR,
> + touch->major_tool_len);
> + input_report_abs(input, ABS_MT_WIDTH_MINOR,
> + touch->minor_tool_len);
> +
> + input_report_abs(input, ABS_MT_ORIENTATION,
> + touch->orientation);
> +}
> +
> +static void cyapa_gen5_report_touches(struct cyapa *cyapa,
> + const struct cyapa_gen5_report_data *report_data)
> +{
> + struct input_dev *input = cyapa->input;
> + unsigned int touch_num;
> + int i;
> +
> + touch_num = report_data->report_head[GEN5_NUMBER_OF_TOUCH_OFFSET] &
> + GEN5_NUMBER_OF_TOUCH_MASK;
> +
> + for (i = 0; i < touch_num; i++)
> + cyapa_gen5_report_slot_data(cyapa,
> + &report_data->touch_records[i]);
> +
> + input_mt_sync_frame(input);
> + input_sync(input);
> +}
> +
> +static int cyapa_gen5_irq_handler(struct cyapa *cyapa)
> +{
> + struct device *dev = &cyapa->client->dev;
> + struct cyapa_gen5_report_data report_data;
> + int ret;
> + u8 report_id;
> + unsigned int report_len;
> +
> + if (cyapa->gen != CYAPA_GEN5 ||
> + cyapa->state != CYAPA_STATE_GEN5_APP) {
> + dev_err(dev, "invalid device state, gen=%d, state=0x%02x\n",
> + cyapa->gen, cyapa->state);
> + return -EINVAL;
> + }
> +
> + ret = cyapa_i2c_pip_read(cyapa, (u8 *)&report_data,
> + GEN5_RESP_LENGTH_SIZE);
> + if (ret != GEN5_RESP_LENGTH_SIZE) {
> + dev_err(dev, "failed to read length bytes, (%d)\n", ret);
> + return -EINVAL;
> + }
> +
> + report_len = get_unaligned_le16(
> + &report_data.report_head[GEN5_RESP_LENGTH_OFFSET]);
> + if (report_len < GEN5_RESP_LENGTH_SIZE) {
> + /* Invliad length or internal reset happened. */
> + dev_err(dev, "invalid report_len=%d. bytes: %02x %02x\n",
> + report_len, report_data.report_head[0],
> + report_data.report_head[1]);
> + return -EINVAL;
> + }
> +
> + /* Idle, no data for report. */
> + if (report_len == GEN5_RESP_LENGTH_SIZE)
> + return 0;
> +
> + ret = cyapa_i2c_pip_read(cyapa, (u8 *)&report_data, report_len);
> + if (ret != report_len) {
> + dev_err(dev, "failed to read %d bytes report data, (%d)\n",
> + report_len, ret);
> + return -EINVAL;
> + }
> +
> + report_id = report_data.report_head[GEN5_RESP_REPORT_ID_OFFSET];
> + if (report_id == GEN5_WAKEUP_EVENT_REPORT_ID &&
> + report_len == GEN5_WAKEUP_EVENT_SIZE) {
> + /*
> + * Device wake event from deep sleep mode for touch.
> + * This interrupt event is used to wake system up.
> + */
> + return 0;
> + } else if (report_id != GEN5_TOUCH_REPORT_ID &&
> + report_id != GEN5_BTN_REPORT_ID &&
> + report_id != GEN5_OLD_PUSH_BTN_REPORT_ID &&
> + report_id != GEN5_PUSH_BTN_REPORT_ID) {
> + /* Running in BL mode or unknown response data read. */
> + dev_err(dev, "invalid report_id=0x%02x\n", report_id);
> + return -EINVAL;
> + }
> +
> + if (report_id == GEN5_TOUCH_REPORT_ID &&
> + (report_len < GEN5_TOUCH_REPORT_HEAD_SIZE ||
> + report_len > GEN5_TOUCH_REPORT_MAX_SIZE)) {
> + /* Invalid report data length for finger packet. */
> + dev_err(dev, "invalid touch packet length=%d\n", report_len);
> + return 0;
> + }
> +
> + if ((report_id == GEN5_BTN_REPORT_ID ||
> + report_id == GEN5_OLD_PUSH_BTN_REPORT_ID ||
> + report_id == GEN5_PUSH_BTN_REPORT_ID) &&
> + (report_len < GEN5_BTN_REPORT_HEAD_SIZE ||
> + report_len > GEN5_BTN_REPORT_MAX_SIZE)) {
> + /* Invalid report data length of button packet. */
> + dev_err(dev, "invalid button packet length=%d\n", report_len);
> + return 0;
> + }
> +
> + if (report_id == GEN5_TOUCH_REPORT_ID)
> + cyapa_gen5_report_touches(cyapa, &report_data);
> + else
> + cyapa_gen5_report_buttons(cyapa, &report_data);
> +
> + return 0;
> +}
> +
> +const struct cyapa_dev_ops cyapa_gen5_ops = {
> + .initialize = cyapa_gen5_initialize,
> +
> + .state_parse = cyapa_gen5_state_parse,
> + .operational_check = cyapa_gen5_do_operational_check,
> +
> + .irq_handler = cyapa_gen5_irq_handler,
> + .irq_cmd_handler = cyapa_gen5_irq_cmd_handler,
> + .sort_empty_output_data = cyapa_empty_pip_output_data,
> + .set_power_mode = cyapa_gen5_set_power_mode,
> +};
> --
> 1.9.1
>
> --
> 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
--
- Jeremiah Mahler
^ permalink raw reply
* Re: [PATCH v15 00/12] input: cyapa: instruction of cyapa patches
From: Jeremiah Mahler @ 2014-12-15 14:10 UTC (permalink / raw)
To: Dudley Du
Cc: dmitry.torokhov, rydberg, bleung, dso, linux-input, linux-kernel
In-Reply-To: <1418624603-19054-1-git-send-email-dudley.dulixin@gmail.com>
Dudley,
On Mon, Dec 15, 2014 at 02:23:11PM +0800, Dudley Du wrote:
> V15 patches have below updates, details of other updates see history list:
> 1) Fix all warning errors of sparse tool when running with "make C=1".
> 2) Change variable name "unique_str" to "product_id" for clearer meanings.
>
>
> This patch series is aimed to re-design the cyapa driver to support
> old gen3 trackpad devices and new gen5 trackpad devices in one
[...]
The patch set still tests fine on my Acer C720.
I went through all the patches and found lots of minor things to fix
as you would expect from this large amount of code.
I hope you don't get discouraged :-)
--
- Jeremiah Mahler
^ permalink raw reply
* Re: [PATCH v4 0/6] Touchscreen performance related fixes
From: Catalin Crenguta @ 2014-12-15 12:45 UTC (permalink / raw)
To: Griffis, Brad
Cc: Sebastian Andrzej Siewior, Nicolae Rosia, R, Vignesh, Rob Herring,
Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
Benoit Cousson, Tony Lindgren, Russell King, Jonathan Cameron,
Hartmut Knaack,
richardcochran-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org,
Dmitry Torokhov, Lee Jones, Lars-Peter Clausen, Peter Meerwald,
Samuel Ortiz, Balbi, Felipe, Sanjeev Sharma, Paul Gortmaker
In-Reply-To: <912A29987EAE174BA6CF187D7CDFA9CE26FA135A-YmePFLaaepqIQmiDNMet8wC/G2K4zDHf@public.gmane.org>
On Fri, Dec 12, 2014 at 4:16 PM, Griffis, Brad <bgriffis-l0cyMroinI0@public.gmane.org> wrote:
> How are you configuring ti,charge-delay in your dts? I've seen this behavior on some custom boards where we were using a smaller charge delay (0x400) to begin with, and by upping it to 0xb000 we resolved the issue. These patches however already specified ti,charge-delay = 0xb000 by default so this would surprise me that it's still seeing that issue. Was the touchscreen working as expected before these new patches, or does it have issues both ways?
I have created a DTS for Beaglebone Black with 4 wire touchscreen and
display which works on 3.18 stable and tsc-devel, omap2plus_defconfig
with tsc and tilcdc support.
It seems that with lcdc disabled, I am not getting false reports but
when I'm activating the lcdc, I get a lot of false pen-downs/pen-ups.
Even with tilcdc enabled, after it prints "timeout waiting for
framedone" and the screen get blanked (white), the noise is gone.
Regards,
Catalin.
^ permalink raw reply
* [PATCH 2/2] Input: atmel_mxt_ts - Split out touchpad initialisation logic
From: Javier Martinez Canillas @ 2014-12-15 10:39 UTC (permalink / raw)
To: Dmitry Torokhov
Cc: Henrik Rydberg, Nick Dyer, Sjoerd Simons, Doug Anderson,
Olof Johansson, Yufeng Shen, Benson Leung, linux-input,
linux-samsung-soc, Javier Martinez Canillas
In-Reply-To: <1418639947-28765-1-git-send-email-javier.martinez@collabora.co.uk>
From: Sjoerd Simons <sjoerd.simons@collabora.co.uk>
If the "linux,gpio-keymap" DT property is defined, the T19 keys are configured
and the device is setup as a touchpad rather than a touchscreen. The logic is
part of the input device initialization routine but it can be factored out to
its own function to simplify the former.
Signed-off-by: Sjoerd Simons <sjoerd.simons@collabora.co.uk>
[javier: Adapt to latest driver changes and modify commit message accordingly]
Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
---
drivers/input/touchscreen/atmel_mxt_ts.c | 48 +++++++++++++++++++-------------
1 file changed, 28 insertions(+), 20 deletions(-)
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index aaa9e07..01fda60 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -1756,15 +1756,40 @@ static int mxt_read_t100_config(struct mxt_data *data)
static int mxt_input_open(struct input_dev *dev);
static void mxt_input_close(struct input_dev *dev);
+static bool mxt_initialize_t19(struct input_dev *input_dev,
+ struct mxt_data *data)
+{
+ const struct mxt_platform_data *pdata = data->pdata;
+ int i;
+
+ if (pdata->t19_num_keys) {
+ __set_bit(INPUT_PROP_BUTTONPAD, input_dev->propbit);
+
+ for (i = 0; i < pdata->t19_num_keys; i++)
+ if (pdata->t19_keymap[i] != KEY_RESERVED)
+ input_set_capability(input_dev, EV_KEY,
+ pdata->t19_keymap[i]);
+
+ input_abs_set_res(input_dev, ABS_X, MXT_PIXELS_PER_MM);
+ input_abs_set_res(input_dev, ABS_Y, MXT_PIXELS_PER_MM);
+ input_abs_set_res(input_dev, ABS_MT_POSITION_X,
+ MXT_PIXELS_PER_MM);
+ input_abs_set_res(input_dev, ABS_MT_POSITION_Y,
+ MXT_PIXELS_PER_MM);
+
+ input_dev->name = "Atmel maXTouch Touchpad";
+ return true;
+ }
+ return false;
+}
+
static int mxt_initialize_input_device(struct mxt_data *data, int multitouch)
{
struct device *dev = &data->client->dev;
- const struct mxt_platform_data *pdata = data->pdata;
struct input_dev *input_dev;
int error;
unsigned int num_mt_slots;
unsigned int mt_flags = 0;
- int i;
switch (multitouch) {
case MXT_TOUCH_MULTI_T9:
@@ -1800,26 +1825,9 @@ static int mxt_initialize_input_device(struct mxt_data *data, int multitouch)
set_bit(EV_ABS, input_dev->evbit);
input_set_capability(input_dev, EV_KEY, BTN_TOUCH);
- if (pdata->t19_num_keys) {
- __set_bit(INPUT_PROP_BUTTONPAD, input_dev->propbit);
-
- for (i = 0; i < pdata->t19_num_keys; i++)
- if (pdata->t19_keymap[i] != KEY_RESERVED)
- input_set_capability(input_dev, EV_KEY,
- pdata->t19_keymap[i]);
-
+ if (mxt_initialize_t19(input_dev, data))
mt_flags |= INPUT_MT_POINTER;
- input_abs_set_res(input_dev, ABS_X, MXT_PIXELS_PER_MM);
- input_abs_set_res(input_dev, ABS_Y, MXT_PIXELS_PER_MM);
- input_abs_set_res(input_dev, ABS_MT_POSITION_X,
- MXT_PIXELS_PER_MM);
- input_abs_set_res(input_dev, ABS_MT_POSITION_Y,
- MXT_PIXELS_PER_MM);
-
- input_dev->name = "Atmel maXTouch Touchpad";
- }
-
/* For single touch */
input_set_abs_params(input_dev, ABS_X,
0, data->max_x, 0, 0);
--
2.1.3
^ permalink raw reply related
* [PATCH 1/2] Input: atmel_mxt_ts - Implement support for T100 touch object
From: Javier Martinez Canillas @ 2014-12-15 10:39 UTC (permalink / raw)
To: Dmitry Torokhov
Cc: Henrik Rydberg, Nick Dyer, Sjoerd Simons, Doug Anderson,
Olof Johansson, Yufeng Shen, Benson Leung, linux-input,
linux-samsung-soc, Javier Martinez Canillas
In-Reply-To: <1418639947-28765-1-git-send-email-javier.martinez@collabora.co.uk>
From: Nick Dyer <nick.dyer@itdev.co.uk>
The T100 object replaces the old T9 multitouch touchscreen object in new
chips. This patch was cherry-picked from the Atmel touch downstream tree
The original patch had different initialization functions for the T9 and
T100 multi-touch input devices but there was a lot of code duplicated so
the code was refactored to make the T9 dev init function more generic to
support different multi-touch object types.
T9 and T100 initialization logic is kept as it was in the original patch
since there is no public documentation about the different object types.
Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
Acked-by: Yufeng Shen <miletus@chromium.org>
[javier: Factor out T9 and T100 routines to have a common init function]
Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
---
drivers/input/touchscreen/atmel_mxt_ts.c | 258 +++++++++++++++++++++++++++++--
1 file changed, 241 insertions(+), 17 deletions(-)
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index bb07020..aaa9e07 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -79,6 +79,7 @@
#define MXT_SPT_DIGITIZER_T43 43
#define MXT_SPT_MESSAGECOUNT_T44 44
#define MXT_SPT_CTECONFIG_T46 46
+#define MXT_TOUCH_MULTITOUCHSCREEN_T100 100
/* MXT_GEN_MESSAGE_T5 object */
#define MXT_RPTID_NOMSG 0xff
@@ -138,6 +139,9 @@ struct t9_range {
/* MXT_TOUCH_MULTI_T9 orient */
#define MXT_T9_ORIENT_SWITCH (1 << 0)
+/* T47 Stylus */
+#define MXT_TOUCH_MAJOR_T47_STYLUS 1
+
/* MXT_PROCI_GRIPFACE_T20 field */
#define MXT_GRIPFACE_CTRL 0
#define MXT_GRIPFACE_XLOGRIP 1
@@ -188,6 +192,23 @@ struct t9_range {
#define MXT_RESET_VALUE 0x01
#define MXT_BACKUP_VALUE 0x55
+/* T100 Multiple Touch Touchscreen */
+#define MXT_T100_CTRL 0
+#define MXT_T100_CFG1 1
+#define MXT_T100_TCHAUX 3
+#define MXT_T100_XRANGE 13
+#define MXT_T100_YRANGE 24
+
+#define MXT_T100_CFG_SWITCHXY (1 << 5)
+
+#define MXT_T100_TCHAUX_VECT (1 << 0)
+#define MXT_T100_TCHAUX_AMPL (1 << 1)
+#define MXT_T100_TCHAUX_AREA (1 << 2)
+
+#define MXT_T100_DETECT (1 << 7)
+#define MXT_T100_TYPE_MASK 0x70
+#define MXT_T100_TYPE_STYLUS 0x20
+
/* Delay times */
#define MXT_BACKUP_TIME 50 /* msec */
#define MXT_RESET_TIME 200 /* msec */
@@ -247,6 +268,9 @@ struct mxt_data {
unsigned int max_y;
bool in_bootloader;
u16 mem_size;
+ u8 t100_aux_ampl;
+ u8 t100_aux_area;
+ u8 t100_aux_vect;
u8 max_reportid;
u32 config_crc;
u32 info_crc;
@@ -268,6 +292,8 @@ struct mxt_data {
u8 T9_reportid_max;
u8 T19_reportid;
u16 T44_address;
+ u8 T100_reportid_min;
+ u8 T100_reportid_max;
/* for fw update in bootloader */
struct completion bl_completion;
@@ -761,6 +787,72 @@ static void mxt_proc_t9_message(struct mxt_data *data, u8 *message)
data->update_input = true;
}
+static void mxt_proc_t100_message(struct mxt_data *data, u8 *message)
+{
+ struct device *dev = &data->client->dev;
+ struct input_dev *input_dev = data->input_dev;
+ int id;
+ u8 status;
+ int x;
+ int y;
+ int tool;
+
+ id = message[0] - data->T100_reportid_min - 2;
+
+ /* ignore SCRSTATUS events */
+ if (id < 0)
+ return;
+
+ status = message[1];
+ x = (message[3] << 8) | message[2];
+ y = (message[5] << 8) | message[4];
+
+ dev_dbg(dev,
+ "[%u] status:%02X x:%u y:%u area:%02X amp:%02X vec:%02X\n",
+ id,
+ status,
+ x, y,
+ data->t100_aux_area ? message[data->t100_aux_area] : 0,
+ data->t100_aux_ampl ? message[data->t100_aux_ampl] : 0,
+ data->t100_aux_vect ? message[data->t100_aux_vect] : 0);
+
+ input_mt_slot(input_dev, id);
+
+ if (status & MXT_T100_DETECT) {
+ if ((status & MXT_T100_TYPE_MASK) == MXT_T100_TYPE_STYLUS)
+ tool = MT_TOOL_PEN;
+ else
+ tool = MT_TOOL_FINGER;
+
+ /* Touch active */
+ input_mt_report_slot_state(input_dev, tool, 1);
+ input_report_abs(input_dev, ABS_MT_POSITION_X, x);
+ input_report_abs(input_dev, ABS_MT_POSITION_Y, y);
+
+ if (data->t100_aux_ampl)
+ input_report_abs(input_dev, ABS_MT_PRESSURE,
+ message[data->t100_aux_ampl]);
+
+ if (data->t100_aux_area) {
+ if (tool == MT_TOOL_PEN)
+ input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR,
+ MXT_TOUCH_MAJOR_T47_STYLUS);
+ else
+ input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR,
+ message[data->t100_aux_area]);
+ }
+
+ if (data->t100_aux_vect)
+ input_report_abs(input_dev, ABS_MT_ORIENTATION,
+ message[data->t100_aux_vect]);
+ } else {
+ /* Touch no longer active, close out slot */
+ input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, 0);
+ }
+
+ data->update_input = true;
+}
+
static int mxt_proc_message(struct mxt_data *data, u8 *message)
{
u8 report_id = message[0];
@@ -779,6 +871,9 @@ static int mxt_proc_message(struct mxt_data *data, u8 *message)
} else if (report_id >= data->T9_reportid_min
&& report_id <= data->T9_reportid_max) {
mxt_proc_t9_message(data, message);
+ } else if (report_id >= data->T100_reportid_min
+ && report_id <= data->T100_reportid_max) {
+ mxt_proc_t100_message(data, message);
} else if (report_id == data->T19_reportid) {
mxt_input_button(data, message);
data->update_input = true;
@@ -1401,6 +1496,8 @@ static void mxt_free_object_table(struct mxt_data *data)
data->T9_reportid_max = 0;
data->T19_reportid = 0;
data->T44_address = 0;
+ data->T100_reportid_min = 0;
+ data->T100_reportid_max = 0;
data->max_reportid = 0;
}
@@ -1488,6 +1585,12 @@ static int mxt_get_object_table(struct mxt_data *data)
case MXT_SPT_GPIOPWM_T19:
data->T19_reportid = min_id;
break;
+ case MXT_TOUCH_MULTITOUCHSCREEN_T100:
+ data->T100_reportid_min = min_id;
+ data->T100_reportid_max = max_id;
+ /* first two report IDs reserved */
+ data->num_touchids = object->num_report_ids - 2;
+ break;
}
end_address = object->start_address
@@ -1572,10 +1675,88 @@ static int mxt_read_t9_resolution(struct mxt_data *data)
return 0;
}
+static int mxt_read_t100_config(struct mxt_data *data)
+{
+ struct i2c_client *client = data->client;
+ int error;
+ struct mxt_object *object;
+ u16 range_x, range_y;
+ u8 cfg, tchaux;
+ u8 aux;
+
+ object = mxt_get_object(data, MXT_TOUCH_MULTITOUCHSCREEN_T100);
+ if (!object)
+ return -EINVAL;
+
+ error = __mxt_read_reg(client,
+ object->start_address + MXT_T100_XRANGE,
+ sizeof(range_x), &range_x);
+ if (error)
+ return error;
+
+ le16_to_cpus(range_x);
+
+ error = __mxt_read_reg(client,
+ object->start_address + MXT_T100_YRANGE,
+ sizeof(range_y), &range_y);
+ if (error)
+ return error;
+
+ le16_to_cpus(range_y);
+
+ error = __mxt_read_reg(client,
+ object->start_address + MXT_T100_CFG1,
+ 1, &cfg);
+ if (error)
+ return error;
+
+ error = __mxt_read_reg(client,
+ object->start_address + MXT_T100_TCHAUX,
+ 1, &tchaux);
+ if (error)
+ return error;
+
+ /* Handle default values */
+ if (range_x == 0)
+ range_x = 1023;
+
+ /* Handle default values */
+ if (range_x == 0)
+ range_x = 1023;
+
+ if (range_y == 0)
+ range_y = 1023;
+
+ if (cfg & MXT_T100_CFG_SWITCHXY) {
+ data->max_x = range_y;
+ data->max_y = range_x;
+ } else {
+ data->max_x = range_x;
+ data->max_y = range_y;
+ }
+
+ /* allocate aux bytes */
+ aux = 6;
+
+ if (tchaux & MXT_T100_TCHAUX_VECT)
+ data->t100_aux_vect = aux++;
+
+ if (tchaux & MXT_T100_TCHAUX_AMPL)
+ data->t100_aux_ampl = aux++;
+
+ if (tchaux & MXT_T100_TCHAUX_AREA)
+ data->t100_aux_area = aux++;
+
+ dev_info(&client->dev,
+ "T100 Touchscreen size X%uY%u\n", data->max_x, data->max_y);
+
+ return 0;
+}
+
static int mxt_input_open(struct input_dev *dev);
static void mxt_input_close(struct input_dev *dev);
-static int mxt_initialize_t9_input_device(struct mxt_data *data)
+static int mxt_initialize_input_device(struct mxt_data *data, int multitouch)
{
struct device *dev = &data->client->dev;
const struct mxt_platform_data *pdata = data->pdata;
@@ -1585,9 +1766,23 @@ static int mxt_initialize_t9_input_device(struct mxt_data *data)
unsigned int mt_flags = 0;
int i;
- error = mxt_read_t9_resolution(data);
- if (error)
- dev_warn(dev, "Failed to initialize T9 resolution\n");
+ switch (multitouch) {
+ case MXT_TOUCH_MULTI_T9:
+ num_mt_slots = data->T9_reportid_max - data->T9_reportid_min + 1;
+ error = mxt_read_t9_resolution(data);
+ if (error)
+ dev_warn(dev, "Failed to initialize T9 resolution\n");
+ break;
+ case MXT_TOUCH_MULTITOUCHSCREEN_T100:
+ num_mt_slots = data->num_touchids;
+ error = mxt_read_t100_config(data);
+ if (error)
+ dev_warn(dev, "Failed to read T100 config\n");
+ break;
+ default:
+ dev_err(dev, "Invalid multitouch object\n");
+ return -EINVAL;
+ }
input_dev = input_allocate_device();
if (!input_dev) {
@@ -1602,9 +1797,8 @@ static int mxt_initialize_t9_input_device(struct mxt_data *data)
input_dev->open = mxt_input_open;
input_dev->close = mxt_input_close;
- __set_bit(EV_ABS, input_dev->evbit);
- __set_bit(EV_KEY, input_dev->evbit);
- __set_bit(BTN_TOUCH, input_dev->keybit);
+ set_bit(EV_ABS, input_dev->evbit);
+ input_set_capability(input_dev, EV_KEY, BTN_TOUCH);
if (pdata->t19_num_keys) {
__set_bit(INPUT_PROP_BUTTONPAD, input_dev->propbit);
@@ -1631,25 +1825,45 @@ static int mxt_initialize_t9_input_device(struct mxt_data *data)
0, data->max_x, 0, 0);
input_set_abs_params(input_dev, ABS_Y,
0, data->max_y, 0, 0);
- input_set_abs_params(input_dev, ABS_PRESSURE,
- 0, 255, 0, 0);
+
+ if (multitouch == MXT_TOUCH_MULTI_T9 ||
+ (multitouch == MXT_TOUCH_MULTITOUCHSCREEN_T100 &&
+ data->t100_aux_ampl))
+ input_set_abs_params(input_dev, ABS_PRESSURE,
+ 0, 255, 0, 0);
/* For multi touch */
- num_mt_slots = data->T9_reportid_max - data->T9_reportid_min + 1;
error = input_mt_init_slots(input_dev, num_mt_slots, mt_flags);
if (error) {
dev_err(dev, "Error %d initialising slots\n", error);
goto err_free_mem;
}
- input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,
- 0, MXT_MAX_AREA, 0, 0);
+ if (multitouch == MXT_TOUCH_MULTI_T9 ||
+ (multitouch == MXT_TOUCH_MULTITOUCHSCREEN_T100 &&
+ data->t100_aux_area))
+ input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,
+ 0, MXT_MAX_AREA, 0, 0);
+
+ if (multitouch == MXT_TOUCH_MULTITOUCHSCREEN_T100)
+ input_set_abs_params(input_dev, ABS_MT_TOOL_TYPE, 0,
+ MT_TOOL_MAX, 0, 0);
+
input_set_abs_params(input_dev, ABS_MT_POSITION_X,
0, data->max_x, 0, 0);
input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
0, data->max_y, 0, 0);
- input_set_abs_params(input_dev, ABS_MT_PRESSURE,
- 0, 255, 0, 0);
+
+ if (multitouch == MXT_TOUCH_MULTI_T9 ||
+ (multitouch == MXT_TOUCH_MULTITOUCHSCREEN_T100 &&
+ data->t100_aux_ampl))
+ input_set_abs_params(input_dev, ABS_MT_PRESSURE,
+ 0, 255, 0, 0);
+
+ if (multitouch == MXT_TOUCH_MULTITOUCHSCREEN_T100 &&
+ data->t100_aux_vect)
+ input_set_abs_params(input_dev, ABS_MT_ORIENTATION,
+ 0, 255, 0, 0);
input_set_drvdata(input_dev, data);
@@ -1801,6 +2015,7 @@ static int mxt_configure_objects(struct mxt_data *data,
{
struct device *dev = &data->client->dev;
struct mxt_info *info = &data->info;
+ int multitouch = 0;
int error;
if (cfg) {
@@ -1815,9 +2030,18 @@ static int mxt_configure_objects(struct mxt_data *data,
return error;
}
- error = mxt_initialize_t9_input_device(data);
- if (error)
- return error;
+ if (data->T9_reportid_min)
+ multitouch = MXT_TOUCH_MULTI_T9;
+ else if (data->T100_reportid_min)
+ multitouch = MXT_TOUCH_MULTITOUCHSCREEN_T100;
+
+ if (multitouch) {
+ error = mxt_initialize_input_device(data, multitouch);
+ if (error)
+ return error;
+ } else {
+ dev_warn(dev, "No touch object detected\n");
+ }
dev_info(dev,
"Family: %u Variant: %u Firmware V%u.%u.%02X Objects: %u\n",
--
2.1.3
^ permalink raw reply related
* [PATCH 0/2] Input: atmel_mxt_ts - Add support for T100 multi-touch
From: Javier Martinez Canillas @ 2014-12-15 10:39 UTC (permalink / raw)
To: Dmitry Torokhov
Cc: Henrik Rydberg, Nick Dyer, Sjoerd Simons, Doug Anderson,
Olof Johansson, Yufeng Shen, Benson Leung, linux-input,
linux-samsung-soc, Javier Martinez Canillas
Hello Dmitry,
There are different multi-touch protocols used by Atmel maXTouch touchscreen
chips. Old chips use the T9 multi-touch object type while newer chips use the
T100 multi-touch object type. The Atmel touch driver currently only supports
the former so this series add support for the later.
The series is composed of the following patches:
Nick Dyer (1):
Input: atmel_mxt_ts - Implement support for T100 touch object
Sjoerd Simons (1):
Input: atmel_mxt_ts - Split out touchpad initialisation logic
drivers/input/touchscreen/atmel_mxt_ts.c | 307 +++++++++++++++++++++++++++----
1 file changed, 270 insertions(+), 37 deletions(-)
Patch #1 adds the support for the T100 touch object and patch #2 is a
cleanup to simplify the driver's input device initialization function.
The series were tested on an Exynos 5420 Peach Pit (T9) and an Exynos
5800 Peach Pi (T100) using evtest.
Best regards,
Javier
^ permalink raw reply
* Re: [PATCH 2/2] Input: gpio_keys - replace timer and workqueue with delayed workqueue
From: Andy Shevchenko @ 2014-12-15 10:20 UTC (permalink / raw)
To: Dmitry Torokhov
Cc: linux-input, Alexander Stein, Linus Walleij, Ezequiel Garcia,
Alexander Shiyan, Laxman Dewangan, devicetree, linux-kernel
In-Reply-To: <20141213190926.GD22702@dtor-ws>
On Sat, 2014-12-13 at 11:09 -0800, Dmitry Torokhov wrote:
> Hi Andy,
>
> On Wed, Dec 10, 2014 at 08:32:56PM +0200, Andy Shevchenko wrote:
> > On Sun, 2014-12-07 at 23:21 -0800, Dmitry Torokhov wrote:
> > > We do not need to roll our own implementation of delayed work now that we
> > > have proper implementation of mod_delayed_work.
> > >
> > > For interrupt-only driven buttons we retain the timer, but we rename
> > > it to release_timer to better reflect its purpose.
> >
> > At least it doesn't break the driver on Intel Medfield device.
> >
> > Tested-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
>
> Thank you for testing it. Assume it is for both patches, right?
Right.
--
Andy Shevchenko <andriy.shevchenko@intel.com>
Intel Finland Oy
^ permalink raw reply
* Re: [PATCH v15 00/12] input: cyapa: instruction of cyapa patches
From: Jeremiah Mahler @ 2014-12-15 10:20 UTC (permalink / raw)
To: Dudley Du
Cc: dmitry.torokhov@gmail.com, rydberg@euromail.se, bleung@google.com,
David Solda, linux-input@vger.kernel.org,
linux-kernel@vger.kernel.org
In-Reply-To: <BN1PR06MB0701116150EACEA75FCADB7D16F0@BN1PR06MB070.namprd06.prod.outlook.com>
Dudley,
On Mon, Dec 15, 2014 at 06:31:25AM +0000, Dudley Du wrote:
> Jeremiah,
>
> Thanks for your review and comments.
> I have updated v15 based on your comments and suggestions.
> Could you help review again please.
>
> Thank you very much,
> Dudley
>
Will do.
[...]
--
- Jeremiah Mahler
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).