* Re: [PATCH v4 0/3] input: appletouch: fixes for jagged/uneven cursor movement
From: Henrik Rydberg @ 2014-03-23 14:02 UTC (permalink / raw)
To: Clinton Sprain, linux-input; +Cc: Dmitry Torokhov
In-Reply-To: <5320EA03.2040206@gmail.com>
> input: appletouch: fixes for jagged/uneven cursor movement
>
> The appletouch driver can make some touchpads feel insensitive, with movement that tends to jerk in steps. This is particularly evident when moving diagonally. There is also undesirable movement when additional fingers enter or leave the touchpad.
>
> These patches address these issues by dialing back the fuzz setting, by implementing sensor data smoothing and by discarding movements that directly coincide with a change in the number of fingers detected on the touchpad.
Thanks Clinton, for resolving this long-standing nuisance. It all looks good to
me now.
Henrik
^ permalink raw reply
* Re: [PATCH] HID: uhid: Add UHID_CREATE2 + UHID_INPUT2
From: David Herrmann @ 2014-03-23 14:22 UTC (permalink / raw)
To: Petri Gynther; +Cc: open list:HID CORE LAYER, Jiri Kosina
In-Reply-To: <20140319034501.4B61E10081C@puck.mtv.corp.google.com>
Hi
On Wed, Mar 19, 2014 at 4:45 AM, Petri Gynther <pgynther@google.com> wrote:
> UHID_CREATE2:
> HID report descriptor data (rd_data) is an array in struct uhid_create2_req,
> instead of a pointer. Enables use from languages that don't support pointers,
> e.g. Python.
..and this also makes the x32-COMPAT crap obsolete.
>
> UHID_INPUT2:
> Data array is the last field of struct uhid_input2_req. Enables userspace to
> write only the required bytes to kernel (ev.type + ev.u.input2.size + the part
> of the data array that matters), instead of the entire struct uhid_input2_req.
We should have swapped these fields right from the beginning. We
explicitly support truncated input, but I only ever tested that with
output, not input.. Thanks for fixing that!
> Signed-off-by: Petri Gynther <pgynther@google.com>
> ---
> Documentation/hid/uhid.txt | 11 +++++++
> drivers/hid/uhid.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++
> include/uapi/linux/uhid.h | 23 +++++++++++++
> 3 files changed, 114 insertions(+)
>
> diff --git a/Documentation/hid/uhid.txt b/Documentation/hid/uhid.txt
> index dc35a2b..ee65936 100644
> --- a/Documentation/hid/uhid.txt
> +++ b/Documentation/hid/uhid.txt
> @@ -93,6 +93,11 @@ the request was handled successfully.
> event to the kernel. The payload is of type struct uhid_create_req and
> contains information about your device. You can start I/O now.
>
> + UHID_CREATE2:
> + Same as UHID_CREATE, but the HID report descriptor data (rd_data) is an array
> + inside struct uhid_create2_req, instead of a pointer to a separate array.
> + Enables use from languages that don't support pointers, e.g. Python.
> +
> UHID_DESTROY:
> This destroys the internal HID device. No further I/O will be accepted. There
> may still be pending messages that you can receive with read() but no further
> @@ -105,6 +110,12 @@ the request was handled successfully.
> contains a data-payload. This is the raw data that you read from your device.
> The kernel will parse the HID reports and react on it.
>
> + UHID_INPUT2:
> + Same as UHID_INPUT, but the data array is the last field of uhid_input2_req.
> + Enables userspace to write only the required bytes to kernel (ev.type +
> + ev.u.input2.size + the part of the data array that matters), instead of
> + the entire struct uhid_input2_req.
> +
> UHID_FEATURE_ANSWER:
> If you receive a UHID_FEATURE request you must answer with this request. You
> must copy the "id" field from the request into the answer. Set the "err" field
> diff --git a/drivers/hid/uhid.c b/drivers/hid/uhid.c
> index cedc6da..c5ee173 100644
> --- a/drivers/hid/uhid.c
> +++ b/drivers/hid/uhid.c
> @@ -407,6 +407,69 @@ err_free:
> return ret;
> }
>
> +static int uhid_dev_create2(struct uhid_device *uhid,
> + const struct uhid_event *ev)
> +{
> + struct hid_device *hid;
> + int ret;
> +
> + if (uhid->running)
> + return -EALREADY;
> +
> + uhid->rd_size = ev->u.create2.rd_size;
> + if (uhid->rd_size <= 0 || uhid->rd_size > HID_MAX_DESCRIPTOR_SIZE)
> + return -EINVAL;
> +
> + uhid->rd_data = kmalloc(uhid->rd_size, GFP_KERNEL);
> + if (!uhid->rd_data)
> + return -ENOMEM;
> +
> + memcpy(uhid->rd_data, ev->u.create2.rd_data, uhid->rd_size);
Why don't we just use uhid_dev_create() and do this:
if (ev->type == UHID_CREATE) {
...copy_from_user()...
} else if (ev->type == UHID_CREATE2) {
memcpy(...);
}
This way we can avoid copying this whole function.
> +
> + hid = hid_allocate_device();
> + if (IS_ERR(hid)) {
> + ret = PTR_ERR(hid);
> + goto err_free;
> + }
> +
> + strncpy(hid->name, ev->u.create2.name, 127);
> + hid->name[127] = 0;
> + strncpy(hid->phys, ev->u.create2.phys, 63);
> + hid->phys[63] = 0;
> + strncpy(hid->uniq, ev->u.create2.uniq, 63);
> + hid->uniq[63] = 0;
> +
> + hid->ll_driver = &uhid_hid_driver;
> + hid->hid_get_raw_report = uhid_hid_get_raw;
> + hid->hid_output_raw_report = uhid_hid_output_raw;
> + hid->bus = ev->u.create2.bus;
> + hid->vendor = ev->u.create2.vendor;
> + hid->product = ev->u.create2.product;
> + hid->version = ev->u.create2.version;
> + hid->country = ev->u.create2.country;
> + hid->driver_data = uhid;
> + hid->dev.parent = uhid_misc.this_device;
> +
> + uhid->hid = hid;
> + uhid->running = true;
> +
> + ret = hid_add_device(hid);
> + if (ret) {
> + hid_err(hid, "Cannot register HID device\n");
> + goto err_hid;
> + }
> +
> + return 0;
> +
> +err_hid:
> + hid_destroy_device(hid);
> + uhid->hid = NULL;
> + uhid->running = false;
> +err_free:
> + kfree(uhid->rd_data);
> + return ret;
> +}
> +
> static int uhid_dev_destroy(struct uhid_device *uhid)
> {
> if (!uhid->running)
> @@ -435,6 +498,17 @@ static int uhid_dev_input(struct uhid_device *uhid, struct uhid_event *ev)
> return 0;
> }
>
> +static int uhid_dev_input2(struct uhid_device *uhid, struct uhid_event *ev)
> +{
> + if (!uhid->running)
> + return -EINVAL;
> +
> + hid_input_report(uhid->hid, HID_INPUT_REPORT, ev->u.input2.data,
> + min_t(size_t, ev->u.input2.size, UHID_DATA_MAX), 0);
> +
> + return 0;
> +}
> +
> static int uhid_dev_feature_answer(struct uhid_device *uhid,
> struct uhid_event *ev)
> {
> @@ -571,12 +645,18 @@ static ssize_t uhid_char_write(struct file *file, const char __user *buffer,
> case UHID_CREATE:
> ret = uhid_dev_create(uhid, &uhid->input_buf);
> break;
> + case UHID_CREATE2:
> + ret = uhid_dev_create2(uhid, &uhid->input_buf);
> + break;
> case UHID_DESTROY:
> ret = uhid_dev_destroy(uhid);
> break;
> case UHID_INPUT:
> ret = uhid_dev_input(uhid, &uhid->input_buf);
> break;
> + case UHID_INPUT2:
> + ret = uhid_dev_input2(uhid, &uhid->input_buf);
> + break;
> case UHID_FEATURE_ANSWER:
> ret = uhid_dev_feature_answer(uhid, &uhid->input_buf);
> break;
> diff --git a/include/uapi/linux/uhid.h b/include/uapi/linux/uhid.h
> index 414b74b..1e3b09c 100644
> --- a/include/uapi/linux/uhid.h
> +++ b/include/uapi/linux/uhid.h
> @@ -21,6 +21,7 @@
>
> #include <linux/input.h>
> #include <linux/types.h>
> +#include <linux/hid.h>
>
> enum uhid_event_type {
> UHID_CREATE,
> @@ -34,6 +35,8 @@ enum uhid_event_type {
> UHID_INPUT,
> UHID_FEATURE,
> UHID_FEATURE_ANSWER,
> + UHID_CREATE2,
> + UHID_INPUT2,
> };
>
> struct uhid_create_req {
> @@ -50,6 +53,19 @@ struct uhid_create_req {
> __u32 country;
> } __attribute__((__packed__));
>
> +struct uhid_create2_req {
> + __u8 name[128];
> + __u8 phys[64];
> + __u8 uniq[64];
> + __u16 rd_size;
> + __u16 bus;
> + __u32 vendor;
> + __u32 product;
> + __u32 version;
> + __u32 country;
> + __u8 rd_data[HID_MAX_DESCRIPTOR_SIZE];
> +} __attribute__((__packed__));
> +
> #define UHID_DATA_MAX 4096
>
> enum uhid_report_type {
> @@ -63,6 +79,11 @@ struct uhid_input_req {
> __u16 size;
> } __attribute__((__packed__));
>
> +struct uhid_input2_req {
> + __u16 size;
> + __u8 data[UHID_DATA_MAX];
> +} __attribute__((__packed__));
> +
> struct uhid_output_req {
> __u8 data[UHID_DATA_MAX];
> __u16 size;
> @@ -100,6 +121,8 @@ struct uhid_event {
> struct uhid_output_ev_req output_ev;
> struct uhid_feature_req feature;
> struct uhid_feature_answer_req feature_answer;
> + struct uhid_create2_req create2;
> + struct uhid_input2_req input2;
We change the size of uhid_output_req here, but I think that is fine.
But you might wanna note that down in the commit-message.
Patch looks fine. If you fix the minor issues, this is:
Reviewed-by: David Herrmann <dh.herrmann@gmail.com>
And please always put Jiri on CC for all HID patches: "Jiri Kosina
<jkosina@suse.cz>"
Thanks
David
> } u;
> } __attribute__((__packed__));
>
> --
> 1.9.0.279.gdc9e3eb
>
> --
> 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
* [patch 16/16] input: serio: hp_sdc: Use del_timer_sync() in exit path
From: Thomas Gleixner @ 2014-03-23 15:09 UTC (permalink / raw)
To: LKML; +Cc: Julia Lawall, Andrew Morton, Dmitry Torokhov, input
In-Reply-To: <20140323150557.288925975@linutronix.de>
[-- Attachment #1: input-serio-hp_sdc-use-del_timer_sync.patch --]
[-- Type: text/plain, Size: 705 bytes --]
Make sure that no callback is running before we teardown the module.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Cc: input <linux-input@vger.kernel.org>
---
drivers/input/serio/hp_sdc.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
Index: tip/drivers/input/serio/hp_sdc.c
===================================================================
--- tip.orig/drivers/input/serio/hp_sdc.c
+++ tip/drivers/input/serio/hp_sdc.c
@@ -984,7 +984,7 @@ static void hp_sdc_exit(void)
free_irq(hp_sdc.irq, &hp_sdc);
write_unlock_irq(&hp_sdc.lock);
- del_timer(&hp_sdc.kicker);
+ del_timer_sync(&hp_sdc.kicker);
tasklet_kill(&hp_sdc.task);
^ permalink raw reply
* [PATCH] drivers/input: Use RCU_INIT_POINTER(x, NULL) in evdev.c
From: Monam Agarwal @ 2014-03-23 18:26 UTC (permalink / raw)
To: dmitry.torokhov, linux-input, linux-kernel
This patch replaces rcu_assign_pointer(x, NULL) with RCU_INIT_POINTER(x, NULL)
The rcu_assign_pointer() ensures that the initialization of a structure
is carried out before storing a pointer to that structure.
And in the case of the NULL pointer, there is no structure to initialize.
So, rcu_assign_pointer(p, NULL) can be safely converted to RCU_INIT_POINTER(p, NULL)
Signed-off-by: Monam Agarwal <monamagarwal123@gmail.com>
---
drivers/input/evdev.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index a06e125..fffa107 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -291,7 +291,7 @@ static int evdev_ungrab(struct evdev *evdev, struct evdev_client *client)
if (grab != client)
return -EINVAL;
- rcu_assign_pointer(evdev->grab, NULL);
+ RCU_INIT_POINTER(evdev->grab, NULL);
synchronize_rcu();
input_release_device(&evdev->handle);
--
1.7.9.5
^ permalink raw reply related
* [PATCH] drivers/input: Use RCU_INIT_POINTER(x, NULL) in input.c
From: Monam Agarwal @ 2014-03-23 18:27 UTC (permalink / raw)
To: dmitry.torokhov, linux-input, linux-kernel
This patch replaces rcu_assign_pointer(x, NULL) with RCU_INIT_POINTER(x, NULL)
The rcu_assign_pointer() ensures that the initialization of a structure
is carried out before storing a pointer to that structure.
And in the case of the NULL pointer, there is no structure to initialize.
So, rcu_assign_pointer(p, NULL) can be safely converted to RCU_INIT_POINTER(p, NULL)
Signed-off-by: Monam Agarwal <monamagarwal123@gmail.com>
---
drivers/input/input.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/input/input.c b/drivers/input/input.c
index 1c4c0db..f9db5ea 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -539,7 +539,7 @@ static void __input_release_device(struct input_handle *handle)
grabber = rcu_dereference_protected(dev->grab,
lockdep_is_held(&dev->mutex));
if (grabber == handle) {
- rcu_assign_pointer(dev->grab, NULL);
+ RCU_INIT_POINTER(dev->grab, NULL);
/* Make sure input_pass_event() notices that grab is gone */
synchronize_rcu();
--
1.7.9.5
^ permalink raw reply related
* Re: [patch 16/16] input: serio: hp_sdc: Use del_timer_sync() in exit path
From: Dmitry Torokhov @ 2014-03-24 0:24 UTC (permalink / raw)
To: Thomas Gleixner; +Cc: LKML, Julia Lawall, Andrew Morton, input
In-Reply-To: <20140323150754.381232240@linutronix.de>
On Sun, Mar 23, 2014 at 03:09:33PM -0000, Thomas Gleixner wrote:
> Make sure that no callback is running before we teardown the module.
>
Applied, thank you Thomas.
> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
> Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
> Cc: input <linux-input@vger.kernel.org>
> ---
> drivers/input/serio/hp_sdc.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> Index: tip/drivers/input/serio/hp_sdc.c
> ===================================================================
> --- tip.orig/drivers/input/serio/hp_sdc.c
> +++ tip/drivers/input/serio/hp_sdc.c
> @@ -984,7 +984,7 @@ static void hp_sdc_exit(void)
> free_irq(hp_sdc.irq, &hp_sdc);
> write_unlock_irq(&hp_sdc.lock);
>
> - del_timer(&hp_sdc.kicker);
> + del_timer_sync(&hp_sdc.kicker);
>
> tasklet_kill(&hp_sdc.task);
>
>
>
--
Dmitry
^ permalink raw reply
* Re: [PATCH 0/2] input/serio: Add a firmware_id sysfs attribute
From: Peter Hutterer @ 2014-03-24 1:07 UTC (permalink / raw)
To: Matthew Garrett, Hans de Goede
Cc: Dmitry Torokhov, Benjamin Tissoires, platform-driver-x86,
linux-input
In-Reply-To: <20140320172159.GA27400@srcf.ucam.org>
On 21/03/14 03:21, Matthew Garrett wrote:
> On Thu, Mar 20, 2014 at 11:12:08AM +0100, Hans de Goede wrote:
>
>> Which in the end turns out to be much nicer too, since it gets rid of needing
>> a udev-helper too. After this much too long introduction I'll let the patches
>> speak for themselves.
>
> Yeah, I was coming to the conclusion that this was probably the best we
> could do. It's unfortunate that "id" is already in use - we'd be able to
> get away without any X server modifications otherwise.
IMO we don't need to worry about that. this is needed for a set of
devices that need a kernel patch, several synaptics patches and a server
patch to work properly anyway, so changes are already required. Approach
looks good, ACK from me.
Cheers,
Peter
>
> Long term we probably still want to tie serio devices to the ACPI
> devices in case the vendor provides power management calls there, but we
> can leave that until there's an actual example.
>
^ permalink raw reply
* Re: Re: [PATCH v2 1/8] mfd: AXP20x: Add mfd driver for AXP20x PMIC
From: Lee Jones @ 2014-03-24 8:34 UTC (permalink / raw)
To: Carlo Caione
Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw,
maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
hdegoede-H+wXaHxf7aLQT0dZR+AlfA, emilio-0Z03zUJReD5OxF6Tv1QG9Q,
wens-jdAy2FN1RRM, sameo-VuQAYsv1563Yd54FQh9/CA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
dmitry.torokhov-Re5JQEeQqe8AvxtiuMwx3w,
linux-input-u79uwXL29TY76Z2rM5mHXA,
linux-doc-u79uwXL29TY76Z2rM5mHXA,
lgirdwood-Re5JQEeQqe8AvxtiuMwx3w, broonie-DgEjT+Ai2ygdnm+yROfE0A
In-Reply-To: <20140322165132.GC20668-bi+AKbBUZKZeIdyRz4JgOMwOAu8XWILU@public.gmane.org>
> > > +static struct mfd_cell axp20x_cells[] = {
> > > + {
> > > + .name = "axp20x-pek",
> > > + .num_resources = ARRAY_SIZE(axp20x_pek_resources),
> > > + .resources = axp20x_pek_resources,
> > > + }, {
> > > + .name = "axp20x-regulator",
> > > + },
> > > +};
> >
> > nit: The format of these two structs are inconsistent.
>
> Uhm, what do you mean?
Well you've removed the struct above this one in your reply. Take a
look at my reply to you and see the differences between this _two_
structs, this being only one of them.
[...]
> > > +static const struct i2c_device_id axp20x_i2c_id[] = {
> > > + { "axp202", AXP202_ID },
> > > + { "axp209", AXP209_ID },
> > > + { }
> > > +};
> > > +MODULE_DEVICE_TABLE(i2c, axp20x_i2c_id);
> >
> > Isn't this redundant now that you're using of_id?
>
> It is not. Even it is unused it has to be in the driver otherwise the
> driver is not loaded. Probably it is something wrong in the I2C core.
Sorry, I should have been more specific. The I2C core requires this
struct, but the IDs are unused and redundant. Best remove them in
order to mitigate any confusion.
--
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog
--
You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org
For more options, visit https://groups.google.com/d/optout.
^ permalink raw reply
* Re: [PATCH 00/15] iio: adc: at91 cleanups and atmel_tsadcc removal
From: Nicolas Ferre @ 2014-03-24 9:00 UTC (permalink / raw)
To: Jonathan Cameron
Cc: Alexandre Belloni, Dmitry Torokhov, ARM Maintainers, linux-iio,
linux-kernel, linux-input, Gregory Clement, Maxime Ripard,
Jean-Christophe Plagniol-Villard, linux-arm-kernel
In-Reply-To: <532D828A.8000108@kernel.org>
On 22/03/2014 13:31, Jonathan Cameron :
> On 19/03/14 10:19, Nicolas Ferre wrote:
>> On 16/03/2014 19:30, Jonathan Cameron :
>>> On 05/03/14 17:35, Alexandre Belloni wrote:
>>>> This patch set is a followup of my previous series: iio: adc: at91 fixes
>>>>
>>>> I'm sorry it is so long, I made sure this is bissectable.
>>> It's a nice series, don't apologise for doing things right!
>>>
>>> Clearly there are a few outstanding snippets from the reviews so far, but we
>>> are getting to the point where we need to agree on a path for this. I'm
>>> happy to take the whole series through the IIO tree if Dmitry and the at91
>>> maintainers are happy with that. If it is considered two invasive form the
>>> atmel side then I'm perfectly happy with someone to take it through the relevant
>>> platform tree instead.
>>
>> Jonathan, Dmitry,
>>
>> Considering the amount of AT91 files touched by this series, I would
>> like to take everything through Atmel's git tree and later on arm-soc.
> Sure. Just as a warning, there are one or two patches queued up already that this
> sits on top of. Give a spot of bad timing these are too late to go in as fixes
> before the release. Might be worth waiting on those hitting Linus' tree sometime
> after rc1 before taking this series.
Okay, advice well-noted.
Thanks Jonathan.
>>> I'm obviously not going to pick it up at all until it has a complete set
>>> of at91 maintainer acks though!
>>>
>>> Realistically it's missed the coming merge window anyway, so we have a fair
>>> bit of time.
>>
>> Yes, I will review Alexandre's v2 series.
>>
>> Thanks a lot for your review and for having thought about the path that
>> these patches would take.
>>
>> Bye,
>>
>>
>>> Jonathan
>>>>
>>>> 1-3) The first 3 patches are cleaning up the patform_data used for at91_adc.
>>>>
>>>> 4-5) Then touchscreen support for older ADCs is added, this allows to use that
>>>> for the sam9m10g45ek.
>>>>
>>>> 6) Following those modifications, the mach/at91_adc.h is not used anywhere but
>>>> in the at91_adc driver so it is remove and its content (register definitions)
>>>> placed directly in the driver.
>>>>
>>>> 7-9) at91sam9rl support is added to at91_adc and is used for the at91sam9rl
>>>> based boards.
>>>>
>>>> 10-11) Prepare the atmel_tsadcc removal by switching sam9rl and sam9g45 to use
>>>> only at91_adc instead of atmel_tsadcc.
>>>>
>>>> 12-15) atmel_tsadcc removal
>>>>
>>>>
>>>> Alexandre Belloni (15):
>>>> ARM: at91: sam9g45: remove unused platform_data
>>>> ARM: at91: sam9260: remove unused platform_data
>>>> iio: adc: at91: cleanup platform_data
>>>> iio: adc: at91_adc: Add support for touchscreens without TSMR
>>>> ARM: at91: sam9m10g45ek: Add touchscreen support through at91_adc
>>>> iio: adc: at91: remove unused include from include/mach
>>>> iio: adc: at91: add sam9rl support
>>>> ARM: at91: sam9rl: add at91_adc to support adc and touchscreen
>>>> ARM: at91: sam9rlek add touchscreen support through at91_adc
>>>> ARM: at91: sam9g45: switch from atmel_tsadcc to at91_adc
>>>> ARM: at91: sam9rl: switch from atmel_tsadcc to at91_adc
>>>> ARM: at91: remove atmel_tsadcc platform_data
>>>> ARM: at91: remove atmel_tsadcc from sama5_defconfig
>>>> Input: atmel_tsadcc: remove driver
>>>> ARM: at91/dt: at91-cosino_mega2560 remove useless tsadcc node
>>>>
>>>> MAINTAINERS | 6 -
>>>> arch/arm/boot/dts/at91-cosino_mega2560.dts | 5 -
>>>> arch/arm/configs/at91sam9g45_defconfig | 3 +-
>>>> arch/arm/configs/at91sam9rl_defconfig | 3 +-
>>>> arch/arm/configs/sama5_defconfig | 1 -
>>>> arch/arm/mach-at91/at91sam9260_devices.c | 10 -
>>>> arch/arm/mach-at91/at91sam9g45.c | 2 +-
>>>> arch/arm/mach-at91/at91sam9g45_devices.c | 63 +----
>>>> arch/arm/mach-at91/at91sam9rl.c | 7 +
>>>> arch/arm/mach-at91/at91sam9rl_devices.c | 83 +++++--
>>>> arch/arm/mach-at91/board-sam9m10g45ek.c | 16 +-
>>>> arch/arm/mach-at91/board-sam9rlek.c | 16 +-
>>>> arch/arm/mach-at91/board.h | 3 -
>>>> arch/arm/mach-at91/include/mach/at91_adc.h | 107 ---------
>>>> drivers/iio/adc/at91_adc.c | 339 +++++++++++++++++++++++----
>>>> drivers/input/touchscreen/Kconfig | 12 -
>>>> drivers/input/touchscreen/Makefile | 1 -
>>>> drivers/input/touchscreen/atmel_tsadcc.c | 358 -----------------------------
>>>> include/linux/platform_data/at91_adc.h | 27 +--
>>>> include/linux/platform_data/atmel.h | 7 -
>>>> 20 files changed, 380 insertions(+), 689 deletions(-)
>>>> delete mode 100644 arch/arm/mach-at91/include/mach/at91_adc.h
>>>> delete mode 100644 drivers/input/touchscreen/atmel_tsadcc.c
>>>>
>>>
>>>
>>> _______________________________________________
>>> linux-arm-kernel mailing list
>>> linux-arm-kernel@lists.infradead.org
>>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>>>
>>
>>
>
>
--
Nicolas Ferre
^ permalink raw reply
* Re: [PATCH v2 12/15] ARM: at91: remove atmel_tsadcc platform_data
From: Alexandre Belloni @ 2014-03-24 9:46 UTC (permalink / raw)
To: Nicolas Ferre
Cc: Jonathan Cameron, Dmitry Torokhov,
Jean-Christophe Plagniol-Villard,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-iio-u79uwXL29TY76Z2rM5mHXA,
linux-input-u79uwXL29TY76Z2rM5mHXA, Maxime Ripard,
Gregory Clement
In-Reply-To: <532D8474.8020601-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
On 22/03/2014 at 12:39:16 +0000, Jonathan Cameron wrote :
> On 17/03/14 13:57, Alexandre Belloni wrote:
> >Signed-off-by: Alexandre Belloni <alexandre.belloni-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
> See below.
> >---
> > arch/arm/mach-at91/board.h | 3 ---
> > include/linux/platform_data/atmel.h | 7 -------
> > 2 files changed, 10 deletions(-)
> >
> >diff --git a/arch/arm/mach-at91/board.h b/arch/arm/mach-at91/board.h
> >index 6c08b341167d..4e773b55bc2d 100644
> >--- a/arch/arm/mach-at91/board.h
> >+++ b/arch/arm/mach-at91/board.h
> >@@ -118,9 +118,6 @@ struct isi_platform_data;
> > extern void __init at91_add_device_isi(struct isi_platform_data *data,
> > bool use_pck_as_mck);
> >
> >- /* Touchscreen Controller */
> >-extern void __init at91_add_device_tsadcc(struct at91_tsadcc_data *data);
> >-
> > /* CAN */
> > extern void __init at91_add_device_can(struct at91_can_data *data);
> >
> >diff --git a/include/linux/platform_data/atmel.h b/include/linux/platform_data/atmel.h
> >index cea9f70133c5..4b452c6a2f7b 100644
> >--- a/include/linux/platform_data/atmel.h
> >+++ b/include/linux/platform_data/atmel.h
> >@@ -86,13 +86,6 @@ struct atmel_uart_data {
> > struct serial_rs485 rs485; /* rs485 settings */
> > };
> >
> >- /* Touchscreen Controller */
> >-struct at91_tsadcc_data {
> >- unsigned int adc_clock;
> >- u8 pendet_debounce;
> >- u8 ts_sample_hold_time;
> >-};
> >-
> I believe this is still in use in the driver you don't remove until patch 14.
>
> Probably best to reorder the patches...
Indeed, you are right.
Nicolas, do you take care of that or should I send a v3 ?
--
Alexandre Belloni, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
^ permalink raw reply
* Re: [PATCH] HID: uhid: Add UHID_CREATE2 + UHID_INPUT2
From: Jiri Kosina @ 2014-03-24 12:50 UTC (permalink / raw)
To: David Herrmann; +Cc: Petri Gynther, open list:HID CORE LAYER
In-Reply-To: <CANq1E4SKtB3+pQas9NVE93yVJAArc=LB1r2ojTgE=33YzRnDiw@mail.gmail.com>
On Sun, 23 Mar 2014, David Herrmann wrote:
[ ... snip ... ]
> Patch looks fine. If you fix the minor issues, this is:
> Reviewed-by: David Herrmann <dh.herrmann@gmail.com>
>
> And please always put Jiri on CC for all HID patches: "Jiri Kosina
> <jkosina@suse.cz>"
Indeed, that helps. Petri, could you please resend the patch proper to me
with David's 'Reviewed-by' tag included?
Thanks,
--
Jiri Kosina
SUSE Labs
^ permalink raw reply
* Re: [PATCH v2 1/5] drivers: input: keyboard: st-keyscan: add keyscan driver
From: Lee Jones @ 2014-03-24 13:36 UTC (permalink / raw)
To: Gabriel FERNANDEZ
Cc: Dmitry Torokhov, Rob Herring, Pawel Moll, Mark Rutland,
Ian Campbell, Kumar Gala, Rob Landley, Russell King, Grant Likely,
devicetree, linux-doc, linux-kernel, linux-arm-kernel,
linux-input, kernel, Giuseppe Condorelli
In-Reply-To: <1395154806-2810-2-git-send-email-gabriel.fernandez@st.com>
> This patch adds ST Keyscan driver to use the keypad hw a subset
> of ST boards provide. Specific board setup will be put in the
> given dt.
>
> Signed-off-by: Gabriel Fernandez <gabriel.fernandez@st.com>
> Signed-off-by: Giuseppe Condorelli <giuseppe.condorelli@st.com>
> ---
> .../devicetree/bindings/input/st-keyscan.txt | 60 +++++
> drivers/input/keyboard/Kconfig | 12 +
> drivers/input/keyboard/Makefile | 1 +
> drivers/input/keyboard/st-keyscan.c | 260 +++++++++++++++++++++
> 4 files changed, 333 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/input/st-keyscan.txt
> create mode 100644 drivers/input/keyboard/st-keyscan.c
FWIW: This looks good to me now:
Acked-by: Lee Jones <lee.jones@linaro.org>
--
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog
^ permalink raw reply
* [PATCH] input: cypress_ps2: Don't report the cypress PS/2 trackpads as a button pad
From: Hans de Goede @ 2014-03-24 13:49 UTC (permalink / raw)
To: Dmitry Torokhov
Cc: Benjamin Tissoires, linux-input, Hans de Goede, Adam Williamson,
Peter Hutterer
The cypress PS/2 trackpad models supported by the cypress_ps2 driver emulate
BTN_RIGHT events in firmware based on the finger position, as part of this
no motion events are sent when the finger is in the button area.
The INPUT_PROP_BUTTONPAD property is there to indicate to userspace that
BTN_RIGHT events should be emulated in userspace, which is not necessary
in this case.
When INPUT_PROP_BUTTONPAD is advertised userspace will wait for a motion event
before propagating the button event higher up the stack, as it needs current
abs x + y data for its BTN_RIGHT emulation. Since in the cypress_ps2 pads
don't report motion events in the button area, this means that clicks in the
button area end up being ignored, so INPUT_PROP_BUTTONPAD actually causes
problems for these touchpads, and removing it fixes:
https://bugs.freedesktop.org/show_bug.cgi?id=76341
Reported-by: Adam Williamson <awilliam@redhat.com>
Tested-by: Adam Williamson <awilliam@redhat.com>
Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>
Cc: Adam Williamson <awilliam@redhat.com>
Cc: Peter Hutterer <peter.hutterer@who-t.net>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
drivers/input/mouse/cypress_ps2.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/drivers/input/mouse/cypress_ps2.c b/drivers/input/mouse/cypress_ps2.c
index 87095e2..8af34ff 100644
--- a/drivers/input/mouse/cypress_ps2.c
+++ b/drivers/input/mouse/cypress_ps2.c
@@ -409,7 +409,6 @@ static int cypress_set_input_params(struct input_dev *input,
__clear_bit(REL_X, input->relbit);
__clear_bit(REL_Y, input->relbit);
- __set_bit(INPUT_PROP_BUTTONPAD, input->propbit);
__set_bit(EV_KEY, input->evbit);
__set_bit(BTN_LEFT, input->keybit);
__set_bit(BTN_RIGHT, input->keybit);
--
1.9.0
^ permalink raw reply related
* [PATCHv6 0/5] Input: edt-ft5x06: Add DT support
From: Lothar Waßmann @ 2014-03-24 15:11 UTC (permalink / raw)
To: Dmitry Torokhov, Fugang Duan, Grant Likely, Henrik Rydberg,
Ian Campbell, Jingoo Han, Kumar Gala, Mark Rutland, Pawel Moll,
Rob Herring, Rob Landley, Sachin Kamat, devicetree, linux-doc,
linux-input, linux-kernel, Simon Budig, Lothar Waßmann,
Daniel Wagener
In-Reply-To: <1395323075-12146-1-git-send-email-LW@KARO-electronics.de>
Changes wrt. v1:
addressed the comments from Jingoo Han and Mark Rutland
- added another patch to convert the driver to use devm_* functions
- removed sysfs reference from bindings documentation
- changed '_' to '-' in property name
- added 'edt,' prefix to properties names
- added sanity check for parameters read from DT
- cleaned up the gpio handling code
Changes wrt. v2:
- fixed the devm_* messup reported by Dmitry Torokhov
- added unit for report-rate property to the binding doc
- added separate patch to fix the reset delays
Changes wrt: v3:
- removed patches that have already been applied in the mean time
- ignore touchdown events, since those may report bad coordinates
- added support for a new firmware version
Changes wrt: v4:
- removed some empty lines in the cleanup patch
- addressed comments by Mark Rutland concerning the binding doc
- use of_property_read_u32() instead of of_property_get()
- dropped the 'report_rate' property
- addressed comments by Fugang Duan
- added Daniel Wagener and myself to the Copyright header in the
source file
- use msleep() rather than mdelay() for the reset/wake pin timing
Changes wrt: v5:
- added missing '&' to parameter of of_property_read_u32()
^ permalink raw reply
* [PATCHv6 1/5] Input: edt-ft5x06: several cleanups; no functional change
From: Lothar Waßmann @ 2014-03-24 15:11 UTC (permalink / raw)
To: Dmitry Torokhov, Fugang Duan, Grant Likely, Henrik Rydberg,
Ian Campbell, Jingoo Han, Kumar Gala, Mark Rutland, Pawel Moll,
Rob Herring, Rob Landley, Sachin Kamat, devicetree, linux-doc,
linux-input, linux-kernel, Simon Budig, Lothar Waßmann,
Daniel Wagener
In-Reply-To: <1395673870-29435-1-git-send-email-LW@KARO-electronics.de>
- remove redundant parens
- remove redundant type casts
- fix mixed tab/space indentation
Signed-off-by: Lothar Waßmann <LW@KARO-electronics.de>
---
drivers/input/touchscreen/edt-ft5x06.c | 15 ++++++---------
1 file changed, 6 insertions(+), 9 deletions(-)
diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c
index 412a85e..155ab3b 100644
--- a/drivers/input/touchscreen/edt-ft5x06.c
+++ b/drivers/input/touchscreen/edt-ft5x06.c
@@ -173,7 +173,7 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id)
x = ((buf[0] << 8) | buf[1]) & 0x0fff;
y = ((buf[2] << 8) | buf[3]) & 0x0fff;
id = (buf[2] >> 4) & 0x0f;
- down = (type != TOUCH_EVENT_UP);
+ down = type != TOUCH_EVENT_UP;
input_mt_slot(tsdata->input, id);
input_mt_report_slot_state(tsdata->input, MT_TOOL_FINGER, down);
@@ -257,7 +257,7 @@ static ssize_t edt_ft5x06_setting_show(struct device *dev,
struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client);
struct edt_ft5x06_attribute *attr =
container_of(dattr, struct edt_ft5x06_attribute, dattr);
- u8 *field = (u8 *)((char *)tsdata + attr->field_offset);
+ u8 *field = (u8 *)tsdata + attr->field_offset;
int val;
size_t count = 0;
int error = 0;
@@ -299,7 +299,7 @@ static ssize_t edt_ft5x06_setting_store(struct device *dev,
struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client);
struct edt_ft5x06_attribute *attr =
container_of(dattr, struct edt_ft5x06_attribute, dattr);
- u8 *field = (u8 *)((char *)tsdata + attr->field_offset);
+ u8 *field = (u8 *)tsdata + attr->field_offset;
unsigned int val;
int error;
@@ -479,7 +479,7 @@ static int edt_ft5x06_debugfs_mode_set(void *data, u64 mode)
if (mode != tsdata->factory_mode) {
retval = mode ? edt_ft5x06_factory_mode(tsdata) :
- edt_ft5x06_work_mode(tsdata);
+ edt_ft5x06_work_mode(tsdata);
}
mutex_unlock(&tsdata->mutex);
@@ -568,7 +568,6 @@ out:
return error ?: read;
};
-
static const struct file_operations debugfs_raw_data_fops = {
.open = simple_open,
.read = edt_ft5x06_debugfs_raw_data_read,
@@ -614,8 +613,6 @@ edt_ft5x06_ts_teardown_debugfs(struct edt_ft5x06_ts_data *tsdata)
#endif /* CONFIG_DEBUGFS */
-
-
static int edt_ft5x06_ts_reset(struct i2c_client *client,
int reset_pin)
{
@@ -852,8 +849,8 @@ static SIMPLE_DEV_PM_OPS(edt_ft5x06_ts_pm_ops,
edt_ft5x06_ts_suspend, edt_ft5x06_ts_resume);
static const struct i2c_device_id edt_ft5x06_ts_id[] = {
- { "edt-ft5x06", 0 },
- { }
+ { "edt-ft5x06", 0, },
+ { /* sentinel */ }
};
MODULE_DEVICE_TABLE(i2c, edt_ft5x06_ts_id);
--
1.7.10.4
^ permalink raw reply related
* [PATCHv6 2/5] Input: edt-ft5x06: Add DT support
From: Lothar Waßmann @ 2014-03-24 15:11 UTC (permalink / raw)
To: Dmitry Torokhov, Fugang Duan, Grant Likely, Henrik Rydberg,
Ian Campbell, Jingoo Han, Kumar Gala, Mark Rutland, Pawel Moll,
Rob Herring, Rob Landley, Sachin Kamat, devicetree, linux-doc,
linux-input, linux-kernel, Simon Budig, Lothar Waßmann,
Daniel Wagener
In-Reply-To: <1395673870-29435-1-git-send-email-LW@KARO-electronics.de>
Signed-off-by: Lothar Waßmann <LW@KARO-electronics.de>
---
.../bindings/input/touchscreen/edt-ft5x06.txt | 55 ++++++++
drivers/input/touchscreen/edt-ft5x06.c | 143 +++++++++++++++-----
2 files changed, 167 insertions(+), 31 deletions(-)
create mode 100644 Documentation/devicetree/bindings/input/touchscreen/edt-ft5x06.txt
diff --git a/Documentation/devicetree/bindings/input/touchscreen/edt-ft5x06.txt b/Documentation/devicetree/bindings/input/touchscreen/edt-ft5x06.txt
new file mode 100644
index 0000000..76db967
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/touchscreen/edt-ft5x06.txt
@@ -0,0 +1,55 @@
+FocalTech EDT-FT5x06 Polytouch driver
+=====================================
+
+There are 3 variants of the chip for various touch panel sizes
+FT5206GE1 2.8" .. 3.8"
+FT5306DE4 4.3" .. 7"
+FT5406EE8 7" .. 8.9"
+
+The software interface is identical for all those chips, so that
+currently there is no need for the driver to distinguish between the
+different chips. Nevertheless distinct compatible strings are used so
+that a distinction can be added if necessary without changing the DT
+bindings.
+
+
+Required properties:
+ - compatible: "edt,edt-ft5206"
+ or: "edt,edt-ft5306"
+ or: "edt,edt-ft5406"
+
+ - reg: I2C slave address of the chip (0x38)
+ - interrupt-parent: a phandle pointing to the interrupt controller
+ serving the interrupt for this chip
+ - interrupts: interrupt specification for the touchdetect
+ interrupt
+
+Optional properties:
+ - reset-gpios: GPIO specification for the RESET input
+ - wake-gpios: GPIO specification for the WAKE input
+
+ - pinctrl-names: should be "default"
+ - pinctrl-0: a phandle pointing to the pin settings for the
+ control gpios
+
+ - threshold: allows setting the "click"-threshold in the range
+ from 20 to 80.
+
+ - gain: allows setting the sensitivity in the range from 0 to
+ 31. Note that lower values indicate higher
+ sensitivity.
+
+ - offset: allows setting the edge compensation in the range from
+ 0 to 31.
+
+Example:
+ polytouch: edt-ft5x06@38 {
+ compatible = "edt,edt-ft5406", "edt,edt-ft5x06";
+ reg = <0x38>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&edt_ft5x06_pins>;
+ interrupt-parent = <&gpio2>;
+ interrupts = <5 0>;
+ reset-gpios = <&gpio2 6 1>;
+ wake-gpios = <&gpio4 9 0>;
+ };
diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c
index 155ab3b..04d0665 100644
--- a/drivers/input/touchscreen/edt-ft5x06.c
+++ b/drivers/input/touchscreen/edt-ft5x06.c
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2012 Simon Budig, <simon.budig@kernelconcepts.de>
+ * Lothar Waßmann <LW@KARO-electronics.de> (DT support)
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -33,6 +34,7 @@
#include <linux/debugfs.h>
#include <linux/slab.h>
#include <linux/gpio.h>
+#include <linux/of_gpio.h>
#include <linux/input/mt.h>
#include <linux/input/edt-ft5x06.h>
@@ -65,6 +67,10 @@ struct edt_ft5x06_ts_data {
u16 num_x;
u16 num_y;
+ int reset_pin;
+ int irq_pin;
+ int wake_pin;
+
#if defined(CONFIG_DEBUG_FS)
struct dentry *debug_dir;
u8 *raw_buffer;
@@ -614,24 +620,38 @@ edt_ft5x06_ts_teardown_debugfs(struct edt_ft5x06_ts_data *tsdata)
#endif /* CONFIG_DEBUGFS */
static int edt_ft5x06_ts_reset(struct i2c_client *client,
- int reset_pin)
+ struct edt_ft5x06_ts_data *tsdata)
{
int error;
- if (gpio_is_valid(reset_pin)) {
+ if (gpio_is_valid(tsdata->wake_pin)) {
+ error = devm_gpio_request_one(&client->dev,
+ tsdata->wake_pin, GPIOF_OUT_INIT_LOW,
+ "edt-ft5x06 wake");
+ if (error) {
+ dev_err(&client->dev,
+ "Failed to request GPIO %d as wake pin, error %d\n",
+ tsdata->wake_pin, error);
+ return error;
+ }
+
+ mdelay(5);
+ gpio_set_value(tsdata->wake_pin, 1);
+ }
+ if (gpio_is_valid(tsdata->reset_pin)) {
/* this pulls reset down, enabling the low active reset */
- error = devm_gpio_request_one(&client->dev, reset_pin,
- GPIOF_OUT_INIT_LOW,
- "edt-ft5x06 reset");
+ error = devm_gpio_request_one(&client->dev,
+ tsdata->reset_pin, GPIOF_OUT_INIT_LOW,
+ "edt-ft5x06 reset");
if (error) {
dev_err(&client->dev,
"Failed to request GPIO %d as reset pin, error %d\n",
- reset_pin, error);
+ tsdata->reset_pin, error);
return error;
}
mdelay(50);
- gpio_set_value(reset_pin, 1);
+ gpio_set_value(tsdata->reset_pin, 1);
mdelay(100);
}
@@ -672,6 +692,20 @@ static int edt_ft5x06_ts_identify(struct i2c_client *client,
pdata->name <= edt_ft5x06_attr_##name.limit_high) \
edt_ft5x06_register_write(tsdata, reg, pdata->name)
+#define EDT_GET_PROP(name, reg) { \
+ u32 val; \
+ if (of_property_read_u32(np, #name, &val) == 0) \
+ edt_ft5x06_register_write(tsdata, reg, val); \
+}
+
+static void edt_ft5x06_ts_get_dt_defaults(struct device_node *np,
+ struct edt_ft5x06_ts_data *tsdata)
+{
+ EDT_GET_PROP(threshold, WORK_REGISTER_THRESHOLD);
+ EDT_GET_PROP(gain, WORK_REGISTER_GAIN);
+ EDT_GET_PROP(offset, WORK_REGISTER_OFFSET);
+}
+
static void
edt_ft5x06_ts_get_defaults(struct edt_ft5x06_ts_data *tsdata,
const struct edt_ft5x06_platform_data *pdata)
@@ -699,6 +733,30 @@ edt_ft5x06_ts_get_parameters(struct edt_ft5x06_ts_data *tsdata)
tsdata->num_y = edt_ft5x06_register_read(tsdata, WORK_REGISTER_NUM_Y);
}
+#ifdef CONFIG_OF
+static int edt_ft5x06_i2c_ts_probe_dt(struct device *dev,
+ struct edt_ft5x06_ts_data *tsdata)
+{
+ struct device_node *np = dev->of_node;
+
+ /*
+ * irq_pin is not needed for DT setup.
+ * irq is associated via 'interrupts' property in DT
+ */
+ tsdata->irq_pin = -EINVAL;
+ tsdata->reset_pin = of_get_named_gpio(np, "reset-gpios", 0);
+ tsdata->wake_pin = of_get_named_gpio(np, "wake-gpios", 0);
+
+ return 0;
+}
+#else
+static inline int edt_ft5x06_i2c_ts_probe_dt(struct device *dev,
+ struct edt_ft5x06_i2c_ts_data *tsdata)
+{
+ return -ENODEV;
+}
+#endif
+
static int edt_ft5x06_ts_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -711,32 +769,40 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
dev_dbg(&client->dev, "probing for EDT FT5x06 I2C\n");
+ tsdata = devm_kzalloc(&client->dev, sizeof(*tsdata), GFP_KERNEL);
+ if (!tsdata) {
+ dev_err(&client->dev, "failed to allocate driver data.\n");
+ return -ENOMEM;
+ }
+
if (!pdata) {
- dev_err(&client->dev, "no platform data?\n");
- return -EINVAL;
+ error = edt_ft5x06_i2c_ts_probe_dt(&client->dev, tsdata);
+ if (error) {
+ dev_err(&client->dev,
+ "DT probe failed and no platform data present\n");
+ return error;
+ }
+ } else {
+ tsdata->reset_pin = pdata->reset_pin;
+ tsdata->irq_pin = pdata->irq_pin;
+ tsdata->wake_pin = -EINVAL;
}
- error = edt_ft5x06_ts_reset(client, pdata->reset_pin);
+ error = edt_ft5x06_ts_reset(client, tsdata);
if (error)
return error;
- if (gpio_is_valid(pdata->irq_pin)) {
- error = devm_gpio_request_one(&client->dev, pdata->irq_pin,
- GPIOF_IN, "edt-ft5x06 irq");
+ if (gpio_is_valid(tsdata->irq_pin)) {
+ error = devm_gpio_request_one(&client->dev, tsdata->irq_pin,
+ GPIOF_IN, "edt-ft5x06 irq");
if (error) {
dev_err(&client->dev,
"Failed to request GPIO %d, error %d\n",
- pdata->irq_pin, error);
+ tsdata->irq_pin, error);
return error;
}
}
- tsdata = devm_kzalloc(&client->dev, sizeof(*tsdata), GFP_KERNEL);
- if (!tsdata) {
- dev_err(&client->dev, "failed to allocate driver data.\n");
- return -ENOMEM;
- }
-
input = devm_input_allocate_device(&client->dev);
if (!input) {
dev_err(&client->dev, "failed to allocate input device.\n");
@@ -754,7 +820,11 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
return error;
}
- edt_ft5x06_ts_get_defaults(tsdata, pdata);
+ if (!pdata)
+ edt_ft5x06_ts_get_dt_defaults(client->dev.of_node, tsdata);
+ else
+ edt_ft5x06_ts_get_defaults(tsdata, pdata);
+
edt_ft5x06_ts_get_parameters(tsdata);
dev_dbg(&client->dev,
@@ -784,10 +854,10 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
input_set_drvdata(input, tsdata);
i2c_set_clientdata(client, tsdata);
- error = devm_request_threaded_irq(&client->dev, client->irq,
- NULL, edt_ft5x06_ts_isr,
- IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
- client->name, tsdata);
+ error = devm_request_threaded_irq(&client->dev, client->irq, NULL,
+ edt_ft5x06_ts_isr,
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ client->name, tsdata);
if (error) {
dev_err(&client->dev, "Unable to request touchscreen IRQ.\n");
return error;
@@ -798,19 +868,21 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
return error;
error = input_register_device(input);
- if (error) {
- sysfs_remove_group(&client->dev.kobj, &edt_ft5x06_attr_group);
- return error;
- }
+ if (error)
+ goto err_remove_attrs;
edt_ft5x06_ts_prepare_debugfs(tsdata, dev_driver_string(&client->dev));
device_init_wakeup(&client->dev, 1);
dev_dbg(&client->dev,
- "EDT FT5x06 initialized: IRQ pin %d, Reset pin %d.\n",
- pdata->irq_pin, pdata->reset_pin);
+ "EDT FT5x06 initialized: IRQ %d, WAKE pin %d, Reset pin %d.\n",
+ client->irq, tsdata->wake_pin, tsdata->reset_pin);
return 0;
+
+err_remove_attrs:
+ sysfs_remove_group(&client->dev.kobj, &edt_ft5x06_attr_group);
+ return error;
}
static int edt_ft5x06_ts_remove(struct i2c_client *client)
@@ -854,10 +926,19 @@ static const struct i2c_device_id edt_ft5x06_ts_id[] = {
};
MODULE_DEVICE_TABLE(i2c, edt_ft5x06_ts_id);
+static const struct of_device_id edt_ft5x06_of_match[] = {
+ { .compatible = "edt,edt-ft5206", },
+ { .compatible = "edt,edt-ft5306", },
+ { .compatible = "edt,edt-ft5406", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, edt_ft5x06_of_match);
+
static struct i2c_driver edt_ft5x06_ts_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "edt_ft5x06",
+ .of_match_table = edt_ft5x06_of_match,
.pm = &edt_ft5x06_ts_pm_ops,
},
.id_table = edt_ft5x06_ts_id,
--
1.7.10.4
^ permalink raw reply related
* [PATCHv6 3/5] Input: edt-ft5x06: Adjust delays to conform datasheet
From: Lothar Waßmann @ 2014-03-24 15:11 UTC (permalink / raw)
To: Dmitry Torokhov, Fugang Duan, Grant Likely, Henrik Rydberg,
Ian Campbell, Jingoo Han, Kumar Gala, Mark Rutland, Pawel Moll,
Rob Herring, Rob Landley, Sachin Kamat,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-doc-u79uwXL29TY76Z2rM5mHXA,
linux-input-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Simon Budig,
Lothar Waßmann, Daniel Wagener
In-Reply-To: <1395673870-29435-1-git-send-email-LW-bxm8fMRDkQLDiMYJYoSAnRvVK+yQ3ZXh@public.gmane.org>
The FT5x06 datasheet specifies a minimum reset width of 5ms and a
delay between deassertion of reset and start of reporting of 300ms.
Adjust the delays to conform to the datasheet.
With the original delays I sometimes experienced communication
timeouts when initializing the controller.
Signed-off-by: Lothar Waßmann <LW-bxm8fMRDkQLDiMYJYoSAnRvVK+yQ3ZXh@public.gmane.org>
---
drivers/input/touchscreen/edt-ft5x06.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c
index 04d0665..cc5185a 100644
--- a/drivers/input/touchscreen/edt-ft5x06.c
+++ b/drivers/input/touchscreen/edt-ft5x06.c
@@ -635,7 +635,7 @@ static int edt_ft5x06_ts_reset(struct i2c_client *client,
return error;
}
- mdelay(5);
+ msleep(5);
gpio_set_value(tsdata->wake_pin, 1);
}
if (gpio_is_valid(tsdata->reset_pin)) {
@@ -650,9 +650,9 @@ static int edt_ft5x06_ts_reset(struct i2c_client *client,
return error;
}
- mdelay(50);
+ msleep(5);
gpio_set_value(tsdata->reset_pin, 1);
- mdelay(100);
+ msleep(300);
}
return 0;
--
1.7.10.4
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [PATCHv6 5/5] Input: edt-ft5x06: Add support for M09 firmware version
From: Lothar Waßmann @ 2014-03-24 15:11 UTC (permalink / raw)
To: Dmitry Torokhov, Fugang Duan, Grant Likely, Henrik Rydberg,
Ian Campbell, Jingoo Han, Kumar Gala, Mark Rutland, Pawel Moll,
Rob Herring, Rob Landley, Sachin Kamat, devicetree, linux-doc,
linux-input, linux-kernel, Simon Budig, Lothar Waßmann,
Daniel Wagener
In-Reply-To: <1395673870-29435-1-git-send-email-LW@KARO-electronics.de>
There is a new firmware version for the EDT-FT5x06 chip.
Add support for detecting the firmware version and handle the
differences appropriately.
Signed-off-by: Lothar Waßmann <LW@KARO-electronics.de>
---
drivers/input/touchscreen/edt-ft5x06.c | 358 ++++++++++++++++++++++++--------
1 file changed, 276 insertions(+), 82 deletions(-)
diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c
index 964b6c2..7318654 100644
--- a/drivers/input/touchscreen/edt-ft5x06.c
+++ b/drivers/input/touchscreen/edt-ft5x06.c
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2012 Simon Budig, <simon.budig@kernelconcepts.de>
+ * Daniel Wagener <daniel.wagener@kernelconcepts.de> (M09 firmware support)
* Lothar Waßmann <LW@KARO-electronics.de> (DT support)
*
* This software is licensed under the terms of the GNU General Public
@@ -47,6 +48,14 @@
#define WORK_REGISTER_NUM_X 0x33
#define WORK_REGISTER_NUM_Y 0x34
+#define M09_REGISTER_THRESHOLD 0x80
+#define M09_REGISTER_GAIN 0x92
+#define M09_REGISTER_OFFSET 0x93
+#define M09_REGISTER_NUM_X 0x94
+#define M09_REGISTER_NUM_Y 0x95
+
+#define NO_REGISTER 0xff
+
#define WORK_REGISTER_OPMODE 0x3c
#define FACTORY_REGISTER_OPMODE 0x01
@@ -61,6 +70,20 @@
#define EDT_RAW_DATA_RETRIES 100
#define EDT_RAW_DATA_DELAY 1 /* msec */
+enum edt_ver {
+ M06,
+ M09,
+};
+
+struct edt_reg_addr {
+ int reg_threshold;
+ int reg_report_rate;
+ int reg_gain;
+ int reg_offset;
+ int reg_num_x;
+ int reg_num_y;
+};
+
struct edt_ft5x06_ts_data {
struct i2c_client *client;
struct input_dev *input;
@@ -85,6 +108,9 @@ struct edt_ft5x06_ts_data {
int report_rate;
char name[EDT_NAME_LEN];
+
+ struct edt_reg_addr reg_addr;
+ enum edt_ver version;
};
static int edt_ft5x06_ts_readwrite(struct i2c_client *client,
@@ -142,33 +168,58 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id)
{
struct edt_ft5x06_ts_data *tsdata = dev_id;
struct device *dev = &tsdata->client->dev;
- u8 cmd = 0xf9;
- u8 rdbuf[26];
+ u8 cmd;
+ u8 rdbuf[29];
int i, type, x, y, id;
+ int offset, tplen, datalen;
int error;
+ switch (tsdata->version) {
+ case M06:
+ cmd = 0xf9; /* tell the controller to send touch data */
+ offset = 5; /* where the actual touch data starts */
+ tplen = 4; /* data comes in so called frames */
+ datalen = 26; /* how much bytes to listen for */
+ break;
+
+ case M09:
+ cmd = 0x02;
+ offset = 1;
+ tplen = 6;
+ datalen = 29;
+ break;
+
+ default:
+ goto out;
+ }
+
memset(rdbuf, 0, sizeof(rdbuf));
error = edt_ft5x06_ts_readwrite(tsdata->client,
sizeof(cmd), &cmd,
- sizeof(rdbuf), rdbuf);
+ datalen, rdbuf);
if (error) {
dev_err_ratelimited(dev, "Unable to fetch data, error: %d\n",
error);
goto out;
}
- if (rdbuf[0] != 0xaa || rdbuf[1] != 0xaa || rdbuf[2] != 26) {
- dev_err_ratelimited(dev, "Unexpected header: %02x%02x%02x!\n",
- rdbuf[0], rdbuf[1], rdbuf[2]);
- goto out;
- }
+ /* M09 does not send header or CRC */
+ if (tsdata->version == M06) {
+ if (rdbuf[0] != 0xaa || rdbuf[1] != 0xaa ||
+ rdbuf[2] != datalen) {
+ dev_err_ratelimited(dev,
+ "Unexpected header: %02x%02x%02x!\n",
+ rdbuf[0], rdbuf[1], rdbuf[2]);
+ goto out;
+ }
- if (!edt_ft5x06_ts_check_crc(tsdata, rdbuf, 26))
- goto out;
+ if (!edt_ft5x06_ts_check_crc(tsdata, rdbuf, datalen))
+ goto out;
+ }
for (i = 0; i < MAX_SUPPORT_POINTS; i++) {
- u8 *buf = &rdbuf[i * 4 + 5];
+ u8 *buf = &rdbuf[i * tplen + offset];
bool down;
type = buf[0] >> 6;
@@ -176,8 +227,8 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id)
if (type == TOUCH_EVENT_RESERVED)
continue;
- /* ignore TOUCH_DOWN events, might have bogus coordinates */
- if (type == TOUCH_EVENT_DOWN)
+ /* M06 sometimes sends bogus coordinates in TOUCH_DOWN */
+ if (tsdata->version == M06 && type == TOUCH_EVENT_DOWN)
continue;
x = ((buf[0] << 8) | buf[1]) & 0x0fff;
@@ -207,12 +258,25 @@ static int edt_ft5x06_register_write(struct edt_ft5x06_ts_data *tsdata,
{
u8 wrbuf[4];
- wrbuf[0] = tsdata->factory_mode ? 0xf3 : 0xfc;
- wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f;
- wrbuf[2] = value;
- wrbuf[3] = wrbuf[0] ^ wrbuf[1] ^ wrbuf[2];
-
- return edt_ft5x06_ts_readwrite(tsdata->client, 4, wrbuf, 0, NULL);
+ switch (tsdata->version) {
+ case M06:
+ wrbuf[0] = tsdata->factory_mode ? 0xf3 : 0xfc;
+ wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f;
+ wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f;
+ wrbuf[2] = value;
+ wrbuf[3] = wrbuf[0] ^ wrbuf[1] ^ wrbuf[2];
+ return edt_ft5x06_ts_readwrite(tsdata->client, 4,
+ wrbuf, 0, NULL);
+ case M09:
+ wrbuf[0] = addr;
+ wrbuf[1] = value;
+
+ return edt_ft5x06_ts_readwrite(tsdata->client, 3,
+ wrbuf, 0, NULL);
+
+ default:
+ return -EINVAL;
+ }
}
static int edt_ft5x06_register_read(struct edt_ft5x06_ts_data *tsdata,
@@ -221,19 +285,35 @@ static int edt_ft5x06_register_read(struct edt_ft5x06_ts_data *tsdata,
u8 wrbuf[2], rdbuf[2];
int error;
- wrbuf[0] = tsdata->factory_mode ? 0xf3 : 0xfc;
- wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f;
- wrbuf[1] |= tsdata->factory_mode ? 0x80 : 0x40;
+ switch (tsdata->version) {
+ case M06:
+ wrbuf[0] = tsdata->factory_mode ? 0xf3 : 0xfc;
+ wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f;
+ wrbuf[1] |= tsdata->factory_mode ? 0x80 : 0x40;
- error = edt_ft5x06_ts_readwrite(tsdata->client, 2, wrbuf, 2, rdbuf);
- if (error)
+ error = edt_ft5x06_ts_readwrite(tsdata->client,
+ 2, wrbuf, 2, rdbuf);
return error;
- if ((wrbuf[0] ^ wrbuf[1] ^ rdbuf[0]) != rdbuf[1]) {
- dev_err(&tsdata->client->dev,
- "crc error: 0x%02x expected, got 0x%02x\n",
- wrbuf[0] ^ wrbuf[1] ^ rdbuf[0], rdbuf[1]);
- return -EIO;
+ if ((wrbuf[0] ^ wrbuf[1] ^ rdbuf[0]) != rdbuf[1]) {
+ dev_err(&tsdata->client->dev,
+ "crc error: 0x%02x expected, got 0x%02x\n",
+ wrbuf[0] ^ wrbuf[1] ^ rdbuf[0],
+ rdbuf[1]);
+ return -EIO;
+ }
+ break;
+
+ case M09:
+ wrbuf[0] = addr;
+ error = edt_ft5x06_ts_readwrite(tsdata->client, 1,
+ wrbuf, 1, rdbuf);
+ if (error)
+ return error;
+ break;
+
+ default:
+ return -EINVAL;
}
return rdbuf[0];
@@ -244,19 +324,21 @@ struct edt_ft5x06_attribute {
size_t field_offset;
u8 limit_low;
u8 limit_high;
- u8 addr;
+ u8 addr_m06;
+ u8 addr_m09;
};
-#define EDT_ATTR(_field, _mode, _addr, _limit_low, _limit_high) \
+#define EDT_ATTR(_field, _mode, _addr_m06, _addr_m09, \
+ _limit_low, _limit_high) \
struct edt_ft5x06_attribute edt_ft5x06_attr_##_field = { \
.dattr = __ATTR(_field, _mode, \
edt_ft5x06_setting_show, \
edt_ft5x06_setting_store), \
- .field_offset = \
- offsetof(struct edt_ft5x06_ts_data, _field), \
+ .field_offset = offsetof(struct edt_ft5x06_ts_data, _field), \
+ .addr_m06 = _addr_m06, \
+ .addr_m09 = _addr_m09, \
.limit_low = _limit_low, \
.limit_high = _limit_high, \
- .addr = _addr, \
}
static ssize_t edt_ft5x06_setting_show(struct device *dev,
@@ -271,6 +353,7 @@ static ssize_t edt_ft5x06_setting_show(struct device *dev,
int val;
size_t count = 0;
int error = 0;
+ u8 addr;
mutex_lock(&tsdata->mutex);
@@ -279,15 +362,33 @@ static ssize_t edt_ft5x06_setting_show(struct device *dev,
goto out;
}
- val = edt_ft5x06_register_read(tsdata, attr->addr);
- if (val < 0) {
- error = val;
- dev_err(&tsdata->client->dev,
- "Failed to fetch attribute %s, error %d\n",
- dattr->attr.name, error);
+ switch (tsdata->version) {
+ case M06:
+ addr = attr->addr_m06;
+ break;
+
+ case M09:
+ addr = attr->addr_m09;
+ break;
+
+ default:
+ error = -ENODEV;
goto out;
}
+ if (addr != NO_REGISTER) {
+ val = edt_ft5x06_register_read(tsdata, addr);
+ if (val < 0) {
+ error = val;
+ dev_err(&tsdata->client->dev,
+ "Failed to fetch attribute %s, error %d\n",
+ dattr->attr.name, error);
+ goto out;
+ }
+ } else {
+ val = *field;
+ }
+
if (val != *field) {
dev_warn(&tsdata->client->dev,
"%s: read (%d) and stored value (%d) differ\n",
@@ -312,6 +413,7 @@ static ssize_t edt_ft5x06_setting_store(struct device *dev,
u8 *field = (u8 *)tsdata + attr->field_offset;
unsigned int val;
int error;
+ u8 addr;
mutex_lock(&tsdata->mutex);
@@ -329,14 +431,29 @@ static ssize_t edt_ft5x06_setting_store(struct device *dev,
goto out;
}
- error = edt_ft5x06_register_write(tsdata, attr->addr, val);
- if (error) {
- dev_err(&tsdata->client->dev,
- "Failed to update attribute %s, error: %d\n",
- dattr->attr.name, error);
+ switch (tsdata->version) {
+ case M06:
+ addr = attr->addr_m06;
+ break;
+
+ case M09:
+ addr = attr->addr_m09;
+ break;
+
+ default:
+ error = -ENODEV;
goto out;
}
+ if (addr != NO_REGISTER) {
+ error = edt_ft5x06_register_write(tsdata, addr, val);
+ if (error) {
+ dev_err(&tsdata->client->dev,
+ "Failed to update attribute %s, error: %d\n",
+ dattr->attr.name, error);
+ goto out;
+ }
+ }
*field = val;
out:
@@ -344,12 +461,14 @@ out:
return error ?: count;
}
-static EDT_ATTR(gain, S_IWUSR | S_IRUGO, WORK_REGISTER_GAIN, 0, 31);
-static EDT_ATTR(offset, S_IWUSR | S_IRUGO, WORK_REGISTER_OFFSET, 0, 31);
-static EDT_ATTR(threshold, S_IWUSR | S_IRUGO,
- WORK_REGISTER_THRESHOLD, 20, 80);
-static EDT_ATTR(report_rate, S_IWUSR | S_IRUGO,
- WORK_REGISTER_REPORT_RATE, 3, 14);
+static EDT_ATTR(gain, S_IWUSR | S_IRUGO, WORK_REGISTER_GAIN,
+ M09_REGISTER_GAIN, 0, 31);
+static EDT_ATTR(offset, S_IWUSR | S_IRUGO, WORK_REGISTER_OFFSET,
+ M09_REGISTER_OFFSET, 0, 31);
+static EDT_ATTR(threshold, S_IWUSR | S_IRUGO, WORK_REGISTER_THRESHOLD,
+ M09_REGISTER_THRESHOLD, 20, 80);
+static EDT_ATTR(report_rate, S_IWUSR | S_IRUGO, WORK_REGISTER_REPORT_RATE,
+ NO_REGISTER, 3, 14);
static struct attribute *edt_ft5x06_attrs[] = {
&edt_ft5x06_attr_gain.dattr.attr,
@@ -384,6 +503,9 @@ static int edt_ft5x06_factory_mode(struct edt_ft5x06_ts_data *tsdata)
}
/* mode register is 0x3c when in the work mode */
+ if (tsdata->version == M09)
+ goto m09_out;
+
error = edt_ft5x06_register_write(tsdata, WORK_REGISTER_OPMODE, 0x03);
if (error) {
dev_err(&client->dev,
@@ -416,12 +538,18 @@ err_out:
enable_irq(client->irq);
return error;
+
+m09_out:
+ dev_err(&client->dev, "No factory mode support for M09\n");
+ return -EINVAL;
+
}
static int edt_ft5x06_work_mode(struct edt_ft5x06_ts_data *tsdata)
{
struct i2c_client *client = tsdata->client;
int retries = EDT_SWITCH_MODE_RETRIES;
+ struct edt_reg_addr *reg_addr = &tsdata->reg_addr;
int ret;
int error;
@@ -454,13 +582,14 @@ static int edt_ft5x06_work_mode(struct edt_ft5x06_ts_data *tsdata)
tsdata->raw_buffer = NULL;
/* restore parameters */
- edt_ft5x06_register_write(tsdata, WORK_REGISTER_THRESHOLD,
+ edt_ft5x06_register_write(tsdata, reg_addr->reg_threshold,
tsdata->threshold);
- edt_ft5x06_register_write(tsdata, WORK_REGISTER_GAIN,
+ edt_ft5x06_register_write(tsdata, reg_addr->reg_gain,
tsdata->gain);
- edt_ft5x06_register_write(tsdata, WORK_REGISTER_OFFSET,
+ edt_ft5x06_register_write(tsdata, reg_addr->reg_offset,
tsdata->offset);
- edt_ft5x06_register_write(tsdata, WORK_REGISTER_REPORT_RATE,
+ if (reg_addr->reg_report_rate)
+ edt_ft5x06_register_write(tsdata, reg_addr->reg_report_rate,
tsdata->report_rate);
enable_irq(client->irq);
@@ -663,30 +792,60 @@ static int edt_ft5x06_ts_reset(struct i2c_client *client,
}
static int edt_ft5x06_ts_identify(struct i2c_client *client,
- char *model_name,
- char *fw_version)
+ struct edt_ft5x06_ts_data *tsdata,
+ char *fw_version)
{
u8 rdbuf[EDT_NAME_LEN];
char *p;
int error;
+ char *model_name = tsdata->name;
+ /* see what we find if we assume it is a M06 *
+ * if we get less than EDT_NAME_LEN, we don't want
+ * to have garbage in there
+ */
+ memset(rdbuf, 0, sizeof(rdbuf));
error = edt_ft5x06_ts_readwrite(client, 1, "\xbb",
EDT_NAME_LEN - 1, rdbuf);
if (error)
return error;
- /* remove last '$' end marker */
- rdbuf[EDT_NAME_LEN - 1] = '\0';
- if (rdbuf[EDT_NAME_LEN - 2] == '$')
- rdbuf[EDT_NAME_LEN - 2] = '\0';
+ /* if we find something consistent, stay with that assumption
+ * at least M09 won't send 3 bytes here
+ */
+ if (!(strnicmp(rdbuf + 1, "EP0", 3))) {
+ tsdata->version = M06;
+
+ /* remove last '$' end marker */
+ rdbuf[EDT_NAME_LEN - 1] = '\0';
+ if (rdbuf[EDT_NAME_LEN - 2] == '$')
+ rdbuf[EDT_NAME_LEN - 2] = '\0';
+
+ /* look for Model/Version separator */
+ p = strchr(rdbuf, '*');
+ if (p)
+ *p++ = '\0';
+ strlcpy(model_name, rdbuf + 1, EDT_NAME_LEN);
+ strlcpy(fw_version, p ? p : "", EDT_NAME_LEN);
+ } else {
+ /* since there are only two versions around (M06, M09) */
+ tsdata->version = M09;
+
+ error = edt_ft5x06_ts_readwrite(client, 1, "\xA6",
+ 2, rdbuf);
+ if (error)
+ return error;
- /* look for Model/Version separator */
- p = strchr(rdbuf, '*');
- if (p)
- *p++ = '\0';
+ strlcpy(fw_version, rdbuf, 2);
- strlcpy(model_name, rdbuf + 1, EDT_NAME_LEN);
- strlcpy(fw_version, p ? p : "", EDT_NAME_LEN);
+ error = edt_ft5x06_ts_readwrite(client, 1, "\xA8",
+ 1, rdbuf);
+ if (error)
+ return error;
+
+ snprintf(model_name, EDT_NAME_LEN, "EP0%i%i0M09",
+ rdbuf[0] >> 4, rdbuf[0] & 0x0F);
+ }
return 0;
}
@@ -705,36 +864,69 @@ static int edt_ft5x06_ts_identify(struct i2c_client *client,
static void edt_ft5x06_ts_get_dt_defaults(struct device_node *np,
struct edt_ft5x06_ts_data *tsdata)
{
- EDT_GET_PROP(threshold, WORK_REGISTER_THRESHOLD);
- EDT_GET_PROP(gain, WORK_REGISTER_GAIN);
- EDT_GET_PROP(offset, WORK_REGISTER_OFFSET);
+ struct edt_reg_addr *reg_addr = &tsdata->reg_addr;
+
+ EDT_GET_PROP(threshold, reg_addr->reg_threshold);
+ EDT_GET_PROP(gain, reg_addr->reg_gain);
+ EDT_GET_PROP(offset, reg_addr->reg_offset);
}
static void
edt_ft5x06_ts_get_defaults(struct edt_ft5x06_ts_data *tsdata,
const struct edt_ft5x06_platform_data *pdata)
{
+ struct edt_reg_addr *reg_addr = &tsdata->reg_addr;
+
if (!pdata->use_parameters)
return;
/* pick up defaults from the platform data */
- EDT_ATTR_CHECKSET(threshold, WORK_REGISTER_THRESHOLD);
- EDT_ATTR_CHECKSET(gain, WORK_REGISTER_GAIN);
- EDT_ATTR_CHECKSET(offset, WORK_REGISTER_OFFSET);
- EDT_ATTR_CHECKSET(report_rate, WORK_REGISTER_REPORT_RATE);
+ EDT_ATTR_CHECKSET(threshold, reg_addr->reg_threshold);
+ EDT_ATTR_CHECKSET(gain, reg_addr->reg_gain);
+ EDT_ATTR_CHECKSET(offset, reg_addr->reg_offset);
+ if (reg_addr->reg_report_rate != NO_REGISTER)
+ EDT_ATTR_CHECKSET(report_rate, reg_addr->reg_report_rate);
}
static void
edt_ft5x06_ts_get_parameters(struct edt_ft5x06_ts_data *tsdata)
{
+ struct edt_reg_addr *reg_addr = &tsdata->reg_addr;
+
tsdata->threshold = edt_ft5x06_register_read(tsdata,
- WORK_REGISTER_THRESHOLD);
- tsdata->gain = edt_ft5x06_register_read(tsdata, WORK_REGISTER_GAIN);
- tsdata->offset = edt_ft5x06_register_read(tsdata, WORK_REGISTER_OFFSET);
- tsdata->report_rate = edt_ft5x06_register_read(tsdata,
- WORK_REGISTER_REPORT_RATE);
- tsdata->num_x = edt_ft5x06_register_read(tsdata, WORK_REGISTER_NUM_X);
- tsdata->num_y = edt_ft5x06_register_read(tsdata, WORK_REGISTER_NUM_Y);
+ reg_addr->reg_threshold);
+ tsdata->gain = edt_ft5x06_register_read(tsdata, reg_addr->reg_gain);
+ tsdata->offset = edt_ft5x06_register_read(tsdata, reg_addr->reg_offset);
+ if (reg_addr->reg_report_rate != NO_REGISTER)
+ tsdata->report_rate = edt_ft5x06_register_read(tsdata,
+ reg_addr->reg_report_rate);
+ tsdata->num_x = edt_ft5x06_register_read(tsdata, reg_addr->reg_num_x);
+ tsdata->num_y = edt_ft5x06_register_read(tsdata, reg_addr->reg_num_y);
+}
+
+static void
+edt_ft5x06_ts_set_regs(struct edt_ft5x06_ts_data *tsdata)
+{
+ struct edt_reg_addr *reg_addr = &tsdata->reg_addr;
+
+ switch (tsdata->version) {
+ case M06:
+ reg_addr->reg_threshold = WORK_REGISTER_THRESHOLD;
+ reg_addr->reg_report_rate = WORK_REGISTER_REPORT_RATE;
+ reg_addr->reg_gain = WORK_REGISTER_GAIN;
+ reg_addr->reg_offset = WORK_REGISTER_OFFSET;
+ reg_addr->reg_num_x = WORK_REGISTER_NUM_X;
+ reg_addr->reg_num_y = WORK_REGISTER_NUM_Y;
+ break;
+
+ case M09:
+ reg_addr->reg_threshold = M09_REGISTER_THRESHOLD;
+ reg_addr->reg_gain = M09_REGISTER_GAIN;
+ reg_addr->reg_offset = M09_REGISTER_OFFSET;
+ reg_addr->reg_num_x = M09_REGISTER_NUM_X;
+ reg_addr->reg_num_y = M09_REGISTER_NUM_Y;
+ break;
+ }
}
#ifdef CONFIG_OF
@@ -818,12 +1010,14 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
tsdata->input = input;
tsdata->factory_mode = false;
- error = edt_ft5x06_ts_identify(client, tsdata->name, fw_version);
+ error = edt_ft5x06_ts_identify(client, tsdata, fw_version);
if (error) {
dev_err(&client->dev, "touchscreen probe failed\n");
return error;
}
+ edt_ft5x06_ts_set_regs(tsdata);
+
if (!pdata)
edt_ft5x06_ts_get_dt_defaults(client->dev.of_node, tsdata);
else
--
1.7.10.4
^ permalink raw reply related
* [PATCHv6 4/5] Input: edt-ft5x06: Ignore touchdown events
From: Lothar Waßmann @ 2014-03-24 15:11 UTC (permalink / raw)
To: Dmitry Torokhov, Fugang Duan, Grant Likely, Henrik Rydberg,
Ian Campbell, Jingoo Han, Kumar Gala, Mark Rutland, Pawel Moll,
Rob Herring, Rob Landley, Sachin Kamat, devicetree, linux-doc,
linux-input, linux-kernel, Simon Budig, Lothar Waßmann,
Daniel Wagener
In-Reply-To: <1395673870-29435-1-git-send-email-LW@KARO-electronics.de>
The chip may report invalid coordinates on touchdown events, so don't
report the initial touchdown event.
Signed-off-by: Lothar Waßmann <LW@KARO-electronics.de>
---
drivers/input/touchscreen/edt-ft5x06.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c
index cc5185a..964b6c2 100644
--- a/drivers/input/touchscreen/edt-ft5x06.c
+++ b/drivers/input/touchscreen/edt-ft5x06.c
@@ -176,6 +176,10 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id)
if (type == TOUCH_EVENT_RESERVED)
continue;
+ /* ignore TOUCH_DOWN events, might have bogus coordinates */
+ if (type == TOUCH_EVENT_DOWN)
+ continue;
+
x = ((buf[0] << 8) | buf[1]) & 0x0fff;
y = ((buf[2] << 8) | buf[3]) & 0x0fff;
id = (buf[2] >> 4) & 0x0f;
--
1.7.10.4
--
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
* Re: [PATCH] HID: uhid: Add UHID_CREATE2 + UHID_INPUT2
From: Petri Gynther @ 2014-03-24 19:04 UTC (permalink / raw)
To: David Herrmann; +Cc: open list:HID CORE LAYER, Jiri Kosina
In-Reply-To: <CANq1E4SKtB3+pQas9NVE93yVJAArc=LB1r2ojTgE=33YzRnDiw@mail.gmail.com>
Hi David and Jiri,
On Sun, Mar 23, 2014 at 7:22 AM, David Herrmann <dh.herrmann@gmail.com> wrote:
> Hi
>
> On Wed, Mar 19, 2014 at 4:45 AM, Petri Gynther <pgynther@google.com> wrote:
>> UHID_CREATE2:
>> HID report descriptor data (rd_data) is an array in struct uhid_create2_req,
>> instead of a pointer. Enables use from languages that don't support pointers,
>> e.g. Python.
>
> ..and this also makes the x32-COMPAT crap obsolete.
>
>>
>> UHID_INPUT2:
>> Data array is the last field of struct uhid_input2_req. Enables userspace to
>> write only the required bytes to kernel (ev.type + ev.u.input2.size + the part
>> of the data array that matters), instead of the entire struct uhid_input2_req.
>
> We should have swapped these fields right from the beginning. We
> explicitly support truncated input, but I only ever tested that with
> output, not input.. Thanks for fixing that!
>
>> Signed-off-by: Petri Gynther <pgynther@google.com>
>> ---
>> Documentation/hid/uhid.txt | 11 +++++++
>> drivers/hid/uhid.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++
>> include/uapi/linux/uhid.h | 23 +++++++++++++
>> 3 files changed, 114 insertions(+)
>>
>> diff --git a/Documentation/hid/uhid.txt b/Documentation/hid/uhid.txt
>> index dc35a2b..ee65936 100644
>> --- a/Documentation/hid/uhid.txt
>> +++ b/Documentation/hid/uhid.txt
>> @@ -93,6 +93,11 @@ the request was handled successfully.
>> event to the kernel. The payload is of type struct uhid_create_req and
>> contains information about your device. You can start I/O now.
>>
>> + UHID_CREATE2:
>> + Same as UHID_CREATE, but the HID report descriptor data (rd_data) is an array
>> + inside struct uhid_create2_req, instead of a pointer to a separate array.
>> + Enables use from languages that don't support pointers, e.g. Python.
>> +
>> UHID_DESTROY:
>> This destroys the internal HID device. No further I/O will be accepted. There
>> may still be pending messages that you can receive with read() but no further
>> @@ -105,6 +110,12 @@ the request was handled successfully.
>> contains a data-payload. This is the raw data that you read from your device.
>> The kernel will parse the HID reports and react on it.
>>
>> + UHID_INPUT2:
>> + Same as UHID_INPUT, but the data array is the last field of uhid_input2_req.
>> + Enables userspace to write only the required bytes to kernel (ev.type +
>> + ev.u.input2.size + the part of the data array that matters), instead of
>> + the entire struct uhid_input2_req.
>> +
>> UHID_FEATURE_ANSWER:
>> If you receive a UHID_FEATURE request you must answer with this request. You
>> must copy the "id" field from the request into the answer. Set the "err" field
>> diff --git a/drivers/hid/uhid.c b/drivers/hid/uhid.c
>> index cedc6da..c5ee173 100644
>> --- a/drivers/hid/uhid.c
>> +++ b/drivers/hid/uhid.c
>> @@ -407,6 +407,69 @@ err_free:
>> return ret;
>> }
>>
>> +static int uhid_dev_create2(struct uhid_device *uhid,
>> + const struct uhid_event *ev)
>> +{
>> + struct hid_device *hid;
>> + int ret;
>> +
>> + if (uhid->running)
>> + return -EALREADY;
>> +
>> + uhid->rd_size = ev->u.create2.rd_size;
>> + if (uhid->rd_size <= 0 || uhid->rd_size > HID_MAX_DESCRIPTOR_SIZE)
>> + return -EINVAL;
>> +
>> + uhid->rd_data = kmalloc(uhid->rd_size, GFP_KERNEL);
>> + if (!uhid->rd_data)
>> + return -ENOMEM;
>> +
>> + memcpy(uhid->rd_data, ev->u.create2.rd_data, uhid->rd_size);
>
> Why don't we just use uhid_dev_create() and do this:
>
> if (ev->type == UHID_CREATE) {
> ...copy_from_user()...
> } else if (ev->type == UHID_CREATE2) {
> memcpy(...);
> }
This won't be enough. For UHID_CREATE, we need to use
ev->u.create.<member> and for UHID_CREATE2, ev->u.create2.<member>.
But, I'll collect those in local variables up front, so we can have
just one handler function. I'll send the revised diff shortly.
-- Petri
>
> This way we can avoid copying this whole function.
>
>> +
>> + hid = hid_allocate_device();
>> + if (IS_ERR(hid)) {
>> + ret = PTR_ERR(hid);
>> + goto err_free;
>> + }
>> +
>> + strncpy(hid->name, ev->u.create2.name, 127);
>> + hid->name[127] = 0;
>> + strncpy(hid->phys, ev->u.create2.phys, 63);
>> + hid->phys[63] = 0;
>> + strncpy(hid->uniq, ev->u.create2.uniq, 63);
>> + hid->uniq[63] = 0;
>> +
>> + hid->ll_driver = &uhid_hid_driver;
>> + hid->hid_get_raw_report = uhid_hid_get_raw;
>> + hid->hid_output_raw_report = uhid_hid_output_raw;
>> + hid->bus = ev->u.create2.bus;
>> + hid->vendor = ev->u.create2.vendor;
>> + hid->product = ev->u.create2.product;
>> + hid->version = ev->u.create2.version;
>> + hid->country = ev->u.create2.country;
>> + hid->driver_data = uhid;
>> + hid->dev.parent = uhid_misc.this_device;
>> +
>> + uhid->hid = hid;
>> + uhid->running = true;
>> +
>> + ret = hid_add_device(hid);
>> + if (ret) {
>> + hid_err(hid, "Cannot register HID device\n");
>> + goto err_hid;
>> + }
>> +
>> + return 0;
>> +
>> +err_hid:
>> + hid_destroy_device(hid);
>> + uhid->hid = NULL;
>> + uhid->running = false;
>> +err_free:
>> + kfree(uhid->rd_data);
>> + return ret;
>> +}
>> +
>> static int uhid_dev_destroy(struct uhid_device *uhid)
>> {
>> if (!uhid->running)
>> @@ -435,6 +498,17 @@ static int uhid_dev_input(struct uhid_device *uhid, struct uhid_event *ev)
>> return 0;
>> }
>>
>> +static int uhid_dev_input2(struct uhid_device *uhid, struct uhid_event *ev)
>> +{
>> + if (!uhid->running)
>> + return -EINVAL;
>> +
>> + hid_input_report(uhid->hid, HID_INPUT_REPORT, ev->u.input2.data,
>> + min_t(size_t, ev->u.input2.size, UHID_DATA_MAX), 0);
>> +
>> + return 0;
>> +}
>> +
>> static int uhid_dev_feature_answer(struct uhid_device *uhid,
>> struct uhid_event *ev)
>> {
>> @@ -571,12 +645,18 @@ static ssize_t uhid_char_write(struct file *file, const char __user *buffer,
>> case UHID_CREATE:
>> ret = uhid_dev_create(uhid, &uhid->input_buf);
>> break;
>> + case UHID_CREATE2:
>> + ret = uhid_dev_create2(uhid, &uhid->input_buf);
>> + break;
>> case UHID_DESTROY:
>> ret = uhid_dev_destroy(uhid);
>> break;
>> case UHID_INPUT:
>> ret = uhid_dev_input(uhid, &uhid->input_buf);
>> break;
>> + case UHID_INPUT2:
>> + ret = uhid_dev_input2(uhid, &uhid->input_buf);
>> + break;
>> case UHID_FEATURE_ANSWER:
>> ret = uhid_dev_feature_answer(uhid, &uhid->input_buf);
>> break;
>> diff --git a/include/uapi/linux/uhid.h b/include/uapi/linux/uhid.h
>> index 414b74b..1e3b09c 100644
>> --- a/include/uapi/linux/uhid.h
>> +++ b/include/uapi/linux/uhid.h
>> @@ -21,6 +21,7 @@
>>
>> #include <linux/input.h>
>> #include <linux/types.h>
>> +#include <linux/hid.h>
>>
>> enum uhid_event_type {
>> UHID_CREATE,
>> @@ -34,6 +35,8 @@ enum uhid_event_type {
>> UHID_INPUT,
>> UHID_FEATURE,
>> UHID_FEATURE_ANSWER,
>> + UHID_CREATE2,
>> + UHID_INPUT2,
>> };
>>
>> struct uhid_create_req {
>> @@ -50,6 +53,19 @@ struct uhid_create_req {
>> __u32 country;
>> } __attribute__((__packed__));
>>
>> +struct uhid_create2_req {
>> + __u8 name[128];
>> + __u8 phys[64];
>> + __u8 uniq[64];
>> + __u16 rd_size;
>> + __u16 bus;
>> + __u32 vendor;
>> + __u32 product;
>> + __u32 version;
>> + __u32 country;
>> + __u8 rd_data[HID_MAX_DESCRIPTOR_SIZE];
>> +} __attribute__((__packed__));
>> +
>> #define UHID_DATA_MAX 4096
>>
>> enum uhid_report_type {
>> @@ -63,6 +79,11 @@ struct uhid_input_req {
>> __u16 size;
>> } __attribute__((__packed__));
>>
>> +struct uhid_input2_req {
>> + __u16 size;
>> + __u8 data[UHID_DATA_MAX];
>> +} __attribute__((__packed__));
>> +
>> struct uhid_output_req {
>> __u8 data[UHID_DATA_MAX];
>> __u16 size;
>> @@ -100,6 +121,8 @@ struct uhid_event {
>> struct uhid_output_ev_req output_ev;
>> struct uhid_feature_req feature;
>> struct uhid_feature_answer_req feature_answer;
>> + struct uhid_create2_req create2;
>> + struct uhid_input2_req input2;
>
> We change the size of uhid_output_req here, but I think that is fine.
> But you might wanna note that down in the commit-message.
>
> Patch looks fine. If you fix the minor issues, this is:
> Reviewed-by: David Herrmann <dh.herrmann@gmail.com>
>
> And please always put Jiri on CC for all HID patches: "Jiri Kosina
> <jkosina@suse.cz>"
>
> Thanks
> David
>
>> } u;
>> } __attribute__((__packed__));
>>
>> --
>> 1.9.0.279.gdc9e3eb
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-input" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH] HID: uhid: Add UHID_CREATE2 + UHID_INPUT2
From: David Herrmann @ 2014-03-24 19:07 UTC (permalink / raw)
To: Petri Gynther; +Cc: open list:HID CORE LAYER, Jiri Kosina
In-Reply-To: <CAGXr9JHyR30ZkwnqMvJeSNGurUHFAAsbw7WB85TyaoSjgjrr8Q@mail.gmail.com>
Hi
On Mon, Mar 24, 2014 at 8:04 PM, Petri Gynther <pgynther@google.com> wrote:
> This won't be enough. For UHID_CREATE, we need to use
> ev->u.create.<member> and for UHID_CREATE2, ev->u.create2.<member>.
> But, I'll collect those in local variables up front, so we can have
> just one handler function. I'll send the revised diff shortly.
Oh right, In that case I think we can keep the two functions.
Thanks
David
^ permalink raw reply
* Re: [PATCH] HID: uhid: Add UHID_CREATE2 + UHID_INPUT2
From: Petri Gynther @ 2014-03-24 19:19 UTC (permalink / raw)
To: David Herrmann; +Cc: open list:HID CORE LAYER, Jiri Kosina
In-Reply-To: <CANq1E4QnrBxjuK9irmHss54hJi9T=u0WidB2o=8a1r=2Jo-JuA@mail.gmail.com>
Hi David,
On Mon, Mar 24, 2014 at 12:07 PM, David Herrmann <dh.herrmann@gmail.com> wrote:
> Hi
>
> On Mon, Mar 24, 2014 at 8:04 PM, Petri Gynther <pgynther@google.com> wrote:
>> This won't be enough. For UHID_CREATE, we need to use
>> ev->u.create.<member> and for UHID_CREATE2, ev->u.create2.<member>.
>> But, I'll collect those in local variables up front, so we can have
>> just one handler function. I'll send the revised diff shortly.
>
> Oh right, In that case I think we can keep the two functions.
Agreed, I think we should keep the the two functions separate. So, is
the diff good as-is?
-- Petri
>
> Thanks
> David
^ permalink raw reply
* [PATCH v2] HID: uhid: Add UHID_CREATE2 + UHID_INPUT2
From: Petri Gynther @ 2014-03-24 20:50 UTC (permalink / raw)
To: linux-input; +Cc: dh.herrmann, jkosina
UHID_CREATE2:
HID report descriptor data (rd_data) is an array in struct uhid_create2_req,
instead of a pointer. Enables use from languages that don't support pointers,
e.g. Python.
UHID_INPUT2:
Data array is the last field of struct uhid_input2_req. Enables userspace to
write only the required bytes to kernel (ev.type + ev.u.input2.size + the part
of the data array that matters), instead of the entire struct uhid_input2_req.
Note:
UHID_CREATE2 increases the total size of struct uhid_event slightly, thus
increasing the size of messages that are queued for userspace. However, this
won't affect the userspace processing of these events.
Signed-off-by: Petri Gynther <pgynther@google.com>
Reviewed-by: David Herrmann <dh.herrmann@gmail.com>
---
Documentation/hid/uhid.txt | 11 +++++++
drivers/hid/uhid.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++
include/uapi/linux/uhid.h | 23 +++++++++++++
3 files changed, 114 insertions(+)
diff --git a/Documentation/hid/uhid.txt b/Documentation/hid/uhid.txt
index dc35a2b..ee65936 100644
--- a/Documentation/hid/uhid.txt
+++ b/Documentation/hid/uhid.txt
@@ -93,6 +93,11 @@ the request was handled successfully.
event to the kernel. The payload is of type struct uhid_create_req and
contains information about your device. You can start I/O now.
+ UHID_CREATE2:
+ Same as UHID_CREATE, but the HID report descriptor data (rd_data) is an array
+ inside struct uhid_create2_req, instead of a pointer to a separate array.
+ Enables use from languages that don't support pointers, e.g. Python.
+
UHID_DESTROY:
This destroys the internal HID device. No further I/O will be accepted. There
may still be pending messages that you can receive with read() but no further
@@ -105,6 +110,12 @@ the request was handled successfully.
contains a data-payload. This is the raw data that you read from your device.
The kernel will parse the HID reports and react on it.
+ UHID_INPUT2:
+ Same as UHID_INPUT, but the data array is the last field of uhid_input2_req.
+ Enables userspace to write only the required bytes to kernel (ev.type +
+ ev.u.input2.size + the part of the data array that matters), instead of
+ the entire struct uhid_input2_req.
+
UHID_FEATURE_ANSWER:
If you receive a UHID_FEATURE request you must answer with this request. You
must copy the "id" field from the request into the answer. Set the "err" field
diff --git a/drivers/hid/uhid.c b/drivers/hid/uhid.c
index cedc6da..c5ee173 100644
--- a/drivers/hid/uhid.c
+++ b/drivers/hid/uhid.c
@@ -407,6 +407,69 @@ err_free:
return ret;
}
+static int uhid_dev_create2(struct uhid_device *uhid,
+ const struct uhid_event *ev)
+{
+ struct hid_device *hid;
+ int ret;
+
+ if (uhid->running)
+ return -EALREADY;
+
+ uhid->rd_size = ev->u.create2.rd_size;
+ if (uhid->rd_size <= 0 || uhid->rd_size > HID_MAX_DESCRIPTOR_SIZE)
+ return -EINVAL;
+
+ uhid->rd_data = kmalloc(uhid->rd_size, GFP_KERNEL);
+ if (!uhid->rd_data)
+ return -ENOMEM;
+
+ memcpy(uhid->rd_data, ev->u.create2.rd_data, uhid->rd_size);
+
+ hid = hid_allocate_device();
+ if (IS_ERR(hid)) {
+ ret = PTR_ERR(hid);
+ goto err_free;
+ }
+
+ strncpy(hid->name, ev->u.create2.name, 127);
+ hid->name[127] = 0;
+ strncpy(hid->phys, ev->u.create2.phys, 63);
+ hid->phys[63] = 0;
+ strncpy(hid->uniq, ev->u.create2.uniq, 63);
+ hid->uniq[63] = 0;
+
+ hid->ll_driver = &uhid_hid_driver;
+ hid->hid_get_raw_report = uhid_hid_get_raw;
+ hid->hid_output_raw_report = uhid_hid_output_raw;
+ hid->bus = ev->u.create2.bus;
+ hid->vendor = ev->u.create2.vendor;
+ hid->product = ev->u.create2.product;
+ hid->version = ev->u.create2.version;
+ hid->country = ev->u.create2.country;
+ hid->driver_data = uhid;
+ hid->dev.parent = uhid_misc.this_device;
+
+ uhid->hid = hid;
+ uhid->running = true;
+
+ ret = hid_add_device(hid);
+ if (ret) {
+ hid_err(hid, "Cannot register HID device\n");
+ goto err_hid;
+ }
+
+ return 0;
+
+err_hid:
+ hid_destroy_device(hid);
+ uhid->hid = NULL;
+ uhid->running = false;
+err_free:
+ kfree(uhid->rd_data);
+ return ret;
+}
+
static int uhid_dev_destroy(struct uhid_device *uhid)
{
if (!uhid->running)
@@ -435,6 +498,17 @@ static int uhid_dev_input(struct uhid_device *uhid, struct uhid_event *ev)
return 0;
}
+static int uhid_dev_input2(struct uhid_device *uhid, struct uhid_event *ev)
+{
+ if (!uhid->running)
+ return -EINVAL;
+
+ hid_input_report(uhid->hid, HID_INPUT_REPORT, ev->u.input2.data,
+ min_t(size_t, ev->u.input2.size, UHID_DATA_MAX), 0);
+
+ return 0;
+}
+
static int uhid_dev_feature_answer(struct uhid_device *uhid,
struct uhid_event *ev)
{
@@ -571,12 +645,18 @@ static ssize_t uhid_char_write(struct file *file, const char __user *buffer,
case UHID_CREATE:
ret = uhid_dev_create(uhid, &uhid->input_buf);
break;
+ case UHID_CREATE2:
+ ret = uhid_dev_create2(uhid, &uhid->input_buf);
+ break;
case UHID_DESTROY:
ret = uhid_dev_destroy(uhid);
break;
case UHID_INPUT:
ret = uhid_dev_input(uhid, &uhid->input_buf);
break;
+ case UHID_INPUT2:
+ ret = uhid_dev_input2(uhid, &uhid->input_buf);
+ break;
case UHID_FEATURE_ANSWER:
ret = uhid_dev_feature_answer(uhid, &uhid->input_buf);
break;
diff --git a/include/uapi/linux/uhid.h b/include/uapi/linux/uhid.h
index 414b74b..1e3b09c 100644
--- a/include/uapi/linux/uhid.h
+++ b/include/uapi/linux/uhid.h
@@ -21,6 +21,7 @@
#include <linux/input.h>
#include <linux/types.h>
+#include <linux/hid.h>
enum uhid_event_type {
UHID_CREATE,
@@ -34,6 +35,8 @@ enum uhid_event_type {
UHID_INPUT,
UHID_FEATURE,
UHID_FEATURE_ANSWER,
+ UHID_CREATE2,
+ UHID_INPUT2,
};
struct uhid_create_req {
@@ -50,6 +53,19 @@ struct uhid_create_req {
__u32 country;
} __attribute__((__packed__));
+struct uhid_create2_req {
+ __u8 name[128];
+ __u8 phys[64];
+ __u8 uniq[64];
+ __u16 rd_size;
+ __u16 bus;
+ __u32 vendor;
+ __u32 product;
+ __u32 version;
+ __u32 country;
+ __u8 rd_data[HID_MAX_DESCRIPTOR_SIZE];
+} __attribute__((__packed__));
+
#define UHID_DATA_MAX 4096
enum uhid_report_type {
@@ -63,6 +79,11 @@ struct uhid_input_req {
__u16 size;
} __attribute__((__packed__));
+struct uhid_input2_req {
+ __u16 size;
+ __u8 data[UHID_DATA_MAX];
+} __attribute__((__packed__));
+
struct uhid_output_req {
__u8 data[UHID_DATA_MAX];
__u16 size;
@@ -100,6 +121,8 @@ struct uhid_event {
struct uhid_output_ev_req output_ev;
struct uhid_feature_req feature;
struct uhid_feature_answer_req feature_answer;
+ struct uhid_create2_req create2;
+ struct uhid_input2_req input2;
} u;
} __attribute__((__packed__));
--
1.9.1.423.g4596e3a
^ permalink raw reply related
* [PATCH] HID: hid-sensor-hub: fix sleeping function called from invalid context
From: Srinivas Pandruvada @ 2014-03-24 23:25 UTC (permalink / raw)
To: jkosina; +Cc: linux-input, Srinivas Pandruvada
Fix issue with the sleeping calling hid_hw_request under spinlock.
When i2c is used as HID transport, this is calling kmalloc, which
can sleep. So remove call to this function while under spinlock.
[ 1067.021961] Call Trace:
[ 1067.021970] [<ffffffff8192f5f2>] dump_stack+0x4d/0x6f
[ 1067.021976] [<ffffffff811109f2>] __might_sleep+0xd2/0xf0
[ 1067.021981] [<ffffffff811ea15b>] __kmalloc+0xeb/0x200
[ 1067.021989] [<ffffffff816e0cb3>] ? hid_alloc_report_buf+0x23/0x30
[ 1067.021993] [<ffffffff816e0cb3>] hid_alloc_report_buf+0x23/0x30
[ 1067.021997] [<ffffffff816f4cb7>] i2c_hid_request+0x57/0x110
[ 1067.022006] [<ffffffffa02bc61c>] sensor_hub_input_attr_get_raw_value+0xbc/0x100 [hid_sensor_hub]
Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
---
drivers/hid/hid-sensor-hub.c | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/drivers/hid/hid-sensor-hub.c b/drivers/hid/hid-sensor-hub.c
index 9c22e14..9021c9c 100644
--- a/drivers/hid/hid-sensor-hub.c
+++ b/drivers/hid/hid-sensor-hub.c
@@ -260,13 +260,12 @@ int sensor_hub_input_attr_get_raw_value(struct hid_sensor_hub_device *hsdev,
spin_lock_irqsave(&data->lock, flags);
data->pending.status = true;
+ spin_unlock_irqrestore(&data->lock, flags);
report = sensor_hub_report(report_id, hsdev->hdev, HID_INPUT_REPORT);
- if (!report) {
- spin_unlock_irqrestore(&data->lock, flags);
+ if (!report)
goto err_free;
- }
+
hid_hw_request(hsdev->hdev, report, HID_REQ_GET_REPORT);
- spin_unlock_irqrestore(&data->lock, flags);
wait_for_completion_interruptible_timeout(&data->pending.ready, HZ*5);
switch (data->pending.raw_size) {
case 1:
--
1.8.3.2
^ permalink raw reply related
* Regression: mouse pointer stuck in KDE with kernel 3.13 and above
From: Dâniel Fraga @ 2014-03-25 2:28 UTC (permalink / raw)
To: linux-input
I'd like some help to debug this regression. After upgrading
from kernel 3.12 to 3.13, my mouse gets stuck after entering in KDE (at
console with gpm everything is fine).
Bisect is worthless in this case, because this bug doesn't
trigger everytime. USB is not the problem, since usbmon trace shows
activity even with the mouse pointer stuck.
What can I do do debug this? Any hints?
Thanks.
--
Linux 3.12.14: Shuffling Zombie Juror
http://www.youtube.com/DanielFragaBR
http://mcxnow.com?r=danielfragabr
Bitcoin: 12H6661yoLDUZaYPdah6urZS5WiXwTAUgL
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox