* Re: [PATCH 01/02] input: serio: use DEVICE_ATTR_RO()
From: Greg Kroah-Hartman @ 2013-10-22 6:12 UTC (permalink / raw)
To: Dmitry Torokhov; +Cc: linux-input
In-Reply-To: <20131021162531.GC4575@core.coreip.homeip.net>
On Mon, Oct 21, 2013 at 09:25:32AM -0700, Dmitry Torokhov wrote:
> Hi Greg,
>
> On Mon, Oct 07, 2013 at 06:08:23PM -0700, Greg Kroah-Hartman wrote:
> > From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> >
> > Convert the serio sysfs fiels to use the DEVICE_ATTR_RO() macros to make
> > it easier to audit the correct sysfs file permission usage.
>
> Sorry for the delay. Frankly I am not a fan of DEVICE_ATTR macros as it
> forces particular naming of the attribute structures and methods and
> forces us to lose the module prefix in names. I prefer all functions and
> file-scope variables have module prefix because in the absence of
> language-supported namespaces this is the one thing that insulates
> drivers from changes in shared headers.
No sysfs read/write functions should ever be exported out of the local
file "scope", so why is this an issue? I have run into it being a
problem for some files, where people have device/bus/class sysfs files
all in the same .c file, but that usage is very limited.
I'm trying to eventually convert the whole kernel to use the
DEVICE_ATTR_??() macros to make it so that we can audit the sysfs file
permissions easier, by making them impossible to get wrong. We have had
problems in the past where device files had incorrect permissions and
unprivilidged users could do things they shouldn't have. Using these
macros _should_ prevent almost all of that from even being possible.
Now odds are, I'll never be able to remove DEVICE_ATTR() from the tree,
as there are some strange files that use crazy permissions and we have
to live with that, but for all of the "simple" files, like are done
here, I'd really like to use them, especially as it provides a
kernel-wide uniformity to the naming of attribute function calls, which
is a huge benifit as well.
Note, I did apply this patch to my tree already, and it's queued up for
3.13-rc1. If you really object to it, I'll revert it, and fix up the
02/02 patch in this series to not need it, but I'd really like you to
reconsider your objection.
thanks,
greg k-h
^ permalink raw reply
* Re: [PATCH v2] add sur40 driver for Samsung SUR40 (aka MS Surface 2.0/Pixelsense)
From: Florian Echtler @ 2013-10-22 6:08 UTC (permalink / raw)
To: Dmitry Torokhov; +Cc: linux-input, benjamin.tissoires, rydberg, dh.herrmann
In-Reply-To: <20131021162006.GB4575@core.coreip.homeip.net>
[-- Attachment #1: Type: text/plain, Size: 2153 bytes --]
Hello Dmitry,
thanks for your quick feedback, a few questions below:
On 21.10.2013 18:20, Dmitry Torokhov wrote:
> On Sun, Oct 20, 2013 at 06:49:11PM +0200, Florian Echtler wrote:
>> +/* read 512 bytes from endpoint 0x86 -> get header + blobs */
>> +struct sur40_header {
>> +
>> + uint16_t type; /* always 0x0001 */
>> + uint16_t count; /* count of blobs (if 0: continue prev. packet) */
>> +
>> + uint32_t packet_id;
>> +
>> + uint32_t timestamp; /* milliseconds (inc. by 16 or 17 each frame) */
>> + uint32_t unknown; /* "epoch?" always 02/03 00 00 00 */
>
> Proper internal kernel types are u8, u16, u32. For user-facing APIs
> __u8, __u16, and __u32 should be used. Also, since this is data coming
> directly off the wire, you should be using __le16, __le32, etc, and then
> do __leXX_to_cpu() conversion before using it in calculations.
OK, I'll switch to u32 throughout (also for the float, I'll explain in a
commment). However, I haven't found a single other touchscreen driver
which uses __le32, even though they all probably process raw wire data -
can you suggest an example?
>> +/* debug helper macro */
>> +#define get_dev(x) (&(x->usbdev->dev))
> Just stick that dev in sur40_state and then use sur40->dev throughout.
OK.
>> + struct sur40_header *header = &(sur40->bulk_in_buffer->header);
> No need to have parenthesis around & operator.
>> + struct sur40_blob *inblob = &(sur40->bulk_in_buffer->blobs[0]);
> Same here.
Intention seems clearer to me with parentheses, but if this doesn't
conform to coding style, I'll fix it.
>> + if (!sur40->bulk_in_buffer) {
>> + dev_err(&interface->dev, "Unable to allocate input buffer.");
>> + sur40_delete(sur40);
> Would prefer standard kernel error unwinding style (gotos to proper
> unwinding point).
Something like this example from ucb1400_ts?
error = input_register_device(ucb->ts_idev);
if (error)
goto err_free_irq;
return 0;
err_free_irq:
free_irq(ucb->irq, ucb);
err_free_devs:
input_free_device(ucb->ts_idev);
err:
return error;
Best regards, Florian
--
SENT FROM MY DEC VT50 TERMINAL
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 198 bytes --]
^ permalink raw reply
* [PATCH] HID: Added Holtek USB ID 04d9:a072 LEETGION Hellion Gaming Mouse
From: Anders F. U. Kiær @ 2013-10-21 21:42 UTC (permalink / raw)
To: jkosina; +Cc: linux-input, linux-kernel, Anders F. U. Kiær
Added id, bindings and comments for Holtek USB ID 04d9:a072
LEETGION Hellion Gaming mouse to use the same corrections of the report
descriptor as Holtek 04d9:a067. As the mouse exceed HID_MAX_USAGES at the
same offsets in the reported descriptor.
Tested on the hardware.
Signed-off-by: Anders F. U. Kiær <ablacksheep@gmail.com>
---
drivers/hid/Kconfig | 1 +
drivers/hid/hid-core.c | 1 +
drivers/hid/hid-holtek-mouse.c | 4 ++++
drivers/hid/hid-ids.h | 3 ++-
4 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index c91d547..d68292a 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -242,6 +242,7 @@ config HID_HOLTEK
- Tracer Sniper TRM-503 / NOVA Gaming Slider X200 /
Zalman ZM-GM1
- SHARKOON DarkGlider Gaming mouse
+ - LEETGION Hellion Gaming Mouse
config HOLTEK_FF
bool "Holtek On Line Grip force feedback support"
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 5a8c011..6ab7133 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1715,6 +1715,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_KEYBOARD) },
{ HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A04A) },
{ HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A067) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A072) },
{ HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A081) },
{ HID_USB_DEVICE(USB_VENDOR_ID_HUION, USB_DEVICE_ID_HUION_580) },
{ HID_USB_DEVICE(USB_VENDOR_ID_JESS2, USB_DEVICE_ID_JESS2_COLOR_RUMBLE_PAD) },
diff --git a/drivers/hid/hid-holtek-mouse.c b/drivers/hid/hid-holtek-mouse.c
index e696566..0caa676 100644
--- a/drivers/hid/hid-holtek-mouse.c
+++ b/drivers/hid/hid-holtek-mouse.c
@@ -28,6 +28,7 @@
* - USB ID 04d9:a04a, sold as Tracer Sniper TRM-503, NOVA Gaming Slider X200
* and Zalman ZM-GM1
* - USB ID 04d9:a081, sold as SHARKOON DarkGlider Gaming mouse
+ * - USB ID 04d9:a072, sold as LEETGION Hellion Gaming Mouse
*/
static __u8 *holtek_mouse_report_fixup(struct hid_device *hdev, __u8 *rdesc,
@@ -40,6 +41,7 @@ static __u8 *holtek_mouse_report_fixup(struct hid_device *hdev, __u8 *rdesc,
* 0x2fff, so they don't exceed HID_MAX_USAGES */
switch (hdev->product) {
case USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A067:
+ case USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A072:
if (*rsize >= 122 && rdesc[115] == 0xff && rdesc[116] == 0x7f
&& rdesc[120] == 0xff && rdesc[121] == 0x7f) {
hid_info(hdev, "Fixing up report descriptor\n");
@@ -66,6 +68,8 @@ static const struct hid_device_id holtek_mouse_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT,
USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A04A) },
{ HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT,
+ USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A072) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT,
USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A081) },
{ }
};
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 9cbc7ab..8ebaef95 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -448,8 +448,9 @@
#define USB_VENDOR_ID_HOLTEK_ALT 0x04d9
#define USB_DEVICE_ID_HOLTEK_ALT_KEYBOARD 0xa055
-#define USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A067 0xa067
#define USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A04A 0xa04a
+#define USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A067 0xa067
+#define USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A072 0xa072
#define USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A081 0xa081
#define USB_VENDOR_ID_IMATION 0x0718
--
1.8.1.2
--
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 related
* [PATCH 1/2] input: touchscreen: fix spelling mistake in TSC/ADC DT binding
From: Felipe Balbi @ 2013-10-21 20:13 UTC (permalink / raw)
To: dmitry.torokhov
Cc: rob.herring, pawel.moll, mark.rutland, swarren, ijc+devicetree,
rob, bcousson, Tony Lindgren, Sebastian Andrzej Siewior,
devicetree, Linux OMAP Mailing List, linux-input, Felipe Balbi
In-Reply-To: <1382386404-6659-1-git-send-email-balbi@ti.com>
There was a spelling mistake on TSC/ADC binding where
"coordinate" was spelled as "coordiante".
We can't simply fix the error due to DT being an ABI,
the approach taken was to first use correct spelling
and if that fails, fallback to miss-spelled version.
It's unfortunate that has creeped into the tree.
Signed-off-by: Felipe Balbi <balbi@ti.com>
---
.../devicetree/bindings/input/touchscreen/ti-tsc-adc.txt | 2 +-
arch/arm/boot/dts/am335x-evm.dts | 2 +-
drivers/input/touchscreen/ti_am335x_tsc.c | 9 ++++++++-
3 files changed, 10 insertions(+), 3 deletions(-)
diff --git a/Documentation/devicetree/bindings/input/touchscreen/ti-tsc-adc.txt b/Documentation/devicetree/bindings/input/touchscreen/ti-tsc-adc.txt
index 491c97b..878549b 100644
--- a/Documentation/devicetree/bindings/input/touchscreen/ti-tsc-adc.txt
+++ b/Documentation/devicetree/bindings/input/touchscreen/ti-tsc-adc.txt
@@ -6,7 +6,7 @@ Required properties:
ti,wires: Wires refer to application modes i.e. 4/5/8 wire touchscreen
support on the platform.
ti,x-plate-resistance: X plate resistance
- ti,coordiante-readouts: The sequencer supports a total of 16
+ ti,coordinate-readouts: The sequencer supports a total of 16
programmable steps each step is used to
read a single coordinate. A single
readout is enough but multiple reads can
diff --git a/arch/arm/boot/dts/am335x-evm.dts b/arch/arm/boot/dts/am335x-evm.dts
index e8ec875..c5b73bc 100644
--- a/arch/arm/boot/dts/am335x-evm.dts
+++ b/arch/arm/boot/dts/am335x-evm.dts
@@ -509,7 +509,7 @@
tsc {
ti,wires = <4>;
ti,x-plate-resistance = <200>;
- ti,coordiante-readouts = <5>;
+ ti,coordinate-readouts = <5>;
ti,wire-config = <0x00 0x11 0x22 0x33>;
};
diff --git a/drivers/input/touchscreen/ti_am335x_tsc.c b/drivers/input/touchscreen/ti_am335x_tsc.c
index e1c5300..b61df9d 100644
--- a/drivers/input/touchscreen/ti_am335x_tsc.c
+++ b/drivers/input/touchscreen/ti_am335x_tsc.c
@@ -348,9 +348,16 @@ static int titsc_parse_dt(struct platform_device *pdev,
if (err < 0)
return err;
- err = of_property_read_u32(node, "ti,coordiante-readouts",
+ /*
+ * try with new binding first. If it fails, still try with
+ * bogus, miss-spelled version.
+ */
+ err = of_property_read_u32(node, "ti,coordinate-readouts",
&ts_dev->coordinate_readouts);
if (err < 0)
+ err = of_property_read_u32(node, "ti,coordiante-readouts",
+ &ts_dev->coordinate_readouts);
+ if (err < 0)
return err;
return of_property_read_u32_array(node, "ti,wire-config",
--
1.8.4.GIT
^ permalink raw reply related
* [PATCH 0/2] arm: am335x: am335x evm sk: add touchscreen DT node
From: Felipe Balbi @ 2013-10-21 20:13 UTC (permalink / raw)
To: dmitry.torokhov
Cc: rob.herring, pawel.moll, mark.rutland, swarren, ijc+devicetree,
rob, bcousson, Tony Lindgren, Sebastian Andrzej Siewior,
devicetree, Linux OMAP Mailing List, linux-input, Felipe Balbi
Hi,
the following patches fix a typo on TSC/ADC DT binding while
maintaining backwards compatibility and add support for the
touchscreen available on am335x-evm-sk.
Patches have been tested with am335x-evm-sk with a couple patches
(already floating around the mailing lists) to get that board
booting in mainline.
cheers
Felipe Balbi (2):
input: touchscreen: fix spelling mistake in TSC/ADC DT binding
arm: dts: am335x sk: add touchscreen support
.../devicetree/bindings/input/touchscreen/ti-tsc-adc.txt | 2 +-
arch/arm/boot/dts/am335x-evm.dts | 2 +-
arch/arm/boot/dts/am335x-evmsk.dts | 10 ++++++++++
drivers/input/touchscreen/ti_am335x_tsc.c | 9 ++++++++-
4 files changed, 20 insertions(+), 3 deletions(-)
--
1.8.4.GIT
^ permalink raw reply
* [PATCH 2/2] arm: dts: am335x sk: add touchscreen support
From: Felipe Balbi @ 2013-10-21 20:13 UTC (permalink / raw)
To: dmitry.torokhov
Cc: rob.herring, pawel.moll, mark.rutland, swarren, ijc+devicetree,
rob, bcousson, Tony Lindgren, Sebastian Andrzej Siewior,
devicetree, Linux OMAP Mailing List, linux-input, Felipe Balbi
In-Reply-To: <1382386404-6659-1-git-send-email-balbi@ti.com>
Add missing nodes for the touchscreen available
on AM335x EVM SK.
Signed-off-by: Felipe Balbi <balbi@ti.com>
---
arch/arm/boot/dts/am335x-evmsk.dts | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/arch/arm/boot/dts/am335x-evmsk.dts b/arch/arm/boot/dts/am335x-evmsk.dts
index 4f339fa..d7c2c0c 100644
--- a/arch/arm/boot/dts/am335x-evmsk.dts
+++ b/arch/arm/boot/dts/am335x-evmsk.dts
@@ -419,3 +419,13 @@
phy_id = <&davinci_mdio>, <1>;
phy-mode = "rgmii-txid";
};
+
+&tscadc {
+ status = "okay";
+ tsc {
+ ti,wires = <4>;
+ ti,x-plate-resistance = <200>;
+ ti,coordinate-readouts = <5>;
+ ti,wire-config = <0x00 0x11 0x22 0x33>;
+ };
+};
--
1.8.4.GIT
^ permalink raw reply related
* [PATCH] HID: hid-multitouch: add support for SiS panels
From: Forest Bond @ 2013-10-21 16:38 UTC (permalink / raw)
To: Jiri Kosina; +Cc: linux-input
From: Forest Bond <forest.bond@rapidrollout.com>
Signed-off-by: Forest Bond <forest.bond@rapidrollout.com>
---
drivers/hid/Kconfig | 1 +
drivers/hid/hid-core.c | 2 ++
drivers/hid/hid-ids.h | 4 ++++
drivers/hid/hid-multitouch.c | 8 ++++++++
drivers/hid/usbhid/hid-quirks.c | 2 ++
5 files changed, 17 insertions(+)
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index c91d547..5448c02 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -453,6 +453,7 @@ config HID_MULTITOUCH
- Pixcir dual touch panels
- Quanta panels
- eGalax dual-touch panels, including the Joojoo and Wetab tablets
+ - SiS multitouch panels
- Stantum multitouch panels
- Touch International Panels
- Unitec Panels
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index dfcd67f..1c4a442 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1815,6 +1815,8 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_PS1000) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_SIS2_TOUCH, USB_DEVICE_ID_SIS9200_TOUCH) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_SIS2_TOUCH, USB_DEVICE_ID_SIS817_TOUCH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SKYCABLE, USB_DEVICE_ID_SKYCABLE_WIRELESS_PRESENTER) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_BUZZ_CONTROLLER) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_WIRELESS_BUZZ_CONTROLLER) },
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 9cbc7ab..c511d4d 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -744,6 +744,10 @@
#define USB_VENDOR_ID_SIGMATEL 0x066F
#define USB_DEVICE_ID_SIGMATEL_STMP3780 0x3780
+#define USB_VENDOR_ID_SIS2_TOUCH 0x0457
+#define USB_DEVICE_ID_SIS9200_TOUCH 0x9200
+#define USB_DEVICE_ID_SIS817_TOUCH 0x0817
+
#define USB_VENDOR_ID_SKYCABLE 0x1223
#define USB_DEVICE_ID_SKYCABLE_WIRELESS_PRESENTER 0x3F07
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index 5e5fe1b..b18a943 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -1284,6 +1284,14 @@ static const struct hid_device_id mt_devices[] = {
MT_USB_DEVICE(USB_VENDOR_ID_QUANTA,
USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3008) },
+ /* SiS panels */
+ { .driver_data = MT_CLS_DEFAULT,
+ HID_USB_DEVICE(USB_VENDOR_ID_SIS2_TOUCH,
+ USB_DEVICE_ID_SIS9200_TOUCH) },
+ { .driver_data = MT_CLS_DEFAULT,
+ HID_USB_DEVICE(USB_VENDOR_ID_SIS2_TOUCH,
+ USB_DEVICE_ID_SIS817_TOUCH) },
+
/* Stantum panels */
{ .driver_data = MT_CLS_CONFIDENCE,
MT_USB_DEVICE(USB_VENDOR_ID_STANTUM,
diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c
index 0734552..ae5c634 100644
--- a/drivers/hid/usbhid/hid-quirks.c
+++ b/drivers/hid/usbhid/hid-quirks.c
@@ -84,6 +84,8 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_REALTEK, USB_DEVICE_ID_REALTEK_READER, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_SENNHEISER, USB_DEVICE_ID_SENNHEISER_BTD500USB, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_SIGMATEL, USB_DEVICE_ID_SIGMATEL_STMP3780, HID_QUIRK_NOGET },
+ { USB_VENDOR_ID_SIS2_TOUCH, USB_DEVICE_ID_SIS9200_TOUCH, HID_QUIRK_NOGET },
+ { USB_VENDOR_ID_SIS2_TOUCH, USB_DEVICE_ID_SIS817_TOUCH, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_SYMBOL, USB_DEVICE_ID_SYMBOL_SCANNER_1, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_SYMBOL, USB_DEVICE_ID_SYMBOL_SCANNER_2, HID_QUIRK_NOGET },
--
1.7.9.5
^ permalink raw reply related
* [PATCH 2/2] Input: usbtouchscreen: ignore eGalax/D-Wav/EETI HIDs
From: Forest Bond @ 2013-10-21 16:38 UTC (permalink / raw)
To: Dmitry Torokhov
Cc: linux-input, Sebastian Dalfuß, Daniel Ritz, Max Weninger,
Jiri Kosina, Christian Engelmayer
From: Forest Bond <forest.bond@rapidrollout.com>
The HID driver now handles these devices, regardless of what protocol
the device claims it supports.
Signed-off-by: Forest Bond <forest.bond@rapidrollout.com>
---
drivers/input/touchscreen/usbtouchscreen.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/drivers/input/touchscreen/usbtouchscreen.c b/drivers/input/touchscreen/usbtouchscreen.c
index 721fdb3..ae4b6b9 100644
--- a/drivers/input/touchscreen/usbtouchscreen.c
+++ b/drivers/input/touchscreen/usbtouchscreen.c
@@ -146,12 +146,10 @@ enum {
#define USB_DEVICE_HID_CLASS(vend, prod) \
.match_flags = USB_DEVICE_ID_MATCH_INT_CLASS \
- | USB_DEVICE_ID_MATCH_INT_PROTOCOL \
| USB_DEVICE_ID_MATCH_DEVICE, \
.idVendor = (vend), \
.idProduct = (prod), \
- .bInterfaceClass = USB_INTERFACE_CLASS_HID, \
- .bInterfaceProtocol = USB_INTERFACE_PROTOCOL_MOUSE
+ .bInterfaceClass = USB_INTERFACE_CLASS_HID
static const struct usb_device_id usbtouch_devices[] = {
#ifdef CONFIG_TOUCHSCREEN_USB_EGALAX
--
1.7.9.5
^ permalink raw reply related
* [PATCH 1/2] HID: don't ignore eGalax/D-Wav/EETI HIDs
From: Forest Bond @ 2013-10-21 16:38 UTC (permalink / raw)
To: Jiri Kosina
Cc: linux-input, Sebastian Dalfuß, Daniel Ritz, Max Weninger,
Dmitry Torokhov, Christian Engelmayer
From: Forest Bond <forest.bond@rapidrollout.com>
Certain devices with class HID, protocol None did not work with the HID
driver at one point, and as a result were bound to usbtouchscreen
instead as of commit 139ebe8 ("Input: usbtouchscreen - fix eGalax HID
ignoring"). This change was prompted by the following report:
https://lkml.org/lkml/2009/1/25/127
Unfortunately, the device mentioned in this report is no longer
available for testing.
We've recently discovered that some devices with class HID, protocol
None do not work with usbtouchscreen, but do work with usbhid. Here is
the report that made this evident:
http://comments.gmane.org/gmane.linux.kernel.input/31710
Driver binding for these devices has flip-flopped a few times, so both
of the above reports were regressions.
This situation would appear to leave us with no easy way to bind every
device to the right driver. However, in my own testing with several
devices I have not found a device with class HID that does not work with
the current HID driver. It is my belief that changes to the HID driver
since the original report have likely fixed the issue(s) that made it
unsuitable at the time, and that we should prefer it over usbtouchscreen
for these devices. In particular, HID quirks affecting these devices
were added/removed in the following commits since then:
fe6065d HID: add multi-input quirk for eGalax Touchcontroller
77933c3 Merge branch 'egalax' into for-linus
ebd11fe HID: Add quirk for eGalax touch controler.
d34c4aa HID: add no-get quirk for eGalax touch controller
This patch makes the HID driver no longer ignore eGalax/D-Wav/EETI
devices with class HID. If there are in fact devices with class HID
that still do not work with the HID driver, we will see another round of
regressions. In that case I propose we investigate why the device is
not working with the HID driver rather than re-introduce regressions for
functioning HID devices by again binding them to usbtouchscreen.
The corresponding change to usbtouchscreen will be made separately.
Signed-off-by: Forest Bond <forest.bond@rapidrollout.com>
---
drivers/hid/hid-core.c | 9 ---------
1 file changed, 9 deletions(-)
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 5a8c011..dfcd67f 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -2374,15 +2374,6 @@ bool hid_ignore(struct hid_device *hdev)
hdev->type == HID_TYPE_USBNONE)
return true;
break;
- case USB_VENDOR_ID_DWAV:
- /* These are handled by usbtouchscreen. hdev->type is probably
- * HID_TYPE_USBNONE, but we say !HID_TYPE_USBMOUSE to match
- * usbtouchscreen. */
- if ((hdev->product == USB_DEVICE_ID_EGALAX_TOUCHCONTROLLER ||
- hdev->product == USB_DEVICE_ID_DWAV_TOUCHCONTROLLER) &&
- hdev->type != HID_TYPE_USBMOUSE)
- return true;
- break;
case USB_VENDOR_ID_VELLEMAN:
/* These are not HID devices. They are handled by comedi. */
if ((hdev->product >= USB_DEVICE_ID_VELLEMAN_K8055_FIRST &&
--
1.7.9.5
^ permalink raw reply related
* Re: [PATCH 01/02] input: serio: use DEVICE_ATTR_RO()
From: Dmitry Torokhov @ 2013-10-21 16:25 UTC (permalink / raw)
To: Greg Kroah-Hartman; +Cc: linux-input
In-Reply-To: <20131008010823.GA27012@kroah.com>
Hi Greg,
On Mon, Oct 07, 2013 at 06:08:23PM -0700, Greg Kroah-Hartman wrote:
> From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
>
> Convert the serio sysfs fiels to use the DEVICE_ATTR_RO() macros to make
> it easier to audit the correct sysfs file permission usage.
Sorry for the delay. Frankly I am not a fan of DEVICE_ATTR macros as it
forces particular naming of the attribute structures and methods and
forces us to lose the module prefix in names. I prefer all functions and
file-scope variables have module prefix because in the absence of
language-supported namespaces this is the one thing that insulates
drivers from changes in shared headers.
Thanks.
--
Dmitry
^ permalink raw reply
* Re: [PATCH v2] add sur40 driver for Samsung SUR40 (aka MS Surface 2.0/Pixelsense)
From: Dmitry Torokhov @ 2013-10-21 16:20 UTC (permalink / raw)
To: Florian Echtler; +Cc: linux-input, benjamin.tissoires, rydberg, dh.herrmann
In-Reply-To: <1382287751-21515-1-git-send-email-floe@butterbrot.org>
Hi Florian,
On Sun, Oct 20, 2013 at 06:49:11PM +0200, Florian Echtler wrote:
> From: "Florian \"floe\" Echtler" <floe@butterbrot.org>
>
> This patch adds support for the built-in multitouch sensor in the Samsung
> SUR40 touchscreen device, also known as Microsoft Surface 2.0 or Microsoft
> Pixelsense. Support for raw video output from the sensor as well as the
> accelerometer will be added in a later patch.
>
> Signed-off-by: Florian Echtler <floe@butterbrot.org>
> ---
> drivers/input/touchscreen/Kconfig | 10 +
> drivers/input/touchscreen/Makefile | 1 +
> drivers/input/touchscreen/sur40.c | 446 ++++++++++++++++++++++++++++++++++++
> 3 files changed, 457 insertions(+)
> create mode 100644 drivers/input/touchscreen/sur40.c
>
> diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
> index 515cfe7..99aaf10 100644
> --- a/drivers/input/touchscreen/Kconfig
> +++ b/drivers/input/touchscreen/Kconfig
> @@ -876,6 +876,16 @@ config TOUCHSCREEN_STMPE
> To compile this driver as a module, choose M here: the
> module will be called stmpe-ts.
>
> +config TOUCHSCREEN_SUR40
> + tristate "Samsung SUR40 (Surface 2.0/PixelSense) touchscreen"
> + depends on USB
> + help
> + Say Y here if you want support for the Samsung SUR40 touchscreen
> + (also known as Microsoft Surface 2.0 or Microsoft PixelSense).
> +
> + To compile this driver as a module, choose M here: the
> + module will be called sur40.
> +
> config TOUCHSCREEN_TPS6507X
> tristate "TPS6507x based touchscreens"
> depends on I2C
> diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
> index 6bfbeab..b63a25d 100644
> --- a/drivers/input/touchscreen/Makefile
> +++ b/drivers/input/touchscreen/Makefile
> @@ -51,6 +51,7 @@ obj-$(CONFIG_TOUCHSCREEN_PIXCIR) += pixcir_i2c_ts.o
> obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o
> obj-$(CONFIG_TOUCHSCREEN_ST1232) += st1232.o
> obj-$(CONFIG_TOUCHSCREEN_STMPE) += stmpe-ts.o
> +obj-$(CONFIG_TOUCHSCREEN_SUR40) += sur40.o
> obj-$(CONFIG_TOUCHSCREEN_TI_AM335X_TSC) += ti_am335x_tsc.o
> obj-$(CONFIG_TOUCHSCREEN_TNETV107X) += tnetv107x-ts.o
> obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o
> diff --git a/drivers/input/touchscreen/sur40.c b/drivers/input/touchscreen/sur40.c
> new file mode 100644
> index 0000000..89f5d48
> --- /dev/null
> +++ b/drivers/input/touchscreen/sur40.c
> @@ -0,0 +1,446 @@
> +/*
> + Surface2.0/SUR40/PixelSense input driver
> +
> + This program is free software; you can redistribute it and/or
> + modify it under the terms of the GNU General Public License as
> + published by the Free Software Foundation; either version 2 of
> + the License, or (at your option) any later version.
> +
> + Copyright (c) 2013 by Florian 'floe' Echtler <floe@butterbrot.org>
> +
> + Derived from the USB Skeleton driver 1.1,
> + Copyright (c) 2003 Greg Kroah-Hartman (greg@kroah.com)
> +
> + and from the Apple USB BCM5974 multitouch driver,
> + Copyright (c) 2008 Henrik Rydberg (rydberg@euromail.se)
> +
> + and from the generic hid-multitouch driver,
> + Copyright (c) 2010-2012 Stephane Chatty <chatty@enac.fr>
> +*/
> +
> +#include <linux/kernel.h>
> +#include <linux/errno.h>
> +#include <linux/delay.h>
> +#include <linux/init.h>
> +#include <linux/slab.h>
> +#include <linux/module.h>
> +#include <linux/completion.h>
> +#include <linux/uaccess.h>
> +#include <linux/usb.h>
> +#include <linux/printk.h>
> +#include <linux/input-polldev.h>
> +#include <linux/input/mt.h>
> +#include <linux/usb/input.h>
> +
> +/* read 512 bytes from endpoint 0x86 -> get header + blobs */
> +struct sur40_header {
> +
> + uint16_t type; /* always 0x0001 */
> + uint16_t count; /* count of blobs (if 0: continue prev. packet) */
> +
> + uint32_t packet_id;
> +
> + uint32_t timestamp; /* milliseconds (inc. by 16 or 17 each frame) */
> + uint32_t unknown; /* "epoch?" always 02/03 00 00 00 */
Proper internal kernel types are u8, u16, u32. For user-facing APIs
__u8, __u16, and __u32 should be used. Also, since this is data coming
directly off the wire, you should be using __le16, __le32, etc, and then
do __leXX_to_cpu() conversion before using it in calculations.
> +} __packed;
> +
> +struct sur40_blob {
> +
> + uint16_t blob_id;
> +
> + uint8_t action; /* 0x02 = enter/exit, 0x03 = update (?) */
> + uint8_t unknown; /* always 0x01 or 0x02 (no idea what this is?) */
> +
> + uint16_t bb_pos_x; /* upper left corner of bounding box */
> + uint16_t bb_pos_y;
> +
> + uint16_t bb_size_x; /* size of bounding box */
> + uint16_t bb_size_y;
> +
> + uint16_t pos_x; /* finger tip position */
> + uint16_t pos_y;
> +
> + uint16_t ctr_x; /* centroid position */
> + uint16_t ctr_y;
> +
> + uint16_t axis_x; /* somehow related to major/minor axis, mostly: */
> + uint16_t axis_y; /* axis_x == bb_size_y && axis_y == bb_size_x */
> +
> + float angle; /* orientation in radians relative to x axis */
> + uint32_t area; /* size in pixels/pressure (?) */
> +
> + uint8_t padding[32];
> +} __packed;
> +
> +/* combined header/blob data */
> +struct sur40_data {
> + struct sur40_header header;
> + struct sur40_blob blobs[];
> +} __packed;
> +
> +
> +/* version information */
> +#define DRIVER_SHORT "sur40"
> +#define DRIVER_AUTHOR "Florian 'floe' Echtler <floe@butterbrot.org>"
> +#define DRIVER_DESC "Surface2.0/SUR40/PixelSense input driver"
> +
> +/* vendor and device IDs */
> +#define ID_MICROSOFT 0x045e
> +#define ID_SUR40 0x0775
> +
> +/* sensor resolution */
> +#define SENSOR_RES_X 1920
> +#define SENSOR_RES_Y 1080
> +
> +/* touch data endpoint */
> +#define TOUCH_ENDPOINT 0x86
> +
> +/* polling interval (ms) */
> +#define POLL_INTERVAL 10
> +
> +/* maximum number of contacts FIXME: this is a guess? */
> +#define MAX_CONTACTS 64
> +
> +/* device ID table */
> +static const struct usb_device_id sur40_table[] = {
> + {USB_DEVICE(ID_MICROSOFT, ID_SUR40)}, /* Samsung SUR40 */
> + {} /* terminating null entry */
> +};
> +
> +/* control commands */
> +#define SUR40_GET_VERSION 0xb0 /* 12 bytes string */
> +#define SUR40_UNKNOWN1 0xb3 /* 5 bytes */
> +#define SUR40_UNKNOWN2 0xc1 /* 24 bytes */
> +
> +#define SUR40_GET_STATE 0xc5 /* 4 bytes state (?) */
> +#define SUR40_GET_SENSORS 0xb1 /* 8 bytes sensors */
> +
> +/*
> + * Note: an earlier, non-public version of this driver used USB_RECIP_ENDPOINT
> + * here by mistake which is very likely to have corrupted the firmware EEPROM
> + * on two separate SUR40 devices. Thanks to Alan Stern who spotted this bug.
> + * Should you ever run into a similar problem, the background story to this
> + * incident and instructions on how to fix the corrupted EEPROM are available
> + * at https://floe.butterbrot.org/matrix/hacking/surface/brick.html
> +*/
> +#define sur40_command(dev, command, index, buffer, size) \
> + usb_control_msg(dev->usbdev, usb_rcvctrlpipe(dev->usbdev, 0), \
> + command, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, 0x00, \
> + index, buffer, size, 1000)
> +
> +MODULE_DEVICE_TABLE(usb, sur40_table);
> +
> +/* structure to hold all of our device specific stuff */
> +struct sur40_state {
> +
> + struct usb_device *usbdev; /* save the usb device pointer */
> + struct input_polled_dev *input; /* struct for polled input device */
> +
> + struct sur40_data *bulk_in_buffer; /* the buffer to receive data */
> + size_t bulk_in_size; /* the maximum bulk packet size */
> + __u8 bulk_in_epaddr; /* address of the bulk in endpoint */
> +
> + char phys[64]; /* buffer for phys name */
> +};
> +
> +/* debug helper macro */
> +#define get_dev(x) (&(x->usbdev->dev))
Just stick that dev in sur40_state and then use sur40->dev throughout.
> +
> +/* initialization routine, called from sur40_open */
> +static int sur40_init(struct sur40_state *dev)
> +{
> + int result;
> + __u8 buffer[24];
> +
> + /* stupidly replay the original MS driver init sequence */
> + result = sur40_command(dev, SUR40_GET_VERSION, 0x00, buffer, 12);
> + if (result < 0)
> + return result;
> +
> + result = sur40_command(dev, SUR40_GET_VERSION, 0x01, buffer, 12);
> + if (result < 0)
> + return result;
> +
> + result = sur40_command(dev, SUR40_GET_VERSION, 0x02, buffer, 12);
> + if (result < 0)
> + return result;
> +
> + result = sur40_command(dev, SUR40_UNKNOWN2, 0x00, buffer, 24);
> + if (result < 0)
> + return result;
> +
> + result = sur40_command(dev, SUR40_UNKNOWN1, 0x00, buffer, 5);
> + if (result < 0)
> + return result;
> +
> + result = sur40_command(dev, SUR40_GET_VERSION, 0x03, buffer, 12);
> +
> + /* discard the result buffer - no known data inside except
> + some version strings, maybe extract these sometime.. */
> +
> + return result;
> +}
> +
> +/*
> + * callback routines from input_polled_dev
> +*/
> +
> +/* enable the device, polling will now start */
> +void sur40_open(struct input_polled_dev *polldev)
> +{
> + struct sur40_state *sur40 = polldev->private;
> + dev_dbg(get_dev(sur40), "open\n");
> + sur40_init(sur40);
> +}
> +
> +/* disable device, polling has stopped */
> +void sur40_close(struct input_polled_dev *polldev)
> +{
> + /* no known way to stop the device, except to stop polling */
> + struct sur40_state *sur40 = polldev->private;
> + dev_dbg(get_dev(sur40), "close\n");
> +}
> +
> +/*
> + * this function is called when a whole contact has been processed,
> + * so that it can assign it to a slot and store the data there
> + */
> +static void report_blob(struct sur40_blob *blob, struct input_dev *input)
> +{
> + int wide, major, minor;
> +
> + int slotnum = input_mt_get_slot_by_key(input, blob->blob_id);
> + if (slotnum < 0 || slotnum >= MAX_CONTACTS)
> + return;
> +
> + input_mt_slot(input, slotnum);
> + input_mt_report_slot_state(input, MT_TOOL_FINGER, 1);
> + wide = (blob->bb_size_x > blob->bb_size_y);
> + major = max(blob->bb_size_x, blob->bb_size_y);
> + minor = min(blob->bb_size_x, blob->bb_size_y);
> +
> + input_event(input, EV_ABS, ABS_MT_POSITION_X, blob->pos_x);
> + input_event(input, EV_ABS, ABS_MT_POSITION_Y, blob->pos_y);
> + input_event(input, EV_ABS, ABS_MT_TOOL_X, blob->ctr_x);
> + input_event(input, EV_ABS, ABS_MT_TOOL_Y, blob->ctr_y);
> + /* TODO: use a better orientation measure */
> + input_event(input, EV_ABS, ABS_MT_ORIENTATION, wide);
> + input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, major);
> + input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, minor);
> +}
> +
> +/* core function: poll for new input data */
> +void sur40_poll(struct input_polled_dev *polldev)
> +{
> +
> + struct sur40_state *sur40 = polldev->private;
> + struct input_dev *input = polldev->input;
> + int result, bulk_read, need_blobs, packet_blobs, i;
> + uint32_t packet_id;
> +
> + struct sur40_header *header = &(sur40->bulk_in_buffer->header);
No need to have parenthesis around & operator.
> + struct sur40_blob *inblob = &(sur40->bulk_in_buffer->blobs[0]);
Same here.
> +
> + need_blobs = -1;
> +
> + dev_dbg(get_dev(sur40), "poll\n");
> +
> + do {
> +
> + /* perform a blocking bulk read to get data from the device */
> + result = usb_bulk_msg(sur40->usbdev,
> + usb_rcvbulkpipe(sur40->usbdev, sur40->bulk_in_epaddr),
> + sur40->bulk_in_buffer, sur40->bulk_in_size,
> + &bulk_read, 1000);
> +
> + dev_dbg(get_dev(sur40), "received %d bytes\n", bulk_read);
> +
> + if (result < 0) {
> + dev_err(get_dev(sur40), "error in usb_bulk_read\n");
> + return;
> + }
> +
> + result = bulk_read - sizeof(struct sur40_header);
> +
> + if (result % sizeof(struct sur40_blob) != 0) {
> + dev_err(get_dev(sur40), "transfer size mismatch\n");
> + return;
> + }
> +
> + /* first packet? */
> + if (need_blobs == -1) {
> + need_blobs = header->count;
> + dev_dbg(get_dev(sur40), "need %d blobs\n", need_blobs);
> + packet_id = header->packet_id;
> + }
> +
> + /* sanity check. when video data is also being retrieved, the
> + * packet ID will usually increase in the middle of a series
> + * instead of at the end. */
> + if (packet_id != header->packet_id)
> + dev_warn(get_dev(sur40), "packet ID mismatch\n");
> +
> + packet_blobs = result / sizeof(struct sur40_blob);
> + dev_dbg(get_dev(sur40), "received %d blobs\n", packet_blobs);
> +
> + /* packets always contain at least 4 blobs, even if empty */
> + if (packet_blobs > need_blobs)
> + packet_blobs = need_blobs;
> +
> + for (i = 0; i < packet_blobs; i++) {
> + need_blobs--;
> + dev_dbg(get_dev(sur40), "processing blob\n");
> + report_blob(&(inblob[i]), input);
> + }
> +
> + } while (need_blobs > 0);
> +
> + input_mt_sync_frame(input);
> + input_sync(input);
> +}
> +
> +/*
> + * housekeeping routines
> +*/
> +
> +/* initialize input device parameters */
> +static void sur40_input_setup(struct input_dev *input_dev)
> +{
> + set_bit(EV_KEY, input_dev->evbit);
> + set_bit(EV_SYN, input_dev->evbit);
> + set_bit(EV_ABS, input_dev->evbit);
> +
> + input_set_abs_params(input_dev, ABS_MT_POSITION_X,
> + 0, SENSOR_RES_X, 0, 0);
> + input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
> + 0, SENSOR_RES_Y, 0, 0);
> +
> + input_set_abs_params(input_dev, ABS_MT_TOOL_X,
> + 0, SENSOR_RES_X, 0, 0);
> + input_set_abs_params(input_dev, ABS_MT_TOOL_Y,
> + 0, SENSOR_RES_Y, 0, 0);
> +
> + /* max value unknown, but major/minor axis
> + * can never be larger than screen */
> + input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,
> + 0, SENSOR_RES_X, 0, 0);
> + input_set_abs_params(input_dev, ABS_MT_TOUCH_MINOR,
> + 0, SENSOR_RES_Y, 0, 0);
> +
> + input_set_abs_params(input_dev, ABS_MT_ORIENTATION, 0, 1, 0, 0);
> +
> + input_mt_init_slots(input_dev, MAX_CONTACTS,
> + INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED);
> +}
> +
> +/* clean up all allocated buffers/structs */
> +static inline void sur40_delete(struct sur40_state *sur40)
> +{
> + input_free_polled_device(sur40->input);
> + kfree(sur40->bulk_in_buffer);
> + kfree(sur40);
> +}
> +
> +/* check candidate USB interface */
> +static int sur40_probe(struct usb_interface *interface,
> + const struct usb_device_id *id)
> +{
> + struct usb_device *usbdev = interface_to_usbdev(interface);
> + struct sur40_state *sur40;
> + struct usb_host_interface *iface_desc;
> + struct usb_endpoint_descriptor *endpoint;
> + struct input_polled_dev *poll_dev;
> + int result;
> +
> + /* check if we really have the right interface */
> + iface_desc = &interface->altsetting[0];
> + if (iface_desc->desc.bInterfaceClass != 0xFF)
> + return -ENODEV;
> +
> + /* use endpoint #4 (0x86) */
> + endpoint = &iface_desc->endpoint[4].desc;
> + if (endpoint->bEndpointAddress != TOUCH_ENDPOINT)
> + return -ENODEV;
> +
> + /* allocate memory for our device state and initialize it */
> + sur40 = kzalloc(sizeof(struct sur40_state), GFP_KERNEL);
> + if (!sur40)
> + return -ENOMEM;
> +
> + poll_dev = input_allocate_polled_device();
> + if (!poll_dev) {
> + kfree(sur40);
> + return -ENOMEM;
> + }
> +
> + /* setup polled input device control struct */
> + poll_dev->private = sur40;
> + poll_dev->poll_interval = POLL_INTERVAL;
> + poll_dev->open = sur40_open;
> + poll_dev->poll = sur40_poll;
> + poll_dev->close = sur40_close;
> +
> + /* setup regular input device struct */
> + sur40_input_setup(poll_dev->input);
> +
> + poll_dev->input->name = "Samsung SUR40";
> + usb_to_input_id(usbdev, &(poll_dev->input->id));
> + usb_make_path(usbdev, sur40->phys, sizeof(sur40->phys));
> + strlcat(sur40->phys, "/input0", sizeof(sur40->phys));
> + poll_dev->input->phys = sur40->phys;
> +
> + sur40->usbdev = usbdev;
> + sur40->input = poll_dev;
> +
> + /* use the bulk-in endpoint tested above */
> + sur40->bulk_in_size = le16_to_cpu(endpoint->wMaxPacketSize);
> + sur40->bulk_in_epaddr = endpoint->bEndpointAddress;
> + sur40->bulk_in_buffer = kmalloc(sur40->bulk_in_size, GFP_KERNEL);
> + if (!sur40->bulk_in_buffer) {
> + dev_err(&interface->dev, "Unable to allocate input buffer.");
> + sur40_delete(sur40);
Would prefer standard kernel error unwinding style (gotos to proper
unwinding point).
> + return -ENOMEM;
> + }
> +
> + result = input_register_polled_device(poll_dev);
> + if (result) {
> + dev_err(&interface->dev,
> + "Unable to register polled input device.");
> + sur40_delete(sur40);
> + return result;
> + }
> +
> + /* we can register the device now, as it is ready */
> + usb_set_intfdata(interface, sur40);
> + dev_dbg(&interface->dev, "%s now attached\n", DRIVER_DESC);
> +
> + return 0;
> +}
> +
> +/* unregister device & clean up */
> +static void sur40_disconnect(struct usb_interface *interface)
> +{
> + struct sur40_state *sur40 = usb_get_intfdata(interface);
> +
> + input_unregister_polled_device(sur40->input);
> +
> + usb_set_intfdata(interface, NULL);
> +
> + sur40_delete(sur40);
> +
> + dev_dbg(&interface->dev, "%s now disconnected\n", DRIVER_DESC);
> +}
> +
> +/* usb specific object needed to register this driver with the usb subsystem */
> +static struct usb_driver sur40_driver = {
> + .name = DRIVER_SHORT,
> + .probe = sur40_probe,
> + .disconnect = sur40_disconnect,
> + .id_table = sur40_table,
> +};
> +
> +module_usb_driver(sur40_driver);
> +
> +MODULE_AUTHOR(DRIVER_AUTHOR);
> +MODULE_DESCRIPTION(DRIVER_DESC);
> +MODULE_LICENSE("GPL");
> --
> 1.7.9.5
>
Thanks.
--
Dmitry
^ permalink raw reply
* Re: [PATCHv4][ 1/4] Input: tsc2007: Add device tree support.
From: Dmitry Torokhov @ 2013-10-21 15:59 UTC (permalink / raw)
To: Denis Carikli
Cc: Lothar Waßmann, linux-input, Sascha Hauer, linux-arm-kernel,
Eric Bénard, Rob Herring, Pawel Moll, Mark Rutland,
Stephen Warren, Ian Campbell, devicetree
In-Reply-To: <1382363667-10341-1-git-send-email-denis@eukrea.com>
Hi Denis,
On Mon, Oct 21, 2013 at 03:54:24PM +0200, Denis Carikli wrote:
>
> + if (ts->of)
> + return tsc2007_get_pendown_state_dt(ts);
> +
> if (!ts->get_pendown_state)
> return true;
Instead of special casing "if (ts->of)" all over the place why don't you
set up the device structure as:
if (<configuring_tsc2007_form_dt>)
ts->get_pendown_state = tsc2007_get_pendown_state_dt;
and be done with it?
Thanks.
--
Dmitry
^ permalink raw reply
* Re: [PATCH] Input: add regulator haptic driver
From: Dmitry Torokhov @ 2013-10-21 15:55 UTC (permalink / raw)
To: hyunhee.kim
Cc: broonie, peter.ujfalusi, wfp5p, linux-input, linux-kernel, akpm,
kyungmin.park, Aristeu Sergio Rozanski Filho
In-Reply-To: <000a01cec629$3cf34de0$b6d9e9a0$%kim@samsung.com>
Hi Hyunhee,
On Fri, Oct 11, 2013 at 11:26:05AM +0900, hyunhee.kim wrote:
> From: Hyunhee Kim <hyunhee.kim@samsung.com>
> Date: Wed, 9 Oct 2013 16:21:36 +0900
> Subject: [PATCH] Input: add regulator haptic driver
>
> The regulator haptic driver function can be used to control motor by on/off
> regulator.
> User can control the haptic driver by using force feedback framework.
>
> Signed-off-by: Hyunhee Kim <hyunhee.kim@samsung.com>
> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
> ---
> drivers/input/misc/Kconfig | 6 ++
> drivers/input/misc/Makefile | 1 +
> drivers/input/misc/regulator-haptic.c | 185
> +++++++++++++++++++++++++++++++++
> 3 files changed, 192 insertions(+)
> create mode 100644 drivers/input/misc/regulator-haptic.c
>
> diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
> index bb698e1..f391cd7 100644
> --- a/drivers/input/misc/Kconfig
> +++ b/drivers/input/misc/Kconfig
> @@ -82,6 +82,12 @@ config INPUT_ARIZONA_HAPTICS
> To compile this driver as a module, choose M here: the
> module will be called arizona-haptics.
>
> +config INPUT_REGULATOR_HAPTIC
> + tristate "regulator haptics support"
This option should be worded better I think.
> + select INPUT_FF_MEMLESS
> + help
> + Say Y to enable support for the haptics module for regulator.
And explained better to. Also please add "To compile this driver as a
module..."
> +
> config INPUT_BMA150
> tristate "BMA150/SMB380 acceleration sensor support"
> depends on I2C
> diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
> index d7fc17f..106f0bc 100644
> --- a/drivers/input/misc/Makefile
> +++ b/drivers/input/misc/Makefile
> @@ -15,6 +15,7 @@ obj-$(CONFIG_INPUT_ADXL34X_I2C) +=
> adxl34x-i2c.o
> obj-$(CONFIG_INPUT_ADXL34X_SPI) += adxl34x-spi.o
> obj-$(CONFIG_INPUT_APANEL) += apanel.o
> obj-$(CONFIG_INPUT_ARIZONA_HAPTICS) += arizona-haptics.o
> +obj-$(CONFIG_INPUT_REGULATOR_HAPTIC) += regulator-haptic.o
> obj-$(CONFIG_INPUT_ATI_REMOTE2) += ati_remote2.o
> obj-$(CONFIG_INPUT_ATLAS_BTNS) += atlas_btns.o
> obj-$(CONFIG_INPUT_BFIN_ROTARY) += bfin_rotary.o
> diff --git a/drivers/input/misc/regulator-haptic.c
> b/drivers/input/misc/regulator-haptic.c
> new file mode 100644
> index 0000000..29f57ea
> --- /dev/null
> +++ b/drivers/input/misc/regulator-haptic.c
> @@ -0,0 +1,185 @@
> +/*
> + * Regulator haptic driver
> + *
> + * Copyright (c) 2013 Samsung Electronics Co., Ltd.
> + *
> + * Author: Hyunhee Kim <hyunhee.kim@samsung.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/input.h>
> +#include <linux/slab.h>
> +#include <linux/regulator/driver.h>
> +
> +struct regulator_haptic {
> + struct device *dev;
> + struct input_dev *input_dev;
> + struct work_struct work;
> + bool enabled;
> + struct regulator *regulator;
> + struct mutex mutex;
> + int level;
> +};
> +
> +static void regulator_haptic_enable(struct regulator_haptic *haptic, bool
> enable)
> +{
> + int ret;
> +
> + mutex_lock(&haptic->mutex);
> + if (enable && !haptic->enabled) {
> + haptic->enabled = true;
> + ret = regulator_enable(haptic->regulator);
> + if (ret)
> + pr_err("haptic: %s failed to enable regulator\n",
> + __func__);
Please use dev_err() here and also stick error code into the message.
> + } else if (!enable && haptic->enabled) {
> + haptic->enabled = false;
> + ret = regulator_disable(haptic->regulator);
> + if (ret)
> + pr_err("haptic: %s failed to disable regulator\n",
> + __func__);
> + }
> + mutex_unlock(&haptic->mutex);
I wonder if you want separate functions for regulator_haptic_enable and
regulator_haptic_disable seeing how you are using it later in the code.
If not then ...
> +}
> +
> +static void regulator_haptic_work(struct work_struct *work)
> +{
> + struct regulator_haptic *haptic = container_of(work,
> + struct
> regulator_haptic,
> + work);
> + if (haptic->level)
> + regulator_haptic_enable(haptic, true);
> + else
> + regulator_haptic_enable(haptic, false);
... just say:
regulator_haptic_toggle(haptic, haptic->level != 0);
> +
> +}
> +
> +static int regulator_haptic_play(struct input_dev *input, void *data,
> + struct ff_effect *effect)
> +{
> + struct regulator_haptic *haptic = input_get_drvdata(input);
> +
> + haptic->level = effect->u.rumble.strong_magnitude;
> + if (!haptic->level)
> + haptic->level = effect->u.rumble.weak_magnitude;
> + schedule_work(&haptic->work);
> +
> + return 0;
> +}
> +
> +static void regulator_haptic_close(struct input_dev *input)
> +{
> + struct regulator_haptic *haptic = input_get_drvdata(input);
> +
> + cancel_work_sync(&haptic->work);
> + regulator_haptic_enable(haptic, false);
> +}
> +
> +static int regulator_haptic_probe(struct platform_device *pdev)
> +{
> + struct regulator_haptic *haptic;
> + struct input_dev *input_dev;
> + int error;
> +
> + haptic = kzalloc(sizeof(*haptic), GFP_KERNEL);
> + if (!haptic) {
> + dev_err(&pdev->dev, "unable to allocate memory for
> haptic\n");
> + return -ENOMEM;
> + }
> +
> + input_dev = input_allocate_device();
> +
> + if (!input_dev) {
> + dev_err(&pdev->dev, "unable to allocate memory\n");
> + error = -ENOMEM;
> + goto err_kfree_mem;
> + }
> +
> + INIT_WORK(&haptic->work, regulator_haptic_work);
> + mutex_init(&haptic->mutex);
> + haptic->input_dev = input_dev;
> + haptic->dev = &pdev->dev;
> + haptic->regulator = regulator_get(&pdev->dev, "haptic");
> +
> + if (IS_ERR(haptic->regulator)) {
> + error = PTR_ERR(haptic->regulator);
> + dev_err(&pdev->dev, "unable to get regulator, err: %d\n",
> + error);
> + goto err_ifree_mem;
> + }
> +
> + haptic->input_dev->name = "regulator:haptic";
> + haptic->input_dev->dev.parent = &pdev->dev;
> + haptic->input_dev->close = regulator_haptic_close;
> + haptic->enabled = false;
> + input_set_drvdata(haptic->input_dev, haptic);
> + input_set_capability(haptic->input_dev, EV_FF, FF_RUMBLE);
> +
> + error = input_ff_create_memless(input_dev, NULL,
> + regulator_haptic_play);
> + if (error) {
> + dev_err(&pdev->dev,
> + "input_ff_create_memless() failed: %d\n",
> + error);
> + goto err_put_regulator;
> + }
> +
> + error = input_register_device(haptic->input_dev);
> + if (error) {
> + dev_err(&pdev->dev,
> + "couldn't register input device: %d\n",
> + error);
> + goto err_destroy_ff;
> + }
> +
> + platform_set_drvdata(pdev, haptic);
> +
> + return 0;
> +
> +err_destroy_ff:
> + input_ff_destroy(haptic->input_dev);
> +err_put_regulator:
> + regulator_put(haptic->regulator);
> +err_ifree_mem:
> + input_free_device(haptic->input_dev);
> +err_kfree_mem:
> + kfree(haptic);
> +
> + return error;
> +}
> +
> +static int regulator_haptic_remove(struct platform_device *pdev)
> +{
> + struct regulator_haptic *haptic = platform_get_drvdata(pdev);
> +
> + input_unregister_device(haptic->input_dev);
I think you are leaking reference to regulator and memory allocated for
the haptic structure here. Maybe it should all be converted to devm.
> +
> + return 0;
> +}
> +
> +static struct of_device_id regulator_haptic_dt_match[] = {
> + { .compatible = "linux,regulator-haptic" },
> + {},
> +};
> +
> +static struct platform_driver regulator_haptic_driver = {
> + .driver = {
> + .name = "regulator-haptic",
> + .owner = THIS_MODULE,
> + .of_match_table = regulator_haptic_dt_match,
> + },
> +
> + .probe = regulator_haptic_probe,
> + .remove = regulator_haptic_remove,
> +};
> +module_platform_driver(regulator_haptic_driver);
> +
> +MODULE_ALIAS("platform:regulator-haptic");
> +MODULE_DESCRIPTION("Regulator haptic driver");
> +MODULE_LICENSE("GPL");
> +MODULE_AUTHOR("Hyunhee Kim <hyunhee.kim@samsung.com>");
> --
> 1.7.9.5
>
>
Thanks.
--
Dmitry
^ permalink raw reply
* [PATCHv4][ 4/4] ARM: imx_v6_v7_defconfig: Enable tsc2007 support.
From: Denis Carikli @ 2013-10-21 13:54 UTC (permalink / raw)
To: Lothar Waßmann, Dmitry Torokhov
Cc: linux-input, Sascha Hauer, linux-arm-kernel, Eric Bénard,
Denis Carikli, Rob Herring, Pawel Moll, Mark Rutland,
Stephen Warren, Ian Campbell, devicetree, Fabio Estevam,
Shawn Guo
In-Reply-To: <1382363667-10341-1-git-send-email-denis@eukrea.com>
The eukrea cpuimx35 and cpuimx51 have a tsc2007 touchscreen controller,
so we turn it on.
Cc: Rob Herring <rob.herring@calxeda.com>
Cc: Pawel Moll <pawel.moll@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Stephen Warren <swarren@wwwdotorg.org>
Cc: Ian Campbell <ijc+devicetree@hellion.org.uk>
Cc: devicetree@vger.kernel.org
Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Cc: linux-input@vger.kernel.org
Cc: Sascha Hauer <kernel@pengutronix.de>
Cc: linux-arm-kernel@lists.infradead.org
Cc: Lothar Waßmann <LW@KARO-electronics.de>
Cc: Fabio Estevam <fabio.estevam@freescale.com>
Cc: Shawn Guo <shawn.guo@linaro.org>
Cc: Eric Bénard <eric@eukrea.com>
Signed-off-by: Denis Carikli <denis@eukrea.com>
---
ChangeLog v2->v4:
- This patch was splitted, only the part enabling the audio was kept.
Part of the rest has already been submited, and the remaining parts
will be submited later, because they depend on changes touching other
subsystems.
---
arch/arm/configs/imx_v6_v7_defconfig | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/arm/configs/imx_v6_v7_defconfig b/arch/arm/configs/imx_v6_v7_defconfig
index d8a52a0..23ba17d 100644
--- a/arch/arm/configs/imx_v6_v7_defconfig
+++ b/arch/arm/configs/imx_v6_v7_defconfig
@@ -130,6 +130,7 @@ CONFIG_MOUSE_PS2_ELANTECH=y
CONFIG_INPUT_TOUCHSCREEN=y
CONFIG_TOUCHSCREEN_EGALAX=y
CONFIG_TOUCHSCREEN_MC13783=y
+CONFIG_TOUCHSCREEN_TSC2007=y
CONFIG_INPUT_MISC=y
CONFIG_INPUT_MMA8450=y
CONFIG_SERIO_SERPORT=m
--
1.7.9.5
--
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 related
* [PATCHv4][ 2/4] ARM: dts: cpuimx51 Add touchscreen support.
From: Denis Carikli @ 2013-10-21 13:54 UTC (permalink / raw)
To: Lothar Waßmann, Dmitry Torokhov
Cc: linux-input, Sascha Hauer, linux-arm-kernel, Eric Bénard,
Denis Carikli, Rob Herring, Pawel Moll, Mark Rutland,
Stephen Warren, Ian Campbell, devicetree
In-Reply-To: <1382363667-10341-1-git-send-email-denis@eukrea.com>
Cc: Rob Herring <rob.herring@calxeda.com>
Cc: Pawel Moll <pawel.moll@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Stephen Warren <swarren@wwwdotorg.org>
Cc: Ian Campbell <ijc+devicetree@hellion.org.uk>
Cc: devicetree@vger.kernel.org
Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Cc: linux-input@vger.kernel.org
Cc: Sascha Hauer <kernel@pengutronix.de>
Cc: linux-arm-kernel@lists.infradead.org
Cc: Lothar Waßmann <LW@KARO-electronics.de>
Cc: Eric Bénard <eric@eukrea.com>
Signed-off-by: Denis Carikli <denis@eukrea.com>
---
ChangeLog v2->v4:
- This patch was splitted, only the part enabling the audio was kept.
Part of the rest has already been submited, and the remaining parts
will be submited later, because they depend on changes touching other
subsystems.
- The x-plate-ohms property was renamed to ti,x-plate-ohms.
- The tsc2007 label was added for consistency.
---
arch/arm/boot/dts/imx51-eukrea-cpuimx51.dtsi | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/arch/arm/boot/dts/imx51-eukrea-cpuimx51.dtsi b/arch/arm/boot/dts/imx51-eukrea-cpuimx51.dtsi
index 8638656..34ca8d3a 100644
--- a/arch/arm/boot/dts/imx51-eukrea-cpuimx51.dtsi
+++ b/arch/arm/boot/dts/imx51-eukrea-cpuimx51.dtsi
@@ -42,6 +42,17 @@
compatible = "nxp,pcf8563";
reg = <0x51>;
};
+
+ tsc2007: tsc2007@49 {
+ compatible = "ti,tsc2007";
+ reg = <0x49>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_tsc2007_1>;
+ interrupt-parent = <&gpio4>;
+ interrupts = <0x0 0x8>;
+ gpios = <&gpio4 0 0>;
+ ti,x-plate-ohms = <180>;
+ };
};
&iomuxc {
--
1.7.9.5
--
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 related
* [PATCHv4][ 1/4] Input: tsc2007: Add device tree support.
From: Denis Carikli @ 2013-10-21 13:54 UTC (permalink / raw)
To: Lothar Waßmann, Dmitry Torokhov
Cc: linux-input, Sascha Hauer, linux-arm-kernel, Eric Bénard,
Denis Carikli, Rob Herring, Pawel Moll, Mark Rutland,
Stephen Warren, Ian Campbell, devicetree
Cc: Rob Herring <rob.herring@calxeda.com>
Cc: Pawel Moll <pawel.moll@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Stephen Warren <swarren@wwwdotorg.org>
Cc: Ian Campbell <ijc+devicetree@hellion.org.uk>
Cc: devicetree@vger.kernel.org
Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Cc: linux-input@vger.kernel.org
Cc: Sascha Hauer <kernel@pengutronix.de>
Cc: linux-arm-kernel@lists.infradead.org
Cc: Lothar Waßmann <LW@KARO-electronics.de>
Cc: Eric Bénard <eric@eukrea.com>
Signed-off-by: Denis Carikli <denis@eukrea.com>
---
ChangeLog v2->v4:
- The x-plate-ohms property was renamed to ti,x-plate-ohms.
- multilines strings were avoided.
- shorten the message related to the lack of ti,x-plate-ohms in the dts.
- whitespace fix in tsc2007_get_pendown_state_dt(struct tsc2007 *ts)
- (ts->gpio < 0) replaced by !gpio_is_valid(ts->gpio)
- devm_kzalloc is now used instead of kzalloc, and some minor code change was
made because of that.
---
.../bindings/input/touchscreen/tsc2007.txt | 44 +++++
drivers/input/touchscreen/tsc2007.c | 201 +++++++++++++++-----
2 files changed, 200 insertions(+), 45 deletions(-)
create mode 100644 Documentation/devicetree/bindings/input/touchscreen/tsc2007.txt
diff --git a/Documentation/devicetree/bindings/input/touchscreen/tsc2007.txt b/Documentation/devicetree/bindings/input/touchscreen/tsc2007.txt
new file mode 100644
index 0000000..fadd3f6
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/touchscreen/tsc2007.txt
@@ -0,0 +1,44 @@
+* Texas Instruments tsc2007 touchscreen controller
+
+Required properties:
+- compatible: must be "ti,tsc2007".
+- reg: I2C address of the chip.
+- pinctrl-0: Should specify pin control groups used for this controller
+ (see pinctrl bindings[0]).
+- pinctrl-names: Should contain only one value - "default"
+ (see pinctrl bindings[0]).
+- interrupt-parent: the phandle for the interrupt controller
+ (see interrupt binding[1]).
+- interrupts: interrupt to which the chip is connected
+ (see interrupt binding[1]).
+- ti,x-plate-ohms: X-plate resistance in ohms.
+
+Optional properties:
+- gpios: the interrupt gpio the chip is connected to (trough the penirq pin)
+ (see GPIO binding[2] for more details).
+- max-rt: maximum pressure.
+- fuzzy: specifies the fuzz value that is used to filter noise from the event
+ stream.
+- poll-period: how much time to wait(in millisecond) before reading again the
+ values from the tsc2007.
+
+[0]: Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt
+[1]: Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
+[2]: Documentation/devicetree/bindings/gpio/gpio.txt
+
+Example:
+ &i2c1 {
+ /* ... */
+ tsc2007@49 {
+ compatible = "ti,tsc2007";
+ reg = <0x49>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_tsc2007_1>;
+ interrupt-parent = <&gpio4>;
+ interrupts = <0x0 0x8>;
+ gpios = <&gpio4 0 0>;
+ ti,x-plate-ohms = <180>;
+ };
+
+ /* ... */
+ };
diff --git a/drivers/input/touchscreen/tsc2007.c b/drivers/input/touchscreen/tsc2007.c
index 0b67ba4..3143ebc 100644
--- a/drivers/input/touchscreen/tsc2007.c
+++ b/drivers/input/touchscreen/tsc2007.c
@@ -26,6 +26,9 @@
#include <linux/interrupt.h>
#include <linux/i2c.h>
#include <linux/i2c/tsc2007.h>
+#include <linux/of_device.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
#define TSC2007_MEASURE_TEMP0 (0x0 << 4)
#define TSC2007_MEASURE_AUX (0x2 << 4)
@@ -74,7 +77,10 @@ struct tsc2007 {
u16 max_rt;
unsigned long poll_delay;
unsigned long poll_period;
+ int fuzzy;
+ char of;
+ unsigned gpio;
int irq;
wait_queue_head_t wait;
@@ -84,6 +90,14 @@ struct tsc2007 {
void (*clear_penirq)(void);
};
+static int tsc2007_get_pendown_state_dt(struct tsc2007 *ts)
+{
+ if (gpio_is_valid(ts->gpio))
+ return !gpio_get_value(ts->gpio);
+ else
+ return true;
+}
+
static inline int tsc2007_xfer(struct tsc2007 *tsc, u8 cmd)
{
s32 data;
@@ -158,6 +172,9 @@ static bool tsc2007_is_pen_down(struct tsc2007 *ts)
* to fall back on the pressure reading.
*/
+ if (ts->of)
+ return tsc2007_get_pendown_state_dt(ts);
+
if (!ts->get_pendown_state)
return true;
@@ -175,10 +192,10 @@ static irqreturn_t tsc2007_soft_irq(int irq, void *handle)
/* pen is down, continue with the measurement */
tsc2007_read_values(ts, &tc);
-
rt = tsc2007_calculate_pressure(ts, &tc);
- if (rt == 0 && !ts->get_pendown_state) {
+ if ((ts->of && rt == 0 && !gpio_is_valid(ts->gpio)) ||
+ (!ts->of && rt == 0 && !ts->get_pendown_state)) {
/*
* If pressure reported is 0 and we don't have
* callback to check pendown state, we have to
@@ -198,7 +215,6 @@ static irqreturn_t tsc2007_soft_irq(int irq, void *handle)
input_report_abs(input, ABS_PRESSURE, rt);
input_sync(input);
-
} else {
/*
* Sample found inconsistent by debouncing or pressure is
@@ -217,7 +233,6 @@ static irqreturn_t tsc2007_soft_irq(int irq, void *handle)
input_report_key(input, BTN_TOUCH, 0);
input_report_abs(input, ABS_PRESSURE, 0);
input_sync(input);
-
if (ts->clear_penirq)
ts->clear_penirq();
@@ -228,11 +243,17 @@ static irqreturn_t tsc2007_hard_irq(int irq, void *handle)
{
struct tsc2007 *ts = handle;
- if (!ts->get_pendown_state || likely(ts->get_pendown_state()))
- return IRQ_WAKE_THREAD;
+ if (!ts->of) {
+ if (!ts->get_pendown_state || likely(ts->get_pendown_state()))
+ return IRQ_WAKE_THREAD;
- if (ts->clear_penirq)
- ts->clear_penirq();
+ if (ts->clear_penirq)
+ ts->clear_penirq();
+ } else {
+ if ((!gpio_is_valid(ts->gpio)) ||
+ likely(tsc2007_get_pendown_state_dt(ts)))
+ return IRQ_WAKE_THREAD;
+ }
return IRQ_HANDLED;
}
@@ -273,34 +294,65 @@ static void tsc2007_close(struct input_dev *input_dev)
tsc2007_stop(ts);
}
-static int tsc2007_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+#ifdef CONFIG_OF
+static int tsc2007_probe_dt(struct i2c_client *client, struct tsc2007 *ts,
+ struct device_node *np)
{
- struct tsc2007 *ts;
- struct tsc2007_platform_data *pdata = client->dev.platform_data;
- struct input_dev *input_dev;
- int err;
-
- if (!pdata) {
- dev_err(&client->dev, "platform data is required!\n");
+ int err = 0;
+ u32 val32;
+ u64 val64;
+
+ if (!of_property_read_u32(np, "max-rt", &val32))
+ ts->max_rt = val32;
+ else
+ ts->max_rt = MAX_12BIT;
+
+ if (!of_property_read_u32(np, "fuzzy", &val32))
+ ts->fuzzy = val32;
+
+ if (!of_property_read_u64(np, "poll-period", &val64))
+ ts->poll_period = val64;
+ else
+ ts->poll_period = 1;
+
+ if (!of_property_read_u32(np, "ti,x-plate-ohms", &val32)) {
+ ts->x_plate_ohms = val32;
+ } else {
+ dev_err(&client->dev,
+ "Error: lacking ti,x-plate-ohms devicetree property. (err %d).",
+ err);
return -EINVAL;
}
- if (!i2c_check_functionality(client->adapter,
- I2C_FUNC_SMBUS_READ_WORD_DATA))
- return -EIO;
+ ts->gpio = of_get_gpio(np, 0);
+ if (!gpio_is_valid(ts->gpio))
+ dev_err(&client->dev,
+ "GPIO not found (of_get_gpio returned %d)\n",
+ ts->gpio);
- ts = kzalloc(sizeof(struct tsc2007), GFP_KERNEL);
- input_dev = input_allocate_device();
- if (!ts || !input_dev) {
- err = -ENOMEM;
- goto err_free_mem;
- }
+ /* Used to detect if it is probed trough the device tree,
+ * in order to be able to use that information in the IRQ handler.
+ */
+ ts->of = 1;
- ts->client = client;
- ts->irq = client->irq;
- ts->input = input_dev;
- init_waitqueue_head(&ts->wait);
+ return 0;
+}
+#else
+static int tsc2007_probe_dt(struct i2c_client *client, struct tsc2007 *ts,
+ struct device_node *np)
+{
+ return -ENODEV;
+}
+#endif
+
+static int tsc2007_probe_pdev(struct i2c_client *client, struct tsc2007 *ts,
+ struct tsc2007_platform_data *pdata,
+ const struct i2c_device_id *id)
+{
+ if (!pdata) {
+ dev_err(&client->dev, "platform data is required!\n");
+ return -EINVAL;
+ }
ts->model = pdata->model;
ts->x_plate_ohms = pdata->x_plate_ohms;
@@ -309,13 +361,57 @@ static int tsc2007_probe(struct i2c_client *client,
ts->poll_period = pdata->poll_period ? : 1;
ts->get_pendown_state = pdata->get_pendown_state;
ts->clear_penirq = pdata->clear_penirq;
+ ts->fuzzy = pdata->fuzzy;
if (pdata->x_plate_ohms == 0) {
dev_err(&client->dev, "x_plate_ohms is not set up in platform data");
- err = -EINVAL;
- goto err_free_mem;
+ return -EINVAL;
}
+ /* Used to detect if it is probed trough the device tree,
+ * in order to be able to use that information in the IRQ handler.
+ */
+ ts->of = 0;
+
+ return 0;
+}
+
+static int tsc2007_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct device_node *np = client->dev.of_node;
+ struct tsc2007_platform_data *pdata = client->dev.platform_data;
+ struct tsc2007 *ts;
+ struct input_dev *input_dev;
+ int err = 0;
+
+ ts = devm_kzalloc(sizeof(struct tsc2007), GFP_KERNEL);
+ if (!ts)
+ return -ENOMEM;
+
+ if (np)
+ err = tsc2007_probe_dt(client, ts, np);
+ else
+ err = tsc2007_probe_pdev(client, ts, pdata, id);
+
+ if (err)
+ return err;
+
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_READ_WORD_DATA))
+ return -EIO;
+
+ input_dev = input_allocate_device();
+ if (!input_dev) {
+ err = -ENOMEM;
+ goto err_free_input;
+ };
+
+ ts->client = client;
+ ts->irq = client->irq;
+ ts->input = input_dev;
+ init_waitqueue_head(&ts->wait);
+
snprintf(ts->phys, sizeof(ts->phys),
"%s/input0", dev_name(&client->dev));
@@ -331,19 +427,21 @@ static int tsc2007_probe(struct i2c_client *client,
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
- input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, pdata->fuzzx, 0);
- input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, pdata->fuzzy, 0);
+ input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, ts->fuzzy, 0);
+ input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, ts->fuzzy, 0);
input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_12BIT,
- pdata->fuzzz, 0);
+ ts->fuzzy, 0);
- if (pdata->init_platform_hw)
- pdata->init_platform_hw();
+ if (!np) {
+ if (pdata->init_platform_hw)
+ pdata->init_platform_hw();
+ }
err = request_threaded_irq(ts->irq, tsc2007_hard_irq, tsc2007_soft_irq,
IRQF_ONESHOT, client->dev.driver->name, ts);
if (err < 0) {
dev_err(&client->dev, "irq %d busy?\n", ts->irq);
- goto err_free_mem;
+ goto err_free_input;
}
tsc2007_stop(ts);
@@ -358,23 +456,27 @@ static int tsc2007_probe(struct i2c_client *client,
err_free_irq:
free_irq(ts->irq, ts);
- if (pdata->exit_platform_hw)
- pdata->exit_platform_hw();
- err_free_mem:
+ if (!np) {
+ if (pdata->exit_platform_hw)
+ pdata->exit_platform_hw();
+ }
+ err_free_input:
input_free_device(input_dev);
- kfree(ts);
return err;
}
static int tsc2007_remove(struct i2c_client *client)
{
+ struct device_node *np = client->dev.of_node;
struct tsc2007 *ts = i2c_get_clientdata(client);
struct tsc2007_platform_data *pdata = client->dev.platform_data;
free_irq(ts->irq, ts);
- if (pdata->exit_platform_hw)
- pdata->exit_platform_hw();
+ if (!np) {
+ if (pdata->exit_platform_hw)
+ pdata->exit_platform_hw();
+ }
input_unregister_device(ts->input);
kfree(ts);
@@ -389,10 +491,19 @@ static const struct i2c_device_id tsc2007_idtable[] = {
MODULE_DEVICE_TABLE(i2c, tsc2007_idtable);
+#ifdef CONFIG_OF
+static const struct of_device_id tsc2007_of_match[] = {
+ { .compatible = "ti,tsc2007" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, tsc2007_of_match);
+#endif
+
static struct i2c_driver tsc2007_driver = {
.driver = {
.owner = THIS_MODULE,
- .name = "tsc2007"
+ .name = "tsc2007",
+ .of_match_table = of_match_ptr(tsc2007_of_match),
},
.id_table = tsc2007_idtable,
.probe = tsc2007_probe,
--
1.7.9.5
--
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 related
* [PATCHv4][ 3/4] ARM: dts: cpuimx35 Add touchscreen support.
From: Denis Carikli @ 2013-10-21 13:54 UTC (permalink / raw)
To: Lothar Waßmann, Dmitry Torokhov
Cc: Mark Rutland, devicetree, Sascha Hauer, Pawel Moll,
Stephen Warren, Ian Campbell, Rob Herring, Denis Carikli,
Eric Bénard, linux-input, linux-arm-kernel
In-Reply-To: <1382363667-10341-1-git-send-email-denis@eukrea.com>
Cc: Rob Herring <rob.herring@calxeda.com>
Cc: Pawel Moll <pawel.moll@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Stephen Warren <swarren@wwwdotorg.org>
Cc: Ian Campbell <ijc+devicetree@hellion.org.uk>
Cc: devicetree@vger.kernel.org
Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Cc: linux-input@vger.kernel.org
Cc: Sascha Hauer <kernel@pengutronix.de>
Cc: linux-arm-kernel@lists.infradead.org
Cc: Lothar Waßmann <LW@KARO-electronics.de>
Cc: Eric Bénard <eric@eukrea.com>
Signed-off-by: Denis Carikli <denis@eukrea.com>
---
ChangeLog v2->v4:
- This patch was splitted, only the part enabling the audio was kept.
Part of the rest has already been submited, and the remaining parts
will be submited later, because they depend on changes touching other
subsystems.
- The x-plate-ohms property was renamed to ti,x-plate-ohms.
---
arch/arm/boot/dts/imx35-eukrea-cpuimx35.dtsi | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/arch/arm/boot/dts/imx35-eukrea-cpuimx35.dtsi b/arch/arm/boot/dts/imx35-eukrea-cpuimx35.dtsi
index 2c2d4cd..a22230b 100644
--- a/arch/arm/boot/dts/imx35-eukrea-cpuimx35.dtsi
+++ b/arch/arm/boot/dts/imx35-eukrea-cpuimx35.dtsi
@@ -41,6 +41,17 @@
compatible = "nxp,pcf8563";
reg = <0x51>;
};
+
+ tsc2007: tsc2007@48 {
+ compatible = "ti,tsc2007";
+ reg = <0x48>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_tsc2007_1>;
+ interrupt-parent = <&gpio3>;
+ interrupts = <0x2 0x8>;
+ gpios = <&gpio3 2 0>;
+ ti,x-plate-ohms = <180>;
+ };
};
&iomuxc {
--
1.7.9.5
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* Re: [PATCH] Input: add regulator haptic driver
From: Aristeu Sergio Rozanski Filho @ 2013-10-21 12:10 UTC (permalink / raw)
To: hyunhee.kim
Cc: dmitry.torokhov, broonie, peter.ujfalusi, wfp5p, linux-input,
linux-kernel, akpm, kyungmin.park
In-Reply-To: <000a01cec629$3cf34de0$b6d9e9a0$%kim@samsung.com>
On Fri, Oct 11, 2013 at 11:26:05AM +0900, hyunhee.kim wrote:
> The regulator haptic driver function can be used to control motor by on/off
> regulator.
> User can control the haptic driver by using force feedback framework.
>
> Signed-off-by: Hyunhee Kim <hyunhee.kim@samsung.com>
> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
> ---
> drivers/input/misc/Kconfig | 6 ++
> drivers/input/misc/Makefile | 1 +
> drivers/input/misc/regulator-haptic.c | 185
> +++++++++++++++++++++++++++++++++
> 3 files changed, 192 insertions(+)
> create mode 100644 drivers/input/misc/regulator-haptic.c
>
> diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
> index bb698e1..f391cd7 100644
> --- a/drivers/input/misc/Kconfig
> +++ b/drivers/input/misc/Kconfig
> @@ -82,6 +82,12 @@ config INPUT_ARIZONA_HAPTICS
> To compile this driver as a module, choose M here: the
> module will be called arizona-haptics.
>
> +config INPUT_REGULATOR_HAPTIC
> + tristate "regulator haptics support"
> + select INPUT_FF_MEMLESS
> + help
> + Say Y to enable support for the haptics module for regulator.
> +
> config INPUT_BMA150
> tristate "BMA150/SMB380 acceleration sensor support"
> depends on I2C
> diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
> index d7fc17f..106f0bc 100644
> --- a/drivers/input/misc/Makefile
> +++ b/drivers/input/misc/Makefile
> @@ -15,6 +15,7 @@ obj-$(CONFIG_INPUT_ADXL34X_I2C) +=
> adxl34x-i2c.o
> obj-$(CONFIG_INPUT_ADXL34X_SPI) += adxl34x-spi.o
> obj-$(CONFIG_INPUT_APANEL) += apanel.o
> obj-$(CONFIG_INPUT_ARIZONA_HAPTICS) += arizona-haptics.o
> +obj-$(CONFIG_INPUT_REGULATOR_HAPTIC) += regulator-haptic.o
> obj-$(CONFIG_INPUT_ATI_REMOTE2) += ati_remote2.o
> obj-$(CONFIG_INPUT_ATLAS_BTNS) += atlas_btns.o
> obj-$(CONFIG_INPUT_BFIN_ROTARY) += bfin_rotary.o
> diff --git a/drivers/input/misc/regulator-haptic.c
> b/drivers/input/misc/regulator-haptic.c
> new file mode 100644
> index 0000000..29f57ea
> --- /dev/null
> +++ b/drivers/input/misc/regulator-haptic.c
> @@ -0,0 +1,185 @@
> +/*
> + * Regulator haptic driver
> + *
> + * Copyright (c) 2013 Samsung Electronics Co., Ltd.
> + *
> + * Author: Hyunhee Kim <hyunhee.kim@samsung.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/input.h>
> +#include <linux/slab.h>
> +#include <linux/regulator/driver.h>
> +
> +struct regulator_haptic {
> + struct device *dev;
> + struct input_dev *input_dev;
> + struct work_struct work;
> + bool enabled;
> + struct regulator *regulator;
> + struct mutex mutex;
> + int level;
> +};
> +
> +static void regulator_haptic_enable(struct regulator_haptic *haptic, bool
> enable)
> +{
> + int ret;
> +
> + mutex_lock(&haptic->mutex);
> + if (enable && !haptic->enabled) {
> + haptic->enabled = true;
> + ret = regulator_enable(haptic->regulator);
> + if (ret)
> + pr_err("haptic: %s failed to enable regulator\n",
> + __func__);
> + } else if (!enable && haptic->enabled) {
> + haptic->enabled = false;
> + ret = regulator_disable(haptic->regulator);
> + if (ret)
> + pr_err("haptic: %s failed to disable regulator\n",
> + __func__);
> + }
> + mutex_unlock(&haptic->mutex);
> +}
> +
> +static void regulator_haptic_work(struct work_struct *work)
> +{
> + struct regulator_haptic *haptic = container_of(work,
> + struct
> regulator_haptic,
> + work);
> + if (haptic->level)
> + regulator_haptic_enable(haptic, true);
> + else
> + regulator_haptic_enable(haptic, false);
> +
> +}
> +
> +static int regulator_haptic_play(struct input_dev *input, void *data,
> + struct ff_effect *effect)
> +{
> + struct regulator_haptic *haptic = input_get_drvdata(input);
> +
> + haptic->level = effect->u.rumble.strong_magnitude;
> + if (!haptic->level)
> + haptic->level = effect->u.rumble.weak_magnitude;
> + schedule_work(&haptic->work);
> +
> + return 0;
> +}
> +
> +static void regulator_haptic_close(struct input_dev *input)
> +{
> + struct regulator_haptic *haptic = input_get_drvdata(input);
> +
> + cancel_work_sync(&haptic->work);
> + regulator_haptic_enable(haptic, false);
> +}
> +
> +static int regulator_haptic_probe(struct platform_device *pdev)
> +{
> + struct regulator_haptic *haptic;
> + struct input_dev *input_dev;
> + int error;
> +
> + haptic = kzalloc(sizeof(*haptic), GFP_KERNEL);
> + if (!haptic) {
> + dev_err(&pdev->dev, "unable to allocate memory for
> haptic\n");
> + return -ENOMEM;
> + }
> +
> + input_dev = input_allocate_device();
> +
> + if (!input_dev) {
> + dev_err(&pdev->dev, "unable to allocate memory\n");
> + error = -ENOMEM;
> + goto err_kfree_mem;
> + }
> +
> + INIT_WORK(&haptic->work, regulator_haptic_work);
> + mutex_init(&haptic->mutex);
> + haptic->input_dev = input_dev;
> + haptic->dev = &pdev->dev;
> + haptic->regulator = regulator_get(&pdev->dev, "haptic");
> +
> + if (IS_ERR(haptic->regulator)) {
> + error = PTR_ERR(haptic->regulator);
> + dev_err(&pdev->dev, "unable to get regulator, err: %d\n",
> + error);
> + goto err_ifree_mem;
> + }
> +
> + haptic->input_dev->name = "regulator:haptic";
> + haptic->input_dev->dev.parent = &pdev->dev;
> + haptic->input_dev->close = regulator_haptic_close;
> + haptic->enabled = false;
> + input_set_drvdata(haptic->input_dev, haptic);
> + input_set_capability(haptic->input_dev, EV_FF, FF_RUMBLE);
> +
> + error = input_ff_create_memless(input_dev, NULL,
> + regulator_haptic_play);
> + if (error) {
> + dev_err(&pdev->dev,
> + "input_ff_create_memless() failed: %d\n",
> + error);
> + goto err_put_regulator;
> + }
> +
> + error = input_register_device(haptic->input_dev);
> + if (error) {
> + dev_err(&pdev->dev,
> + "couldn't register input device: %d\n",
> + error);
> + goto err_destroy_ff;
> + }
> +
> + platform_set_drvdata(pdev, haptic);
> +
> + return 0;
> +
> +err_destroy_ff:
> + input_ff_destroy(haptic->input_dev);
> +err_put_regulator:
> + regulator_put(haptic->regulator);
> +err_ifree_mem:
> + input_free_device(haptic->input_dev);
> +err_kfree_mem:
> + kfree(haptic);
> +
> + return error;
> +}
> +
> +static int regulator_haptic_remove(struct platform_device *pdev)
> +{
> + struct regulator_haptic *haptic = platform_get_drvdata(pdev);
> +
> + input_unregister_device(haptic->input_dev);
> +
> + return 0;
> +}
> +
> +static struct of_device_id regulator_haptic_dt_match[] = {
> + { .compatible = "linux,regulator-haptic" },
> + {},
> +};
> +
> +static struct platform_driver regulator_haptic_driver = {
> + .driver = {
> + .name = "regulator-haptic",
> + .owner = THIS_MODULE,
> + .of_match_table = regulator_haptic_dt_match,
> + },
> +
> + .probe = regulator_haptic_probe,
> + .remove = regulator_haptic_remove,
> +};
> +module_platform_driver(regulator_haptic_driver);
> +
> +MODULE_ALIAS("platform:regulator-haptic");
> +MODULE_DESCRIPTION("Regulator haptic driver");
> +MODULE_LICENSE("GPL");
> +MODULE_AUTHOR("Hyunhee Kim <hyunhee.kim@samsung.com>");
other than the line wrapping issue, the driver looks good to me
Acked-by: Aristeu Rozanski <aris@ruivo.org>
--
Aristeu
^ permalink raw reply
* Re: [PATCH] Input: add regulator haptic driver
From: Aristeu Sergio Rozanski Filho @ 2013-10-21 12:06 UTC (permalink / raw)
To: hyunhee.kim
Cc: dmitry.torokhov, broonie, peter.ujfalusi, wfp5p, linux-input,
linux-kernel, akpm, kyungmin.park
In-Reply-To: <000a01cec629$3cf34de0$b6d9e9a0$%kim@samsung.com>
Hi Hyunhee,
On Fri, Oct 11, 2013 at 11:26:05AM +0900, hyunhee.kim wrote:
> +static void regulator_haptic_work(struct work_struct *work)
> +{
> + struct regulator_haptic *haptic = container_of(work,
> + struct
> regulator_haptic,
you got a line wrap damage patch
--
Aristeu
^ permalink raw reply
* [PATCH v4 1/1] Input: Improve the performance of alps v5-protocol's touchpad
From: Yunkang Tang @ 2013-10-21 11:41 UTC (permalink / raw)
To: dmitry.torokhov, cernekee, dturvene; +Cc: linux-input, ndevos, yunkang.tang
Hi all,
Here is the 4th version of supporting ALPS v5 protocol's device.
Change since v3:
- Fix the bug that Finger1's coordinate data will always be (0,0) when finger
number is more than 1.
Change since v2:
- Merge two patches into one patch because they're all for improving v5 device.
- Modify the source code according to Kevin's suggestions.
1) Simplify the alps_process_bitmap() function by using ffs() and fls().
2) Simplify the alps_decode_dolphin() function by using u64 for the palm data.
3) Reuse the alps_process_touchpad_packet_v3() for v5 device.
4) Add an sample for calculating touchpad's x_max&y_max by using sensor line number.
Self test with v5 device:
- Checked on both 32-bit & 64-bit environment.
- Cursor moves correctly.
- 1Finger Tap/Drag works well.
- 2Finger Tap works well.
- 2Finger Scroll works well.
- L/R Buttons do function
Signed-off-by: Yunkang Tang <yunkang.tang@cn.alps.com>
---
drivers/input/mouse/alps.c | 217 ++++++++++++++++++++++++++++++++++++---------
drivers/input/mouse/alps.h | 7 +-
2 files changed, 183 insertions(+), 41 deletions(-)
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
index ca7a26f..93f412d 100644
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -257,6 +257,50 @@ static void alps_process_packet_v1_v2(struct psmouse *psmouse)
}
/*
+ * Process bitmap data for V5 protocols. Return value is null.
+ *
+ * The bitmaps don't have enough data to track fingers, so this function
+ * only generates points representing a bounding box of at most two contacts.
+ * These two points are returned in x1, y1, x2, and y2.
+ */
+static void alps_process_bitmap_dolphin(struct alps_data *priv,
+ struct alps_fields *fields,
+ int *x1, int *y1, int *x2, int *y2)
+{
+ int box_middle_x, box_middle_y;
+ unsigned int x_map, y_map;
+ unsigned char start_bit, end_bit;
+
+ x_map = fields->x_map;
+ y_map = fields->y_map;
+
+ if (!x_map || !y_map)
+ return;
+
+ /* Most-significant bit should never exceed max sensor line number */
+ if (fls(x_map) > priv->x_bits || fls(y_map) > priv->y_bits)
+ return;
+
+ *x1 = *y1 = *x2 = *y2 = 0;
+
+ if (fields->fingers > 1) {
+ start_bit = priv->x_bits - fls(x_map);
+ end_bit = priv->x_bits - ffs(x_map);
+ box_middle_x = (priv->x_max * (start_bit + end_bit)) /
+ (2 * (priv->x_bits - 1));
+
+ start_bit = ffs(y_map) - 1;
+ end_bit = fls(y_map) - 1;
+ box_middle_y = (priv->y_max * (start_bit + end_bit)) /
+ (2 * (priv->y_bits - 1));
+ *x1 = fields->x;
+ *y1 = fields->y;
+ *x2 = 2 * box_middle_x - *x1;
+ *y2 = 2 * box_middle_y - *y1;
+ }
+}
+
+/*
* Process bitmap data from v3 and v4 protocols. Returns the number of
* fingers detected. A return value of 0 means at least one of the
* bitmaps was empty.
@@ -461,7 +505,8 @@ static void alps_decode_buttons_v3(struct alps_fields *f, unsigned char *p)
f->ts_middle = !!(p[3] & 0x40);
}
-static void alps_decode_pinnacle(struct alps_fields *f, unsigned char *p)
+static void alps_decode_pinnacle(struct alps_fields *f, unsigned char *p,
+ struct psmouse *psmouse)
{
f->first_mp = !!(p[4] & 0x40);
f->is_mp = !!(p[0] & 0x40);
@@ -482,48 +527,61 @@ static void alps_decode_pinnacle(struct alps_fields *f, unsigned char *p)
alps_decode_buttons_v3(f, p);
}
-static void alps_decode_rushmore(struct alps_fields *f, unsigned char *p)
+static void alps_decode_rushmore(struct alps_fields *f, unsigned char *p,
+ struct psmouse *psmouse)
{
- alps_decode_pinnacle(f, p);
+ alps_decode_pinnacle(f, p, psmouse);
f->x_map |= (p[5] & 0x10) << 11;
f->y_map |= (p[5] & 0x20) << 6;
}
-static void alps_decode_dolphin(struct alps_fields *f, unsigned char *p)
+static void alps_decode_dolphin(struct alps_fields *f, unsigned char *p,
+ struct psmouse *psmouse)
{
+ u64 palm_data = 0;
+ struct alps_data *priv = psmouse->private;
+
f->first_mp = !!(p[0] & 0x02);
f->is_mp = !!(p[0] & 0x20);
- f->fingers = ((p[0] & 0x6) >> 1 |
+ if (!f->is_mp) {
+ f->x = ((p[1] & 0x7f) | ((p[4] & 0x0f) << 7));
+ f->y = ((p[2] & 0x7f) | ((p[4] & 0xf0) << 3));
+ f->z = (p[0] & 4) ? 0 : p[5] & 0x7f;
+ alps_decode_buttons_v3(f, p);
+ } else {
+ f->fingers = ((p[0] & 0x6) >> 1 |
(p[0] & 0x10) >> 2);
- f->x_map = ((p[2] & 0x60) >> 5) |
- ((p[4] & 0x7f) << 2) |
- ((p[5] & 0x7f) << 9) |
- ((p[3] & 0x07) << 16) |
- ((p[3] & 0x70) << 15) |
- ((p[0] & 0x01) << 22);
- f->y_map = (p[1] & 0x7f) |
- ((p[2] & 0x1f) << 7);
-
- f->x = ((p[1] & 0x7f) | ((p[4] & 0x0f) << 7));
- f->y = ((p[2] & 0x7f) | ((p[4] & 0xf0) << 3));
- f->z = (p[0] & 4) ? 0 : p[5] & 0x7f;
- alps_decode_buttons_v3(f, p);
+ palm_data = (p[1] & 0x7f) |
+ ((p[2] & 0x7f) << 7) |
+ ((p[4] & 0x7f) << 14) |
+ ((p[5] & 0x7f) << 21) |
+ ((p[3] & 0x07) << 28) |
+ (((u64)p[3] & 0x70) << 27) |
+ (((u64)p[0] & 0x01) << 34);
+
+ /* Y-profile is stored in P(0) to p(n-1), n = y_bits; */
+ f->y_map = palm_data & (BIT(priv->y_bits) - 1);
+
+ /* X-profile is stored in p(n) to p(n+m-1), m = x_bits; */
+ f->x_map = (palm_data >> priv->y_bits) &
+ (BIT(priv->x_bits) - 1);
+ }
}
-static void alps_process_touchpad_packet_v3(struct psmouse *psmouse)
+static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse)
{
struct alps_data *priv = psmouse->private;
unsigned char *packet = psmouse->packet;
struct input_dev *dev = psmouse->dev;
struct input_dev *dev2 = priv->dev2;
int x1 = 0, y1 = 0, x2 = 0, y2 = 0;
- int fingers = 0, bmap_fingers;
- struct alps_fields f;
+ int fingers = 0, bmap_fn;
+ struct alps_fields f = {0};
- priv->decode_fields(&f, packet);
+ priv->decode_fields(&f, packet, psmouse);
/*
* There's no single feature of touchpad position and bitmap packets
@@ -540,19 +598,38 @@ static void alps_process_touchpad_packet_v3(struct psmouse *psmouse)
*/
if (f.is_mp) {
fingers = f.fingers;
- bmap_fingers = alps_process_bitmap(priv,
- f.x_map, f.y_map,
- &x1, &y1, &x2, &y2);
-
- /*
- * We shouldn't report more than one finger if
- * we don't have two coordinates.
- */
- if (fingers > 1 && bmap_fingers < 2)
- fingers = bmap_fingers;
-
- /* Now process position packet */
- priv->decode_fields(&f, priv->multi_data);
+ if (priv->proto_version == ALPS_PROTO_V3) {
+ bmap_fn = alps_process_bitmap(priv, f.x_map,
+ f.y_map, &x1, &y1,
+ &x2, &y2);
+
+ /*
+ * We shouldn't report more than one finger if
+ * we don't have two coordinates.
+ */
+ if (fingers > 1 && bmap_fn < 2)
+ fingers = bmap_fn;
+
+ /* Now process position packet */
+ priv->decode_fields(&f, priv->multi_data,
+ psmouse);
+ } else {
+ /*
+ * Because Dolphin uses position packet's
+ * coordinate data as Pt1 and uses it to
+ * calculate Pt2, so we need to do position
+ * packet decode first.
+ */
+ priv->decode_fields(&f, priv->multi_data,
+ psmouse);
+
+ /*
+ * Since Dolphin's finger number is reliable,
+ * there is no need to compare with bmap_fn.
+ */
+ alps_process_bitmap_dolphin(priv, &f, &x1, &y1,
+ &x2, &y2);
+ }
} else {
priv->multi_packet = 0;
}
@@ -642,7 +719,7 @@ static void alps_process_packet_v3(struct psmouse *psmouse)
return;
}
- alps_process_touchpad_packet_v3(psmouse);
+ alps_process_touchpad_packet_v3_v5(psmouse);
}
static void alps_process_packet_v4(struct psmouse *psmouse)
@@ -742,6 +819,17 @@ static void alps_process_packet_v4(struct psmouse *psmouse)
input_sync(dev);
}
+static void alps_process_packet_v5(struct psmouse *psmouse)
+{
+ unsigned char *packet = psmouse->packet;
+
+ /* Ignore stick point data */
+ if (packet[0] == 0xD8)
+ return;
+
+ alps_process_touchpad_packet_v3_v5(psmouse);
+}
+
static void alps_report_bare_ps2_packet(struct psmouse *psmouse,
unsigned char packet[],
bool report_buttons)
@@ -1519,6 +1607,53 @@ error:
return -1;
}
+static int alps_dolphin_get_device_area(struct psmouse *psmouse,
+ struct alps_data *priv)
+{
+ struct ps2dev *ps2dev = &psmouse->ps2dev;
+ unsigned char param[4] = {0};
+ int num_x_electrode, num_y_electrode;
+
+ if (alps_enter_command_mode(psmouse))
+ return -1;
+
+ if (ps2_command(ps2dev, NULL, 0x00EC) ||
+ ps2_command(ps2dev, NULL, 0x00F0) ||
+ ps2_command(ps2dev, NULL, 0x00F0) ||
+ ps2_command(ps2dev, NULL, 0x00F3) ||
+ ps2_command(ps2dev, NULL, 0x000A) ||
+ ps2_command(ps2dev, NULL, 0x00F3) ||
+ ps2_command(ps2dev, NULL, 0x000A))
+ return -1;
+
+ if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO))
+ return -1;
+
+ /*
+ * Dolphin's sensor line number is not fixed. It can be calculated
+ * by adding the device's register value with DOLPHIN_PROFILE_X/YOFFSET.
+ * Further more, we can get device's x_max and y_max by multiplying
+ * sensor line number with DOLPHIN_COUNT_PER_ELECTRODE.
+ *
+ * e.g. When we get register's sensor_x = 11 & sensor_y = 8,
+ * real sensor line number X = 11 + 8 = 19, and
+ * real sensor line number Y = 8 + 1 = 9.
+ * So, x_max = (19 - 1) * 64 = 1152, and
+ * y_max = (9 - 1) * 64 = 512.
+ */
+ num_x_electrode = DOLPHIN_PROFILE_XOFFSET + (param[2] & 0x0F);
+ num_y_electrode = DOLPHIN_PROFILE_YOFFSET + ((param[2] >> 4) & 0x0F);
+ priv->x_bits = num_x_electrode;
+ priv->y_bits = num_y_electrode;
+ priv->x_max = (num_x_electrode - 1) * DOLPHIN_COUNT_PER_ELECTRODE;
+ priv->y_max = (num_y_electrode - 1) * DOLPHIN_COUNT_PER_ELECTRODE;
+
+ if (alps_exit_command_mode(psmouse))
+ return -1;
+
+ return 0;
+}
+
static int alps_hw_init_dolphin_v1(struct psmouse *psmouse)
{
struct ps2dev *ps2dev = &psmouse->ps2dev;
@@ -1571,7 +1706,7 @@ static void alps_set_defaults(struct alps_data *priv)
break;
case ALPS_PROTO_V5:
priv->hw_init = alps_hw_init_dolphin_v1;
- priv->process_packet = alps_process_packet_v3;
+ priv->process_packet = alps_process_packet_v5;
priv->decode_fields = alps_decode_dolphin;
priv->set_abs_params = alps_set_abs_params_mt;
priv->nibble_commands = alps_v3_nibble_commands;
@@ -1645,11 +1780,13 @@ static int alps_identify(struct psmouse *psmouse, struct alps_data *priv)
if (alps_match_table(psmouse, priv, e7, ec) == 0) {
return 0;
} else if (e7[0] == 0x73 && e7[1] == 0x03 && e7[2] == 0x50 &&
- ec[0] == 0x73 && ec[1] == 0x01) {
+ ec[0] == 0x73 && (ec[1] == 0x01 || ec[1] == 0x02)) {
priv->proto_version = ALPS_PROTO_V5;
alps_set_defaults(priv);
-
- return 0;
+ if (alps_dolphin_get_device_area(psmouse, priv))
+ return -EIO;
+ else
+ return 0;
} else if (ec[0] == 0x88 && ec[1] == 0x08) {
priv->proto_version = ALPS_PROTO_V3;
alps_set_defaults(priv);
diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h
index eee5985..c5c53f4 100644
--- a/drivers/input/mouse/alps.h
+++ b/drivers/input/mouse/alps.h
@@ -18,6 +18,10 @@
#define ALPS_PROTO_V4 4
#define ALPS_PROTO_V5 5
+#define DOLPHIN_COUNT_PER_ELECTRODE 64
+#define DOLPHIN_PROFILE_XOFFSET 8 /* x-electrode offset */
+#define DOLPHIN_PROFILE_YOFFSET 1 /* y-electrode offset */
+
/**
* struct alps_model_info - touchpad ID table
* @signature: E7 response string to match.
@@ -145,7 +149,8 @@ struct alps_data {
int (*hw_init)(struct psmouse *psmouse);
void (*process_packet)(struct psmouse *psmouse);
- void (*decode_fields)(struct alps_fields *f, unsigned char *p);
+ void (*decode_fields)(struct alps_fields *f, unsigned char *p,
+ struct psmouse *psmouse);
void (*set_abs_params)(struct alps_data *priv, struct input_dev *dev1);
int prev_fin;
--
1.8.1.2
^ permalink raw reply related
* Re: [PATCH] HID: wiimote: add LEGO-wiimote VID
From: Jiri Kosina @ 2013-10-21 11:42 UTC (permalink / raw)
To: David Herrmann; +Cc: linux-input, stable
In-Reply-To: <1382106382-24800-1-git-send-email-dh.herrmann@gmail.com>
On Fri, 18 Oct 2013, David Herrmann wrote:
> The LEGO-wiimote uses a different VID than the Nintendo ID. The device is
> technically the same so add the ID.
Applied, thanks David.
--
Jiri Kosina
SUSE Labs
^ permalink raw reply
* Re: [PATCH v3 1/1] Input: Improve the performance of alps v5-protocol's touchpad
From: Tommy Will @ 2013-10-21 9:16 UTC (permalink / raw)
To: Dmitry Torokhov, Kevin Cernekee, david turvene
Cc: linux-input, Niels de Vos, yunkang.tang
In-Reply-To: <1382250180-3579-1-git-send-email-yunkang.tang@cn.alps.com>
Hi all,
I'm so sorry but I suddenly found a bug of below patch. Please kindly
ignore it and I'd
update a new one later. Thanks.
Tommy
2013/10/20 Yunkang Tang <tommywill2011@gmail.com>:
> Hi all,
>
> Here is the 3rd version of supporting ALPS v5 protocol's device
>
> Change since v2:
> - Merge two patches into one patch because they're all for improving v5 device.
> - Modify the source code according to Kevin's suggestions.
> 1) Simplify the alps_process_bitmap() function by using ffs() and fls().
> 2) Simplify the alps_decode_dolphin() function by using u64 for the palm data.
> 3) Reuse the alps_process_touchpad_packet_v3() for v5 device.
> 4) Add an sample for calculating touchpad's x_max&y_max by using sensor line number.
>
> Signed-off-by: Yunkang Tang <yunkang.tang@cn.alps.com>
> ---
> drivers/input/mouse/alps.c | 201 ++++++++++++++++++++++++++++++++++++---------
> drivers/input/mouse/alps.h | 7 +-
> 2 files changed, 169 insertions(+), 39 deletions(-)
>
> diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
> index ca7a26f..7cd0ac0 100644
> --- a/drivers/input/mouse/alps.c
> +++ b/drivers/input/mouse/alps.c
> @@ -257,6 +257,50 @@ static void alps_process_packet_v1_v2(struct psmouse *psmouse)
> }
>
> /*
> + * Process bitmap data for V5 protocols. Return value is null.
> + *
> + * The bitmaps don't have enough data to track fingers, so this function
> + * only generates points representing a bounding box of at most two contacts.
> + * These two points are returned in x1, y1, x2, and y2.
> + */
> +static void alps_process_bitmap_dolphin(struct alps_data *priv,
> + struct alps_fields *fields,
> + int *x1, int *y1, int *x2, int *y2)
> +{
> + int box_middle_x, box_middle_y;
> + unsigned int x_map, y_map;
> + unsigned char start_bit, end_bit;
> +
> + x_map = fields->x_map;
> + y_map = fields->y_map;
> +
> + if (!x_map || !y_map)
> + return;
> +
> + /* Most-significant bit should never exceed max sensor line number */
> + if (fls(x_map) > priv->x_bits || fls(y_map) > priv->y_bits)
> + return;
> +
> + *x1 = *y1 = *x2 = *y2 = 0;
> +
> + if (fields->fingers > 1) {
> + start_bit = priv->x_bits - fls(x_map);
> + end_bit = priv->x_bits - ffs(x_map);
> + box_middle_x = (priv->x_max * (start_bit + end_bit)) /
> + (2 * (priv->x_bits - 1));
> +
> + start_bit = ffs(y_map) - 1;
> + end_bit = fls(y_map) - 1;
> + box_middle_y = (priv->y_max * (start_bit + end_bit)) /
> + (2 * (priv->y_bits - 1));
> + *x1 = fields->x;
> + *y1 = fields->y;
> + *x2 = 2 * box_middle_x - *x1;
> + *y2 = 2 * box_middle_y - *y1;
> + }
> +}
> +
> +/*
> * Process bitmap data from v3 and v4 protocols. Returns the number of
> * fingers detected. A return value of 0 means at least one of the
> * bitmaps was empty.
> @@ -461,7 +505,8 @@ static void alps_decode_buttons_v3(struct alps_fields *f, unsigned char *p)
> f->ts_middle = !!(p[3] & 0x40);
> }
>
> -static void alps_decode_pinnacle(struct alps_fields *f, unsigned char *p)
> +static void alps_decode_pinnacle(struct alps_fields *f, unsigned char *p,
> + struct psmouse *psmouse)
> {
> f->first_mp = !!(p[4] & 0x40);
> f->is_mp = !!(p[0] & 0x40);
> @@ -482,48 +527,61 @@ static void alps_decode_pinnacle(struct alps_fields *f, unsigned char *p)
> alps_decode_buttons_v3(f, p);
> }
>
> -static void alps_decode_rushmore(struct alps_fields *f, unsigned char *p)
> +static void alps_decode_rushmore(struct alps_fields *f, unsigned char *p,
> + struct psmouse *psmouse)
> {
> - alps_decode_pinnacle(f, p);
> + alps_decode_pinnacle(f, p, psmouse);
>
> f->x_map |= (p[5] & 0x10) << 11;
> f->y_map |= (p[5] & 0x20) << 6;
> }
>
> -static void alps_decode_dolphin(struct alps_fields *f, unsigned char *p)
> +static void alps_decode_dolphin(struct alps_fields *f, unsigned char *p,
> + struct psmouse *psmouse)
> {
> + u64 palm_data = 0;
> + struct alps_data *priv = psmouse->private;
> +
> f->first_mp = !!(p[0] & 0x02);
> f->is_mp = !!(p[0] & 0x20);
>
> - f->fingers = ((p[0] & 0x6) >> 1 |
> + if (!f->is_mp) {
> + f->x = ((p[1] & 0x7f) | ((p[4] & 0x0f) << 7));
> + f->y = ((p[2] & 0x7f) | ((p[4] & 0xf0) << 3));
> + f->z = (p[0] & 4) ? 0 : p[5] & 0x7f;
> + alps_decode_buttons_v3(f, p);
> + } else {
> + f->fingers = ((p[0] & 0x6) >> 1 |
> (p[0] & 0x10) >> 2);
> - f->x_map = ((p[2] & 0x60) >> 5) |
> - ((p[4] & 0x7f) << 2) |
> - ((p[5] & 0x7f) << 9) |
> - ((p[3] & 0x07) << 16) |
> - ((p[3] & 0x70) << 15) |
> - ((p[0] & 0x01) << 22);
> - f->y_map = (p[1] & 0x7f) |
> - ((p[2] & 0x1f) << 7);
> -
> - f->x = ((p[1] & 0x7f) | ((p[4] & 0x0f) << 7));
> - f->y = ((p[2] & 0x7f) | ((p[4] & 0xf0) << 3));
> - f->z = (p[0] & 4) ? 0 : p[5] & 0x7f;
>
> - alps_decode_buttons_v3(f, p);
> + palm_data = (p[1] & 0x7f) |
> + ((p[2] & 0x7f) << 7) |
> + ((p[4] & 0x7f) << 14) |
> + ((p[5] & 0x7f) << 21) |
> + ((p[3] & 0x07) << 28) |
> + (((u64)p[3] & 0x70) << 27) |
> + (((u64)p[0] & 0x01) << 34);
> +
> + /* Y-profile is stored in P(0) to p(n-1), n = y_bits; */
> + f->y_map = palm_data & (BIT(priv->y_bits) - 1);
> +
> + /* X-profile is stored in p(n) to p(n+m-1), m = x_bits; */
> + f->x_map = (palm_data >> priv->y_bits) &
> + (BIT(priv->x_bits) - 1);
> + }
> }
>
> -static void alps_process_touchpad_packet_v3(struct psmouse *psmouse)
> +static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse)
> {
> struct alps_data *priv = psmouse->private;
> unsigned char *packet = psmouse->packet;
> struct input_dev *dev = psmouse->dev;
> struct input_dev *dev2 = priv->dev2;
> int x1 = 0, y1 = 0, x2 = 0, y2 = 0;
> - int fingers = 0, bmap_fingers;
> - struct alps_fields f;
> + int fingers = 0, bmap_fn;
> + struct alps_fields f = {0};
>
> - priv->decode_fields(&f, packet);
> + priv->decode_fields(&f, packet, psmouse);
>
> /*
> * There's no single feature of touchpad position and bitmap packets
> @@ -540,19 +598,27 @@ static void alps_process_touchpad_packet_v3(struct psmouse *psmouse)
> */
> if (f.is_mp) {
> fingers = f.fingers;
> - bmap_fingers = alps_process_bitmap(priv,
> - f.x_map, f.y_map,
> - &x1, &y1, &x2, &y2);
> -
> - /*
> - * We shouldn't report more than one finger if
> - * we don't have two coordinates.
> - */
> - if (fingers > 1 && bmap_fingers < 2)
> - fingers = bmap_fingers;
> + if (priv->proto_version == ALPS_PROTO_V3) {
> + bmap_fn = alps_process_bitmap(priv, f.x_map,
> + f.y_map, &x1, &y1,
> + &x2, &y2);
> +
> + /*
> + * We shouldn't report more than one finger if
> + * we don't have two coordinates.
> + */
> + if (fingers > 1 && bmap_fn < 2)
> + fingers = bmap_fn;
> + } else {
> + /* Since Dolphin's finger number is reliable,
> + * there is no need to compare with bmap_fn.
> + */
> + alps_process_bitmap_dolphin(priv, &f, &x1, &y1,
> + &x2, &y2);
> + }
>
> /* Now process position packet */
> - priv->decode_fields(&f, priv->multi_data);
> + priv->decode_fields(&f, priv->multi_data, psmouse);
> } else {
> priv->multi_packet = 0;
> }
> @@ -642,7 +708,7 @@ static void alps_process_packet_v3(struct psmouse *psmouse)
> return;
> }
>
> - alps_process_touchpad_packet_v3(psmouse);
> + alps_process_touchpad_packet_v3_v5(psmouse);
> }
>
> static void alps_process_packet_v4(struct psmouse *psmouse)
> @@ -742,6 +808,17 @@ static void alps_process_packet_v4(struct psmouse *psmouse)
> input_sync(dev);
> }
>
> +static void alps_process_packet_v5(struct psmouse *psmouse)
> +{
> + unsigned char *packet = psmouse->packet;
> +
> + /* Ignore stick point data */
> + if (packet[0] == 0xD8)
> + return;
> +
> + alps_process_touchpad_packet_v3_v5(psmouse);
> +}
> +
> static void alps_report_bare_ps2_packet(struct psmouse *psmouse,
> unsigned char packet[],
> bool report_buttons)
> @@ -1519,6 +1596,52 @@ error:
> return -1;
> }
>
> +static int alps_dolphin_get_device_area(struct psmouse *psmouse,
> + struct alps_data *priv)
> +{
> + struct ps2dev *ps2dev = &psmouse->ps2dev;
> + unsigned char param[4] = {0};
> + int num_x_electrode, num_y_electrode;
> +
> + if (alps_enter_command_mode(psmouse))
> + return -1;
> +
> + if (ps2_command(ps2dev, NULL, 0x00EC) ||
> + ps2_command(ps2dev, NULL, 0x00F0) ||
> + ps2_command(ps2dev, NULL, 0x00F0) ||
> + ps2_command(ps2dev, NULL, 0x00F3) ||
> + ps2_command(ps2dev, NULL, 0x000A) ||
> + ps2_command(ps2dev, NULL, 0x00F3) ||
> + ps2_command(ps2dev, NULL, 0x000A))
> + return -1;
> +
> + if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO))
> + return -1;
> +
> + /* Dolphin's sensor line number is not fixed. It can be calculated
> + * by adding the device's register value with DOLPHIN_PROFILE_X/YOFFSET.
> + * Further more, we can get device's x_max and y_max by multiplying
> + * sensor line number with DOLPHIN_COUNT_PER_ELECTRODE.
> + *
> + * e.g. When we get register's sensor_x = 11 & sensor_y = 8,
> + * real sensor line number X = 11 + 8 = 19, and
> + * real sensor line number Y = 8 + 1 = 9.
> + * So, x_max = (19 - 1) * 64 = 1152, and
> + * y_max = (9 - 1) * 64 = 512.
> + */
> + num_x_electrode = DOLPHIN_PROFILE_XOFFSET + (param[2] & 0x0F);
> + num_y_electrode = DOLPHIN_PROFILE_YOFFSET + ((param[2] >> 4) & 0x0F);
> + priv->x_bits = num_x_electrode;
> + priv->y_bits = num_y_electrode;
> + priv->x_max = (num_x_electrode - 1) * DOLPHIN_COUNT_PER_ELECTRODE;
> + priv->y_max = (num_y_electrode - 1) * DOLPHIN_COUNT_PER_ELECTRODE;
> +
> + if (alps_exit_command_mode(psmouse))
> + return -1;
> +
> + return 0;
> +}
> +
> static int alps_hw_init_dolphin_v1(struct psmouse *psmouse)
> {
> struct ps2dev *ps2dev = &psmouse->ps2dev;
> @@ -1571,7 +1694,7 @@ static void alps_set_defaults(struct alps_data *priv)
> break;
> case ALPS_PROTO_V5:
> priv->hw_init = alps_hw_init_dolphin_v1;
> - priv->process_packet = alps_process_packet_v3;
> + priv->process_packet = alps_process_packet_v5;
> priv->decode_fields = alps_decode_dolphin;
> priv->set_abs_params = alps_set_abs_params_mt;
> priv->nibble_commands = alps_v3_nibble_commands;
> @@ -1645,11 +1768,13 @@ static int alps_identify(struct psmouse *psmouse, struct alps_data *priv)
> if (alps_match_table(psmouse, priv, e7, ec) == 0) {
> return 0;
> } else if (e7[0] == 0x73 && e7[1] == 0x03 && e7[2] == 0x50 &&
> - ec[0] == 0x73 && ec[1] == 0x01) {
> + ec[0] == 0x73 && (ec[1] == 0x01 || ec[1] == 0x02)) {
> priv->proto_version = ALPS_PROTO_V5;
> alps_set_defaults(priv);
> -
> - return 0;
> + if (alps_dolphin_get_device_area(psmouse, priv))
> + return -EIO;
> + else
> + return 0;
> } else if (ec[0] == 0x88 && ec[1] == 0x08) {
> priv->proto_version = ALPS_PROTO_V3;
> alps_set_defaults(priv);
> diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h
> index eee5985..c5c53f4 100644
> --- a/drivers/input/mouse/alps.h
> +++ b/drivers/input/mouse/alps.h
> @@ -18,6 +18,10 @@
> #define ALPS_PROTO_V4 4
> #define ALPS_PROTO_V5 5
>
> +#define DOLPHIN_COUNT_PER_ELECTRODE 64
> +#define DOLPHIN_PROFILE_XOFFSET 8 /* x-electrode offset */
> +#define DOLPHIN_PROFILE_YOFFSET 1 /* y-electrode offset */
> +
> /**
> * struct alps_model_info - touchpad ID table
> * @signature: E7 response string to match.
> @@ -145,7 +149,8 @@ struct alps_data {
>
> int (*hw_init)(struct psmouse *psmouse);
> void (*process_packet)(struct psmouse *psmouse);
> - void (*decode_fields)(struct alps_fields *f, unsigned char *p);
> + void (*decode_fields)(struct alps_fields *f, unsigned char *p,
> + struct psmouse *psmouse);
> void (*set_abs_params)(struct alps_data *priv, struct input_dev *dev1);
>
> int prev_fin;
> --
> 1.8.1.2
>
--
Best Regards,
Tommy
^ permalink raw reply
* [PATCH] HID: i2c-hid: Stop querying for init reports
From: Bibek Basu @ 2013-10-21 4:29 UTC (permalink / raw)
To: benjamin.tissoires; +Cc: jkosina, linux-input, linux-kernel, Bibek Basu
According to specifications, HID over I2C devices
are not bound to respond to query for INPUT
REPORTS. Thus dropping the call during init
as many devices does not respond causing error
messages during boot.
Signed-off-by: Bibek Basu <bbasu@nvidia.com>
---
drivers/hid/i2c-hid/i2c-hid.c | 4 ----
1 file changed, 4 deletions(-)
diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c
index fd7ce37..ae48d18 100644
--- a/drivers/hid/i2c-hid/i2c-hid.c
+++ b/drivers/hid/i2c-hid/i2c-hid.c
@@ -455,10 +455,6 @@ static void i2c_hid_init_reports(struct hid_device *hid)
}
list_for_each_entry(report,
- &hid->report_enum[HID_INPUT_REPORT].report_list, list)
- i2c_hid_init_report(report, inbuf, ihid->bufsize);
-
- list_for_each_entry(report,
&hid->report_enum[HID_FEATURE_REPORT].report_list, list)
i2c_hid_init_report(report, inbuf, ihid->bufsize);
--
1.8.1.5
^ permalink raw reply related
* RE: [PATCH] HID: i2c-hid: Stop querying for init reports
From: Bibek Basu @ 2013-10-21 4:23 UTC (permalink / raw)
To: Benjamin Tissoires; +Cc: Jiri Kosina, linux-input, linux-kernel@vger.kernel.org
In-Reply-To: <CAN+gG=FukmZEpo8wvsmNeV=0h7xR9xYOPLyvYEiDq98T-4tn=A@mail.gmail.com>
Hi Benjamin,
> -----Original Message-----
> From: Benjamin Tissoires [mailto:benjamin.tissoires@gmail.com]
> Sent: Thursday, October 17, 2013 11:27 PM
> To: Bibek Basu
> Cc: Jiri Kosina; linux-input; linux-kernel@vger.kernel.org
> Subject: Re: [PATCH] HID: i2c-hid: Stop querying for init reports
>
> Hi Bibek,
>
> On Tue, Oct 15, 2013 at 4:28 AM, Bibek Basu <bbasu@nvidia.com> wrote:
> > According to specifications, HID over I2C devices are not bound to
> > respond to query for INPUT REPORTS. Thus dropping the call during init
> > as many devices does not respond causing error messages during boot.
> >
>
> This time, the patch is removing too many things that are correct. :)
>
> see below to know what to remove and what to keep:
>
> > Signed-off-by: Bibek Basu <bbasu@nvidia.com>
> > ---
> > drivers/hid/i2c-hid/i2c-hid.c | 59
> > -------------------------------------------
> > 1 file changed, 59 deletions(-)
> >
> > diff --git a/drivers/hid/i2c-hid/i2c-hid.c
> > b/drivers/hid/i2c-hid/i2c-hid.c index fd7ce37..58a4f12 100644
> > --- a/drivers/hid/i2c-hid/i2c-hid.c
> > +++ b/drivers/hid/i2c-hid/i2c-hid.c
> > @@ -409,62 +409,6 @@ static int i2c_hid_get_report_length(struct
> hid_report *report)
> > report->device->report_enum[report->type].numbered +
> > 2; }
> >
> > -static void i2c_hid_init_report(struct hid_report *report, u8 *buffer,
> > - size_t bufsize)
> > -{
> > - struct hid_device *hid = report->device;
> > - struct i2c_client *client = hid->driver_data;
> > - struct i2c_hid *ihid = i2c_get_clientdata(client);
> > - unsigned int size, ret_size;
> > -
> > - size = i2c_hid_get_report_length(report);
> > - if (i2c_hid_get_report(client,
> > - report->type == HID_FEATURE_REPORT ? 0x03 : 0x01,
> > - report->id, buffer, size))
> > - return;
> > -
> > - i2c_hid_dbg(ihid, "report (len=%d): %*ph\n", size, size, ihid->inbuf);
> > -
> > - ret_size = buffer[0] | (buffer[1] << 8);
> > -
> > - if (ret_size != size) {
> > - dev_err(&client->dev, "error in %s size:%d / ret_size:%d\n",
> > - __func__, size, ret_size);
> > - return;
> > - }
> > -
> > - /* hid->driver_lock is held as we are in probe function,
> > - * we just need to setup the input fields, so using
> > - * hid_report_raw_event is safe. */
> > - hid_report_raw_event(hid, report->type, buffer + 2, size - 2, 1);
> > -}
>
> This function should be kept
>
> > -
> > -/*
> > - * Initialize all reports
> > - */
> > -static void i2c_hid_init_reports(struct hid_device *hid) -{
> > - struct hid_report *report;
> > - struct i2c_client *client = hid->driver_data;
> > - struct i2c_hid *ihid = i2c_get_clientdata(client);
> > - u8 *inbuf = kzalloc(ihid->bufsize, GFP_KERNEL);
> > -
> > - if (!inbuf) {
> > - dev_err(&client->dev, "can not retrieve initial reports\n");
> > - return;
> > - }
> > -
>
> Above should be kept
>
> > - list_for_each_entry(report,
> > - &hid->report_enum[HID_INPUT_REPORT].report_list, list)
> > - i2c_hid_init_report(report, inbuf, ihid->bufsize);
> > -
>
> these for lines should be removed (they are the one giving the errors in the
> logs)
>
> and please keep the rest of the code as is.
>
>
> > - list_for_each_entry(report,
> > - &hid->report_enum[HID_FEATURE_REPORT].report_list, list)
> > - i2c_hid_init_report(report, inbuf, ihid->bufsize);
>
> Actually, this part is very important because we have no spontaneous events
> emitted by features, so we don't know the value of the feature until we
> probed it. So please keep this part as mentioned above.
Thanks for the inputs. I am repushing the patch. Unfortunately, looks like I need to upgrade the firmware of my HID keyboard, as it does not responds to the FEATURE_REPORT
query:(
regards
Bibek
>
> Cheers,
> Benjamin
>
> > -
> > - kfree(inbuf);
> > -}
> > -
> > /*
> > * Traverse the supplied list of reports and find the longest
> > */
> > @@ -683,9 +627,6 @@ static int i2c_hid_start(struct hid_device *hid)
> > return ret;
> > }
> >
> > - if (!(hid->quirks & HID_QUIRK_NO_INIT_REPORTS))
> > - i2c_hid_init_reports(hid);
> > -
> > return 0;
> > }
> >
> > --
> > 1.8.1.5
> >
^ permalink raw reply
* [PATCH v2] add sur40 driver for Samsung SUR40 (aka MS Surface 2.0/Pixelsense)
From: Florian Echtler @ 2013-10-20 16:49 UTC (permalink / raw)
To: linux-input, benjamin.tissoires, rydberg, dmitry.torokhov,
dh.herrmann
Cc: Florian "floe" Echtler
From: "Florian \"floe\" Echtler" <floe@butterbrot.org>
This patch adds support for the built-in multitouch sensor in the Samsung
SUR40 touchscreen device, also known as Microsoft Surface 2.0 or Microsoft
Pixelsense. Support for raw video output from the sensor as well as the
accelerometer will be added in a later patch.
Signed-off-by: Florian Echtler <floe@butterbrot.org>
---
drivers/input/touchscreen/Kconfig | 10 +
drivers/input/touchscreen/Makefile | 1 +
drivers/input/touchscreen/sur40.c | 446 ++++++++++++++++++++++++++++++++++++
3 files changed, 457 insertions(+)
create mode 100644 drivers/input/touchscreen/sur40.c
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 515cfe7..99aaf10 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -876,6 +876,16 @@ config TOUCHSCREEN_STMPE
To compile this driver as a module, choose M here: the
module will be called stmpe-ts.
+config TOUCHSCREEN_SUR40
+ tristate "Samsung SUR40 (Surface 2.0/PixelSense) touchscreen"
+ depends on USB
+ help
+ Say Y here if you want support for the Samsung SUR40 touchscreen
+ (also known as Microsoft Surface 2.0 or Microsoft PixelSense).
+
+ To compile this driver as a module, choose M here: the
+ module will be called sur40.
+
config TOUCHSCREEN_TPS6507X
tristate "TPS6507x based touchscreens"
depends on I2C
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 6bfbeab..b63a25d 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -51,6 +51,7 @@ obj-$(CONFIG_TOUCHSCREEN_PIXCIR) += pixcir_i2c_ts.o
obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o
obj-$(CONFIG_TOUCHSCREEN_ST1232) += st1232.o
obj-$(CONFIG_TOUCHSCREEN_STMPE) += stmpe-ts.o
+obj-$(CONFIG_TOUCHSCREEN_SUR40) += sur40.o
obj-$(CONFIG_TOUCHSCREEN_TI_AM335X_TSC) += ti_am335x_tsc.o
obj-$(CONFIG_TOUCHSCREEN_TNETV107X) += tnetv107x-ts.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o
diff --git a/drivers/input/touchscreen/sur40.c b/drivers/input/touchscreen/sur40.c
new file mode 100644
index 0000000..89f5d48
--- /dev/null
+++ b/drivers/input/touchscreen/sur40.c
@@ -0,0 +1,446 @@
+/*
+ Surface2.0/SUR40/PixelSense input driver
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of
+ the License, or (at your option) any later version.
+
+ Copyright (c) 2013 by Florian 'floe' Echtler <floe@butterbrot.org>
+
+ Derived from the USB Skeleton driver 1.1,
+ Copyright (c) 2003 Greg Kroah-Hartman (greg@kroah.com)
+
+ and from the Apple USB BCM5974 multitouch driver,
+ Copyright (c) 2008 Henrik Rydberg (rydberg@euromail.se)
+
+ and from the generic hid-multitouch driver,
+ Copyright (c) 2010-2012 Stephane Chatty <chatty@enac.fr>
+*/
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/completion.h>
+#include <linux/uaccess.h>
+#include <linux/usb.h>
+#include <linux/printk.h>
+#include <linux/input-polldev.h>
+#include <linux/input/mt.h>
+#include <linux/usb/input.h>
+
+/* read 512 bytes from endpoint 0x86 -> get header + blobs */
+struct sur40_header {
+
+ uint16_t type; /* always 0x0001 */
+ uint16_t count; /* count of blobs (if 0: continue prev. packet) */
+
+ uint32_t packet_id;
+
+ uint32_t timestamp; /* milliseconds (inc. by 16 or 17 each frame) */
+ uint32_t unknown; /* "epoch?" always 02/03 00 00 00 */
+} __packed;
+
+struct sur40_blob {
+
+ uint16_t blob_id;
+
+ uint8_t action; /* 0x02 = enter/exit, 0x03 = update (?) */
+ uint8_t unknown; /* always 0x01 or 0x02 (no idea what this is?) */
+
+ uint16_t bb_pos_x; /* upper left corner of bounding box */
+ uint16_t bb_pos_y;
+
+ uint16_t bb_size_x; /* size of bounding box */
+ uint16_t bb_size_y;
+
+ uint16_t pos_x; /* finger tip position */
+ uint16_t pos_y;
+
+ uint16_t ctr_x; /* centroid position */
+ uint16_t ctr_y;
+
+ uint16_t axis_x; /* somehow related to major/minor axis, mostly: */
+ uint16_t axis_y; /* axis_x == bb_size_y && axis_y == bb_size_x */
+
+ float angle; /* orientation in radians relative to x axis */
+ uint32_t area; /* size in pixels/pressure (?) */
+
+ uint8_t padding[32];
+} __packed;
+
+/* combined header/blob data */
+struct sur40_data {
+ struct sur40_header header;
+ struct sur40_blob blobs[];
+} __packed;
+
+
+/* version information */
+#define DRIVER_SHORT "sur40"
+#define DRIVER_AUTHOR "Florian 'floe' Echtler <floe@butterbrot.org>"
+#define DRIVER_DESC "Surface2.0/SUR40/PixelSense input driver"
+
+/* vendor and device IDs */
+#define ID_MICROSOFT 0x045e
+#define ID_SUR40 0x0775
+
+/* sensor resolution */
+#define SENSOR_RES_X 1920
+#define SENSOR_RES_Y 1080
+
+/* touch data endpoint */
+#define TOUCH_ENDPOINT 0x86
+
+/* polling interval (ms) */
+#define POLL_INTERVAL 10
+
+/* maximum number of contacts FIXME: this is a guess? */
+#define MAX_CONTACTS 64
+
+/* device ID table */
+static const struct usb_device_id sur40_table[] = {
+ {USB_DEVICE(ID_MICROSOFT, ID_SUR40)}, /* Samsung SUR40 */
+ {} /* terminating null entry */
+};
+
+/* control commands */
+#define SUR40_GET_VERSION 0xb0 /* 12 bytes string */
+#define SUR40_UNKNOWN1 0xb3 /* 5 bytes */
+#define SUR40_UNKNOWN2 0xc1 /* 24 bytes */
+
+#define SUR40_GET_STATE 0xc5 /* 4 bytes state (?) */
+#define SUR40_GET_SENSORS 0xb1 /* 8 bytes sensors */
+
+/*
+ * Note: an earlier, non-public version of this driver used USB_RECIP_ENDPOINT
+ * here by mistake which is very likely to have corrupted the firmware EEPROM
+ * on two separate SUR40 devices. Thanks to Alan Stern who spotted this bug.
+ * Should you ever run into a similar problem, the background story to this
+ * incident and instructions on how to fix the corrupted EEPROM are available
+ * at https://floe.butterbrot.org/matrix/hacking/surface/brick.html
+*/
+#define sur40_command(dev, command, index, buffer, size) \
+ usb_control_msg(dev->usbdev, usb_rcvctrlpipe(dev->usbdev, 0), \
+ command, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, 0x00, \
+ index, buffer, size, 1000)
+
+MODULE_DEVICE_TABLE(usb, sur40_table);
+
+/* structure to hold all of our device specific stuff */
+struct sur40_state {
+
+ struct usb_device *usbdev; /* save the usb device pointer */
+ struct input_polled_dev *input; /* struct for polled input device */
+
+ struct sur40_data *bulk_in_buffer; /* the buffer to receive data */
+ size_t bulk_in_size; /* the maximum bulk packet size */
+ __u8 bulk_in_epaddr; /* address of the bulk in endpoint */
+
+ char phys[64]; /* buffer for phys name */
+};
+
+/* debug helper macro */
+#define get_dev(x) (&(x->usbdev->dev))
+
+/* initialization routine, called from sur40_open */
+static int sur40_init(struct sur40_state *dev)
+{
+ int result;
+ __u8 buffer[24];
+
+ /* stupidly replay the original MS driver init sequence */
+ result = sur40_command(dev, SUR40_GET_VERSION, 0x00, buffer, 12);
+ if (result < 0)
+ return result;
+
+ result = sur40_command(dev, SUR40_GET_VERSION, 0x01, buffer, 12);
+ if (result < 0)
+ return result;
+
+ result = sur40_command(dev, SUR40_GET_VERSION, 0x02, buffer, 12);
+ if (result < 0)
+ return result;
+
+ result = sur40_command(dev, SUR40_UNKNOWN2, 0x00, buffer, 24);
+ if (result < 0)
+ return result;
+
+ result = sur40_command(dev, SUR40_UNKNOWN1, 0x00, buffer, 5);
+ if (result < 0)
+ return result;
+
+ result = sur40_command(dev, SUR40_GET_VERSION, 0x03, buffer, 12);
+
+ /* discard the result buffer - no known data inside except
+ some version strings, maybe extract these sometime.. */
+
+ return result;
+}
+
+/*
+ * callback routines from input_polled_dev
+*/
+
+/* enable the device, polling will now start */
+void sur40_open(struct input_polled_dev *polldev)
+{
+ struct sur40_state *sur40 = polldev->private;
+ dev_dbg(get_dev(sur40), "open\n");
+ sur40_init(sur40);
+}
+
+/* disable device, polling has stopped */
+void sur40_close(struct input_polled_dev *polldev)
+{
+ /* no known way to stop the device, except to stop polling */
+ struct sur40_state *sur40 = polldev->private;
+ dev_dbg(get_dev(sur40), "close\n");
+}
+
+/*
+ * this function is called when a whole contact has been processed,
+ * so that it can assign it to a slot and store the data there
+ */
+static void report_blob(struct sur40_blob *blob, struct input_dev *input)
+{
+ int wide, major, minor;
+
+ int slotnum = input_mt_get_slot_by_key(input, blob->blob_id);
+ if (slotnum < 0 || slotnum >= MAX_CONTACTS)
+ return;
+
+ input_mt_slot(input, slotnum);
+ input_mt_report_slot_state(input, MT_TOOL_FINGER, 1);
+ wide = (blob->bb_size_x > blob->bb_size_y);
+ major = max(blob->bb_size_x, blob->bb_size_y);
+ minor = min(blob->bb_size_x, blob->bb_size_y);
+
+ input_event(input, EV_ABS, ABS_MT_POSITION_X, blob->pos_x);
+ input_event(input, EV_ABS, ABS_MT_POSITION_Y, blob->pos_y);
+ input_event(input, EV_ABS, ABS_MT_TOOL_X, blob->ctr_x);
+ input_event(input, EV_ABS, ABS_MT_TOOL_Y, blob->ctr_y);
+ /* TODO: use a better orientation measure */
+ input_event(input, EV_ABS, ABS_MT_ORIENTATION, wide);
+ input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, major);
+ input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, minor);
+}
+
+/* core function: poll for new input data */
+void sur40_poll(struct input_polled_dev *polldev)
+{
+
+ struct sur40_state *sur40 = polldev->private;
+ struct input_dev *input = polldev->input;
+ int result, bulk_read, need_blobs, packet_blobs, i;
+ uint32_t packet_id;
+
+ struct sur40_header *header = &(sur40->bulk_in_buffer->header);
+ struct sur40_blob *inblob = &(sur40->bulk_in_buffer->blobs[0]);
+
+ need_blobs = -1;
+
+ dev_dbg(get_dev(sur40), "poll\n");
+
+ do {
+
+ /* perform a blocking bulk read to get data from the device */
+ result = usb_bulk_msg(sur40->usbdev,
+ usb_rcvbulkpipe(sur40->usbdev, sur40->bulk_in_epaddr),
+ sur40->bulk_in_buffer, sur40->bulk_in_size,
+ &bulk_read, 1000);
+
+ dev_dbg(get_dev(sur40), "received %d bytes\n", bulk_read);
+
+ if (result < 0) {
+ dev_err(get_dev(sur40), "error in usb_bulk_read\n");
+ return;
+ }
+
+ result = bulk_read - sizeof(struct sur40_header);
+
+ if (result % sizeof(struct sur40_blob) != 0) {
+ dev_err(get_dev(sur40), "transfer size mismatch\n");
+ return;
+ }
+
+ /* first packet? */
+ if (need_blobs == -1) {
+ need_blobs = header->count;
+ dev_dbg(get_dev(sur40), "need %d blobs\n", need_blobs);
+ packet_id = header->packet_id;
+ }
+
+ /* sanity check. when video data is also being retrieved, the
+ * packet ID will usually increase in the middle of a series
+ * instead of at the end. */
+ if (packet_id != header->packet_id)
+ dev_warn(get_dev(sur40), "packet ID mismatch\n");
+
+ packet_blobs = result / sizeof(struct sur40_blob);
+ dev_dbg(get_dev(sur40), "received %d blobs\n", packet_blobs);
+
+ /* packets always contain at least 4 blobs, even if empty */
+ if (packet_blobs > need_blobs)
+ packet_blobs = need_blobs;
+
+ for (i = 0; i < packet_blobs; i++) {
+ need_blobs--;
+ dev_dbg(get_dev(sur40), "processing blob\n");
+ report_blob(&(inblob[i]), input);
+ }
+
+ } while (need_blobs > 0);
+
+ input_mt_sync_frame(input);
+ input_sync(input);
+}
+
+/*
+ * housekeeping routines
+*/
+
+/* initialize input device parameters */
+static void sur40_input_setup(struct input_dev *input_dev)
+{
+ set_bit(EV_KEY, input_dev->evbit);
+ set_bit(EV_SYN, input_dev->evbit);
+ set_bit(EV_ABS, input_dev->evbit);
+
+ input_set_abs_params(input_dev, ABS_MT_POSITION_X,
+ 0, SENSOR_RES_X, 0, 0);
+ input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
+ 0, SENSOR_RES_Y, 0, 0);
+
+ input_set_abs_params(input_dev, ABS_MT_TOOL_X,
+ 0, SENSOR_RES_X, 0, 0);
+ input_set_abs_params(input_dev, ABS_MT_TOOL_Y,
+ 0, SENSOR_RES_Y, 0, 0);
+
+ /* max value unknown, but major/minor axis
+ * can never be larger than screen */
+ input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,
+ 0, SENSOR_RES_X, 0, 0);
+ input_set_abs_params(input_dev, ABS_MT_TOUCH_MINOR,
+ 0, SENSOR_RES_Y, 0, 0);
+
+ input_set_abs_params(input_dev, ABS_MT_ORIENTATION, 0, 1, 0, 0);
+
+ input_mt_init_slots(input_dev, MAX_CONTACTS,
+ INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED);
+}
+
+/* clean up all allocated buffers/structs */
+static inline void sur40_delete(struct sur40_state *sur40)
+{
+ input_free_polled_device(sur40->input);
+ kfree(sur40->bulk_in_buffer);
+ kfree(sur40);
+}
+
+/* check candidate USB interface */
+static int sur40_probe(struct usb_interface *interface,
+ const struct usb_device_id *id)
+{
+ struct usb_device *usbdev = interface_to_usbdev(interface);
+ struct sur40_state *sur40;
+ struct usb_host_interface *iface_desc;
+ struct usb_endpoint_descriptor *endpoint;
+ struct input_polled_dev *poll_dev;
+ int result;
+
+ /* check if we really have the right interface */
+ iface_desc = &interface->altsetting[0];
+ if (iface_desc->desc.bInterfaceClass != 0xFF)
+ return -ENODEV;
+
+ /* use endpoint #4 (0x86) */
+ endpoint = &iface_desc->endpoint[4].desc;
+ if (endpoint->bEndpointAddress != TOUCH_ENDPOINT)
+ return -ENODEV;
+
+ /* allocate memory for our device state and initialize it */
+ sur40 = kzalloc(sizeof(struct sur40_state), GFP_KERNEL);
+ if (!sur40)
+ return -ENOMEM;
+
+ poll_dev = input_allocate_polled_device();
+ if (!poll_dev) {
+ kfree(sur40);
+ return -ENOMEM;
+ }
+
+ /* setup polled input device control struct */
+ poll_dev->private = sur40;
+ poll_dev->poll_interval = POLL_INTERVAL;
+ poll_dev->open = sur40_open;
+ poll_dev->poll = sur40_poll;
+ poll_dev->close = sur40_close;
+
+ /* setup regular input device struct */
+ sur40_input_setup(poll_dev->input);
+
+ poll_dev->input->name = "Samsung SUR40";
+ usb_to_input_id(usbdev, &(poll_dev->input->id));
+ usb_make_path(usbdev, sur40->phys, sizeof(sur40->phys));
+ strlcat(sur40->phys, "/input0", sizeof(sur40->phys));
+ poll_dev->input->phys = sur40->phys;
+
+ sur40->usbdev = usbdev;
+ sur40->input = poll_dev;
+
+ /* use the bulk-in endpoint tested above */
+ sur40->bulk_in_size = le16_to_cpu(endpoint->wMaxPacketSize);
+ sur40->bulk_in_epaddr = endpoint->bEndpointAddress;
+ sur40->bulk_in_buffer = kmalloc(sur40->bulk_in_size, GFP_KERNEL);
+ if (!sur40->bulk_in_buffer) {
+ dev_err(&interface->dev, "Unable to allocate input buffer.");
+ sur40_delete(sur40);
+ return -ENOMEM;
+ }
+
+ result = input_register_polled_device(poll_dev);
+ if (result) {
+ dev_err(&interface->dev,
+ "Unable to register polled input device.");
+ sur40_delete(sur40);
+ return result;
+ }
+
+ /* we can register the device now, as it is ready */
+ usb_set_intfdata(interface, sur40);
+ dev_dbg(&interface->dev, "%s now attached\n", DRIVER_DESC);
+
+ return 0;
+}
+
+/* unregister device & clean up */
+static void sur40_disconnect(struct usb_interface *interface)
+{
+ struct sur40_state *sur40 = usb_get_intfdata(interface);
+
+ input_unregister_polled_device(sur40->input);
+
+ usb_set_intfdata(interface, NULL);
+
+ sur40_delete(sur40);
+
+ dev_dbg(&interface->dev, "%s now disconnected\n", DRIVER_DESC);
+}
+
+/* usb specific object needed to register this driver with the usb subsystem */
+static struct usb_driver sur40_driver = {
+ .name = DRIVER_SHORT,
+ .probe = sur40_probe,
+ .disconnect = sur40_disconnect,
+ .id_table = sur40_table,
+};
+
+module_usb_driver(sur40_driver);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
--
1.7.9.5
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox