Linux Input/HID development
 help / color / mirror / Atom feed
* Re: [PATCH 3/3] Add logitech m560 driver
From: Nestor Lopez Casado @ 2014-08-25  8:38 UTC (permalink / raw)
  To: Goffredo Baroncelli; +Cc: open list:HID CORE LAYER, Goffredo Baroncelli
In-Reply-To: <1408797629-3474-4-git-send-email-kreijack@inwind.it>

Hi,

If you want to have a special driver for a specific Unifying device
you should put in place the right structure to have a separate driver
for it.

hid-logitech-dj is a "bus" driver for the Unifying *receiver*, not a
driver for any specific Unifying device.

Benjamin Tisssoires (github bentiss) has uploaded a few patches to his
github account to finish the infrastructure for specific Unifying
devices drivers. Look for the more complete branch 'for-whot' See how
he created a hid-logitech-wtp driver for the Different wireless
touchpads.

This would be the right approach to what you are trying to do.

Cheers,
-nestor


On Sat, Aug 23, 2014 at 2:40 PM, Goffredo Baroncelli <kreijack@gmail.com> wrote:
> Add logitech m560 support. In the init phase the driver
> send a sequence which avoid some unnecessary key sending
> from the mouse.
>
> The mouse appears as a couple of mouse and keyboard. Some buttons
> emit a key event instead of the "mouse button" event. However
> some event (like the middle button release) aren't generated.
> Fortunately, the device generates an additional event to
> track it. The event type is 0x0a.
>
> Signed-off-by: Goffredo Baroncelli <kreijack@inwind.it>
> ---
>  drivers/hid/hid-logitech-dj.c | 92 +++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 92 insertions(+)
>
> diff --git a/drivers/hid/hid-logitech-dj.c b/drivers/hid/hid-logitech-dj.c
> index feddd3d..40c5ea1 100644
> --- a/drivers/hid/hid-logitech-dj.c
> +++ b/drivers/hid/hid-logitech-dj.c
> @@ -222,7 +222,99 @@ static inline void call_destroy(struct dj_device *djdev)
>         djdev->methods->destroy(djdev);
>  }
>
> +/*
> + * Send the sequence 10xx0a35 00af03
> + * to the mouse id xx. It disables the key sending by the central button.
> + */
> +
> +static int lg_m560_init_device(struct dj_device *dj_device)
> +{
> +       struct dj_report *dj_report;
> +       int retval;
> +       static u8 reset_data[] = {0x35, 0x00, 0xaf, 0x03};
> +
> +       dj_report = kzalloc(sizeof(struct dj_report), GFP_KERNEL);
> +       if (!dj_report)
> +               return -ENOMEM;
> +
> +       dj_device->userdata = dj_report;
> +
> +       dj_report->report_id = REPORT_ID_RECV_SHORT;
> +       dj_report->device_index = dj_device->device_index;
> +       dj_report->report_type = 0x0a;
> +
> +       memcpy(dj_report->report_params, reset_data, sizeof(reset_data));
> +
> +       retval = hid_hw_raw_request(dj_device->dj_receiver_dev->hdev,
> +               dj_report->report_id,
> +               (void *)dj_report, REPORT_ID_RECV_SHORT_LENGTH,
> +               HID_OUTPUT_REPORT, HID_REQ_SET_REPORT);
> +
> +       memset(dj_report, 0, sizeof(struct dj_report));
> +
> +       return retval;
> +}
> +
> +static int lg_m560_parse_raw_event(struct dj_device *dj_device,
> +                                       struct dj_report *dj_report)
> +{
> +       u8 *m506_last_mouse_report = dj_device->userdata;
> +
> +       BUG_ON(!dj_device);
> +
> +       /* don't pass keys when the mouse is a m560 */
> +       if (dj_report->report_type == REPORT_TYPE_KEYBOARD)
> +               return true;
> +
> +       if (dj_report->report_id == 0x11 && dj_report->report_type == 0x0a) {
> +               int btn;
> +
> +               /* check if the event is a button */
> +               btn = dj_report->report_params[2];
> +               if (btn != 0x00 && btn != 0xb0 && btn != 0xae && btn != 0xaf)
> +                       return true;
> +
> +               if (btn == 0xaf)
> +                       m506_last_mouse_report[1] |= 4;
> +               if (btn == 0xae)
> +                       m506_last_mouse_report[2] |= 2;
> +               if (btn == 0xb0)
> +                       m506_last_mouse_report[2] |= 4;
> +               if (btn == 0x00) {
> +                       m506_last_mouse_report[1] &= ~4;
> +                       m506_last_mouse_report[2] &= ~(4|2);
> +               }
> +
> +               if (hid_input_report(dj_device->hdev, HID_INPUT_REPORT,
> +                                       m506_last_mouse_report, 8, 1)) {
> +                               dbg_hid("hid_input_report error\n");
> +               }
> +               return true;
> +       }
> +
> +       /* copy the button status */
> +       if (dj_report->report_type == REPORT_TYPE_MOUSE) {
> +               /* copy only the first 3 bytes: type, btn0..7, btn8..16 */
> +               memcpy(dj_device->userdata,
> +                       &dj_report->report_type, 3);
> +       }
> +
> +       /* continue with the standard handler */
> +       return false;
> +}
> +
> +static void lg_m560_destroy(struct dj_device *dev)
> +{
> +       kfree(dev->userdata);
> +}
> +
>  static struct dj_device_method dj_device_method[] = {
> +       {       /* logitech M560 */
> +               .device_names = (char *[]){ "M560", NULL },
> +               .init_device = lg_m560_init_device,
> +               .parse_raw_event = lg_m560_parse_raw_event,
> +               .destroy = lg_m560_destroy
> +       },
>
>         /* last element */
>         { NULL, }
> --
> 1.9.3
>
> --
> 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

* Input sync flag when registering.
From: Thomas Poussevin @ 2014-08-25  8:52 UTC (permalink / raw)
  To: linux-input

[-- Attachment #1: Type: text/plain, Size: 606 bytes --]

Hi,
I noticed that with touchscreen drivers that don't explicitly call a 
input_sync after input_register_device, suspend to ram is blocked if no 
event is sent, because the input_dev created is considered as not 
synchronized. The problem was seen with Atmel mxt driver. When any event 
is sent, the driver explicitly ask a sync, so the problem is solved.
The problem occurs only when the screen has never send any event before 
suspend to ram.
I solved it setting the sync element to true (when input dev is created, 
no element is pending).
Is there a better way to solve the problem ?
Thanks.
Thomas.


[-- Attachment #2: 0001-DEV-input-Set-input-sync-param-default-status-to-tru.patch --]
[-- Type: text/x-patch, Size: 967 bytes --]

>From d0edf89b99de37e366d5ad1ab08e3c936ac553ae Mon Sep 17 00:00:00 2001
From: Thomas Poussevin <thomas.poussevin@parrot.com>
Date: Fri, 22 Aug 2014 17:56:17 +0200
Subject: [PATCH] [input] Set input sync param default status to true, to
 prevent touchscreen suspend fails. Problems used to happen only when
 touchsreen had not been touched since boot. When the first event is sent,
 input status is actualized.

Signed-off-by: Thomas Poussevin <thomas.poussevin@parrot.com>
---
 drivers/input/input.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/input/input.c b/drivers/input/input.c
index 8921c61..c214b39 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -1652,6 +1652,7 @@ struct input_dev *input_allocate_device(void)
 	if (dev) {
 		dev->dev.type = &input_dev_type;
 		dev->dev.class = &input_class;
+		dev->sync = true;
 		device_initialize(&dev->dev);
 		mutex_init(&dev->mutex);
 		spin_lock_init(&dev->event_lock);
-- 
1.9.2




^ permalink raw reply related

* Re: [PATCH 1/1] HID: usbhid: add usb_clear_halt determination for next hid_start_in
From: Oliver Neukum @ 2014-08-25 10:21 UTC (permalink / raw)
  To: Alan Stern; +Cc: vichy, Jiri Kosina, linux-usb@vger.kernel.org, linux-input
In-Reply-To: <Pine.LNX.4.44L0.1408221358030.967-100000@iolanthe.rowland.org>

On Fri, 2014-08-22 at 14:23 -0400, Alan Stern wrote:
> On Sat, 23 Aug 2014, vichy wrote:
> 
> > from your patch, I have some questions:
> > a. in Alan's version, if both HID_CLEAR_HALT and HID_RESET_PENDING are
> > set, hid_reset will both "clear ep halt" and "reset devcie".
> > But in original one, even HID_CLEAR_HALT and HID_RESET_PENDING are
> > both set, hid_reset only do one of them.
> 
> Yes.  In my patch, the clear-halt handler will turn on the
> HID_RESET_PENDING bit if something goes wrong.  In that case we want to
> do both things.

Why? If we reset, why bother clearing a halt? Especially as this
may mean waiting the full 5 seconds for a timeout.

> > is there any special reason in original hid_reset to use below flow?
> >     if (test_bit(HID_CLEAR_HALT, &usbhid->iofl)) {
> >             xxxxx
> >     } else if (test_bit(HID_RESET_PENDING, &usbhid->iofl)) {
> >             xxxxxx
> >     }
> 
> No special reason.  We probably never thought that both flags would be
> set.

Yes. And I'd say if this ever happens HID_RESET_PENDING must have
priority and implicitly clears a halt.

	Regards
		Oliver




^ permalink raw reply

* Re: [PATCH 1/1] HID: usbhid: add usb_clear_halt determination for next hid_start_in
From: vichy @ 2014-08-25 12:49 UTC (permalink / raw)
  To: Alan Stern; +Cc: Jiri Kosina, linux-usb@vger.kernel.org, linux-input
In-Reply-To: <Pine.LNX.4.44L0.1408241127320.26310-100000@netrider.rowland.org>

hi Alan:
>> "usb_unbind_and_rebind_marked_interfaces" is called if config
>> parameter is not null,
>> it seems no matter post_reset routine fail or not.
>
> Yes, that's right.  I should have said: "Because the post_reset routine
> failed, usb_unbind_and_rebind_marked_interfaces indirectly calls
> usbhid_disconnect.

Even post_reset routine failed,
usb_unbind_and_rebind_marked_interfaces will still indirectly calls
usbhid_disconnect, right?


> I don't remember the entire call chain.  It was pretty long.
> hid_destroy_device calls hid_remove_device, which calls device_del,
> which calls lots of other things.  If you really want to see all the
> details, put a dump_stack() call in usbhid_close and examine what it
> prints in the kernel log when you unplug an HID device.
I found what you mentioned ^^

Thanks for your kind help,

^ permalink raw reply

* Re: [PATCH 1/1] HID: usbhid: add usb_clear_halt determination for next hid_start_in
From: vichy @ 2014-08-25 12:56 UTC (permalink / raw)
  To: Oliver Neukum
  Cc: Alan Stern, Jiri Kosina, linux-usb@vger.kernel.org, linux-input
In-Reply-To: <1408962087.10300.15.camel@linux-fkkt.site>

hi Oliver:

2014-08-25 18:21 GMT+08:00 Oliver Neukum <oneukum@suse.de>:
> On Fri, 2014-08-22 at 14:23 -0400, Alan Stern wrote:
>> On Sat, 23 Aug 2014, vichy wrote:
>>
>> > from your patch, I have some questions:
>> > a. in Alan's version, if both HID_CLEAR_HALT and HID_RESET_PENDING are
>> > set, hid_reset will both "clear ep halt" and "reset devcie".
>> > But in original one, even HID_CLEAR_HALT and HID_RESET_PENDING are
>> > both set, hid_reset only do one of them.
>>
>> Yes.  In my patch, the clear-halt handler will turn on the
>> HID_RESET_PENDING bit if something goes wrong.  In that case we want to
>> do both things.
>
> Why? If we reset, why bother clearing a halt? Especially as this
> may mean waiting the full 5 seconds for a timeout.
I think what Alan mean is IF CLEAR HALT fail, we reset the device.
That is what below "In that case" mean.
 "In that case we want to do both things."

BR,

^ permalink raw reply

* [PATCH v2 1/7] mfd: cros_ec: Delay for 50ms when we see EC_CMD_REBOOT_EC
From: Javier Martinez Canillas @ 2014-08-25 13:40 UTC (permalink / raw)
  To: Lee Jones
  Cc: Wolfram Sang, Dmitry Torokhov, Doug Anderson, Simon Glass,
	Bill Richardson, Andrew Bresticker, Derek Basehore, Todd Broch,
	Olof Johansson, linux-i2c, linux-input, linux-samsung-soc,
	Javier Martinez Canillas
In-Reply-To: <1408974008-17184-1-git-send-email-javier.martinez@collabora.co.uk>

From: Doug Anderson <dianders@chromium.org>

If someone sends a EC_CMD_REBOOT_EC to the EC, the EC will likely be
unresponsive for quite a while.  Add a delay to the end of the command
to prevent random failures of future commands.

NOTES:
* This could be optimized a bit by simply delaying the next command
  sent, but EC_CMD_REBOOT_EC is such a rare command that the extra
  complexity doesn't seem worth it.
* This is a bit of an "ugly hack" since the SPI driver is effectively
  snooping on the communication and making a lot of assumptions.  It
  would be nice to architect in some better solution long term.
* This same logic probably needs to be applied to the i2c driver.

Signed-off-by: Doug Anderson <dianders@chromium.org>
Reviewed-by: Randall Spangler <rspangler@chromium.org>
Reviewed-by: Vadim Bendebury <vbendeb@chromium.org>
Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
Acked-by: Lee Jones <lee.jones@linaro.org>
---
 drivers/mfd/cros_ec_spi.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/drivers/mfd/cros_ec_spi.c b/drivers/mfd/cros_ec_spi.c
index 588c700..b396705 100644
--- a/drivers/mfd/cros_ec_spi.c
+++ b/drivers/mfd/cros_ec_spi.c
@@ -65,6 +65,12 @@
   */
 #define EC_SPI_RECOVERY_TIME_NS	(200 * 1000)
 
+/*
+ * The EC is unresponsive for a time after a reboot command.  Add a
+ * simple delay to make sure that the bus stays locked.
+ */
+#define EC_REBOOT_DELAY_MS	50
+
 /**
  * struct cros_ec_spi - information about a SPI-connected EC
  *
@@ -318,6 +324,9 @@ static int cros_ec_cmd_xfer_spi(struct cros_ec_device *ec_dev,
 
 	ret = len;
 exit:
+	if (ec_msg->command == EC_CMD_REBOOT_EC)
+		msleep(EC_REBOOT_DELAY_MS);
+
 	mutex_unlock(&ec_spi->lock);
 	return ret;
 }
-- 
2.0.1

^ permalink raw reply related

* [PATCH v2 3/7] mfd: cros_ec: stop calling ->cmd_xfer() directly
From: Javier Martinez Canillas @ 2014-08-25 13:40 UTC (permalink / raw)
  To: Lee Jones
  Cc: Wolfram Sang, Dmitry Torokhov, Doug Anderson, Simon Glass,
	Bill Richardson, Andrew Bresticker, Derek Basehore, Todd Broch,
	Olof Johansson, linux-i2c-u79uwXL29TY76Z2rM5mHXA,
	linux-input-u79uwXL29TY76Z2rM5mHXA,
	linux-samsung-soc-u79uwXL29TY76Z2rM5mHXA,
	Javier Martinez Canillas
In-Reply-To: <1408974008-17184-1-git-send-email-javier.martinez-ZGY8ohtN/8pPYcu2f3hruQ@public.gmane.org>

From: Andrew Bresticker <abrestic-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>

Instead of having users of the ChromeOS EC call the interface-specific
cmd_xfer() callback directly, introduce a central cros_ec_cmd_xfer()
to use instead.  This will allow us to put all the locking and retry
logic in one place instead of duplicating it across the different
drivers.

Signed-off-by: Andrew Bresticker <abrestic-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
Reviewed-by: Simon Glass <sjg-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
Signed-off-by: Javier Martinez Canillas <javier.martinez-ZGY8ohtN/8pPYcu2f3hruQ@public.gmane.org>
Reviewed-by: Doug Anderson <dianders-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
Acked-by: Lee Jones <lee.jones-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
---
 drivers/i2c/busses/i2c-cros-ec-tunnel.c |  2 +-
 drivers/input/keyboard/cros_ec_keyb.c   |  2 +-
 drivers/mfd/cros_ec.c                   |  7 +++++++
 include/linux/mfd/cros_ec.h             | 24 ++++++++++++++++++------
 4 files changed, 27 insertions(+), 8 deletions(-)

diff --git a/drivers/i2c/busses/i2c-cros-ec-tunnel.c b/drivers/i2c/busses/i2c-cros-ec-tunnel.c
index 97e6369..ec5c38d 100644
--- a/drivers/i2c/busses/i2c-cros-ec-tunnel.c
+++ b/drivers/i2c/busses/i2c-cros-ec-tunnel.c
@@ -229,7 +229,7 @@ static int ec_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg i2c_msgs[],
 	msg.indata = response;
 	msg.insize = response_len;
 
-	result = bus->ec->cmd_xfer(bus->ec, &msg);
+	result = cros_ec_cmd_xfer(bus->ec, &msg);
 	if (result < 0)
 		goto exit;
 
diff --git a/drivers/input/keyboard/cros_ec_keyb.c b/drivers/input/keyboard/cros_ec_keyb.c
index 0bdbf2d..f8d4a8b 100644
--- a/drivers/input/keyboard/cros_ec_keyb.c
+++ b/drivers/input/keyboard/cros_ec_keyb.c
@@ -182,7 +182,7 @@ static int cros_ec_keyb_get_state(struct cros_ec_keyb *ckdev, uint8_t *kb_state)
 		.insize = ckdev->cols,
 	};
 
-	return ckdev->ec->cmd_xfer(ckdev->ec, &msg);
+	return cros_ec_cmd_xfer(ckdev->ec, &msg);
 }
 
 static irqreturn_t cros_ec_keyb_irq(int irq, void *data)
diff --git a/drivers/mfd/cros_ec.c b/drivers/mfd/cros_ec.c
index 4873f9c..a9faebd 100644
--- a/drivers/mfd/cros_ec.c
+++ b/drivers/mfd/cros_ec.c
@@ -62,6 +62,13 @@ int cros_ec_check_result(struct cros_ec_device *ec_dev,
 }
 EXPORT_SYMBOL(cros_ec_check_result);
 
+int cros_ec_cmd_xfer(struct cros_ec_device *ec_dev,
+		     struct cros_ec_command *msg)
+{
+	return ec_dev->cmd_xfer(ec_dev, msg);
+}
+EXPORT_SYMBOL(cros_ec_cmd_xfer);
+
 static const struct mfd_cell cros_devs[] = {
 	{
 		.name = "cros-ec-keyb",
diff --git a/include/linux/mfd/cros_ec.h b/include/linux/mfd/cros_ec.h
index fcbe9d1..0e166b9 100644
--- a/include/linux/mfd/cros_ec.h
+++ b/include/linux/mfd/cros_ec.h
@@ -62,10 +62,6 @@ struct cros_ec_command {
  * @dev: Device pointer
  * @was_wake_device: true if this device was set to wake the system from
  * sleep at the last suspend
- * @cmd_xfer: send command to EC and get response
- *     Returns the number of bytes received if the communication succeeded, but
- *     that doesn't mean the EC was happy with the command. The caller
- *     should check msg.result for the EC's result code.
  *
  * @priv: Private data
  * @irq: Interrupt to use
@@ -82,6 +78,10 @@ struct cros_ec_command {
  * @dout_size: size of dout buffer to allocate (zero to use static dout)
  * @parent: pointer to parent device (e.g. i2c or spi device)
  * @wake_enabled: true if this device can wake the system from sleep
+ * @cmd_xfer: send command to EC and get response
+ *     Returns the number of bytes received if the communication succeeded, but
+ *     that doesn't mean the EC was happy with the command. The caller
+ *     should check msg.result for the EC's result code.
  * @lock: one transaction at a time
  */
 struct cros_ec_device {
@@ -92,8 +92,6 @@ struct cros_ec_device {
 	struct device *dev;
 	bool was_wake_device;
 	struct class *cros_class;
-	int (*cmd_xfer)(struct cros_ec_device *ec,
-			struct cros_ec_command *msg);
 
 	/* These are used to implement the platform-specific interface */
 	void *priv;
@@ -104,6 +102,8 @@ struct cros_ec_device {
 	int dout_size;
 	struct device *parent;
 	bool wake_enabled;
+	int (*cmd_xfer)(struct cros_ec_device *ec,
+			struct cros_ec_command *msg);
 	struct mutex lock;
 };
 
@@ -153,6 +153,18 @@ int cros_ec_check_result(struct cros_ec_device *ec_dev,
 			 struct cros_ec_command *msg);
 
 /**
+ * cros_ec_cmd_xfer - Send a command to the ChromeOS EC
+ *
+ * Call this to send a command to the ChromeOS EC.  This should be used
+ * instead of calling the EC's cmd_xfer() callback directly.
+ *
+ * @ec_dev: EC device
+ * @msg: Message to write
+ */
+int cros_ec_cmd_xfer(struct cros_ec_device *ec_dev,
+		     struct cros_ec_command *msg);
+
+/**
  * cros_ec_remove - Remove a ChromeOS EC
  *
  * Call this to deregister a ChromeOS EC, then clean up any private data.
-- 
2.0.1

^ permalink raw reply related

* [PATCH v2 5/7] mfd: cros_ec: wait for completion of commands that return IN_PROGRESS
From: Javier Martinez Canillas @ 2014-08-25 13:40 UTC (permalink / raw)
  To: Lee Jones
  Cc: Wolfram Sang, Dmitry Torokhov, Doug Anderson, Simon Glass,
	Bill Richardson, Andrew Bresticker, Derek Basehore, Todd Broch,
	Olof Johansson, linux-i2c, linux-input, linux-samsung-soc,
	Javier Martinez Canillas
In-Reply-To: <1408974008-17184-1-git-send-email-javier.martinez@collabora.co.uk>

From: Andrew Bresticker <abrestic@chromium.org>

When an EC command returns EC_RES_IN_PROGRESS, we need to query
the state of the EC until it indicates that it is no longer busy.
Do this in cros_ec_cmd_xfer() under the EC's mutex so that other
commands (e.g. keyboard, I2C passtru) aren't issued to the EC while
it is working on the in-progress command.

Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
Reviewed-by: Simon Glass <sjg@chromium.org>
Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
---

Changes since v1:
 - The *xfer() calls don't modify the passed cros_ec_command so there is
   no need to populate it inside the for loop. Suggested by Lee Jones.
---
 drivers/mfd/cros_ec.c | 34 +++++++++++++++++++++++++++++++++-
 1 file changed, 33 insertions(+), 1 deletion(-)

diff --git a/drivers/mfd/cros_ec.c b/drivers/mfd/cros_ec.c
index c53804a..cd0c93c 100644
--- a/drivers/mfd/cros_ec.c
+++ b/drivers/mfd/cros_ec.c
@@ -23,6 +23,10 @@
 #include <linux/mfd/core.h>
 #include <linux/mfd/cros_ec.h>
 #include <linux/mfd/cros_ec_commands.h>
+#include <linux/delay.h>
+
+#define EC_COMMAND_RETRIES	50
+#define EC_RETRY_DELAY_MS	10
 
 int cros_ec_prepare_tx(struct cros_ec_device *ec_dev,
 		       struct cros_ec_command *msg)
@@ -65,10 +69,38 @@ EXPORT_SYMBOL(cros_ec_check_result);
 int cros_ec_cmd_xfer(struct cros_ec_device *ec_dev,
 		     struct cros_ec_command *msg)
 {
-	int ret;
+	int ret, i;
+	struct cros_ec_command status_msg;
+	struct ec_response_get_comms_status status;
 
 	mutex_lock(&ec_dev->lock);
 	ret = ec_dev->cmd_xfer(ec_dev, msg);
+	if (ret == -EAGAIN && msg->result == EC_RES_IN_PROGRESS) {
+		/*
+		 * Query the EC's status until it's no longer busy or
+		 * we encounter an error.
+		 */
+		status_msg.version = 0;
+		status_msg.command = EC_CMD_GET_COMMS_STATUS;
+		status_msg.outdata = NULL;
+		status_msg.outsize = 0;
+		status_msg.indata = (uint8_t *)&status;
+		status_msg.insize = sizeof(status);
+
+		for (i = 0; i < EC_COMMAND_RETRIES; i++) {
+			msleep(EC_RETRY_DELAY_MS);
+
+			ret = ec_dev->cmd_xfer(ec_dev, &status_msg);
+			if (ret < 0)
+				break;
+
+			msg->result = status_msg.result;
+			if (status_msg.result != EC_RES_SUCCESS)
+				break;
+			if (!(status.flags & EC_COMMS_STATUS_PROCESSING))
+				break;
+		}
+	}
 	mutex_unlock(&ec_dev->lock);
 
 	return ret;
-- 
2.0.1

^ permalink raw reply related

* [PATCH v2 7/7] Input: cros_ec_keyb: Optimize ghosting algorithm.
From: Javier Martinez Canillas @ 2014-08-25 13:40 UTC (permalink / raw)
  To: Lee Jones
  Cc: Wolfram Sang, Dmitry Torokhov, Doug Anderson, Simon Glass,
	Bill Richardson, Andrew Bresticker, Derek Basehore, Todd Broch,
	Olof Johansson, linux-i2c-u79uwXL29TY76Z2rM5mHXA,
	linux-input-u79uwXL29TY76Z2rM5mHXA,
	linux-samsung-soc-u79uwXL29TY76Z2rM5mHXA,
	Javier Martinez Canillas
In-Reply-To: <1408974008-17184-1-git-send-email-javier.martinez-ZGY8ohtN/8pPYcu2f3hruQ@public.gmane.org>

From: Todd Broch <tbroch-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>

Previous algorithm was a bit conservative and complicating with
respect to identifying key ghosting.  This CL uses the bitops hamming
weight function (hweight8) to count the number of matching rows for
colM & colN.  If that number is > 1 ghosting is present.

Additionally it removes NULL keys and our one virtual keypress
KEY_BATTERY from consideration as these inputs are never physical
keypresses.

Signed-off-by: Todd Broch <tbroch-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
Reviewed-by: Vincent Palatin <vpalatin-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
Reviewed-by: Luigi Semenzato <semenzato-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
Tested-by: Andreas Färber <afaerber-l3A5Bk7waGM@public.gmane.org>
Signed-off-by: Javier Martinez Canillas <javier.martinez-ZGY8ohtN/8oXa1LcwEujcA@public.gmane.orgk>
---
 drivers/input/keyboard/cros_ec_keyb.c | 92 +++++++++++++++++++----------------
 1 file changed, 49 insertions(+), 43 deletions(-)

diff --git a/drivers/input/keyboard/cros_ec_keyb.c b/drivers/input/keyboard/cros_ec_keyb.c
index f8d4a8b..462bfcb 100644
--- a/drivers/input/keyboard/cros_ec_keyb.c
+++ b/drivers/input/keyboard/cros_ec_keyb.c
@@ -22,6 +22,7 @@
  */
 
 #include <linux/module.h>
+#include <linux/bitops.h>
 #include <linux/i2c.h>
 #include <linux/input.h>
 #include <linux/interrupt.h>
@@ -38,6 +39,7 @@
  * @row_shift: log2 or number of rows, rounded up
  * @keymap_data: Matrix keymap data used to convert to keyscan values
  * @ghost_filter: true to enable the matrix key-ghosting filter
+ * @valid_keys: bitmap of existing keys for each matrix column
  * @old_kb_state: bitmap of keys pressed last scan
  * @dev: Device pointer
  * @idev: Input device
@@ -49,6 +51,7 @@ struct cros_ec_keyb {
 	int row_shift;
 	const struct matrix_keymap_data *keymap_data;
 	bool ghost_filter;
+	uint8_t *valid_keys;
 	uint8_t *old_kb_state;
 
 	struct device *dev;
@@ -57,39 +60,15 @@ struct cros_ec_keyb {
 };
 
 
-static bool cros_ec_keyb_row_has_ghosting(struct cros_ec_keyb *ckdev,
-					  uint8_t *buf, int row)
-{
-	int pressed_in_row = 0;
-	int row_has_teeth = 0;
-	int col, mask;
-
-	mask = 1 << row;
-	for (col = 0; col < ckdev->cols; col++) {
-		if (buf[col] & mask) {
-			pressed_in_row++;
-			row_has_teeth |= buf[col] & ~mask;
-			if (pressed_in_row > 1 && row_has_teeth) {
-				/* ghosting */
-				dev_dbg(ckdev->dev,
-					"ghost found at: r%d c%d, pressed %d, teeth 0x%x\n",
-					row, col, pressed_in_row,
-					row_has_teeth);
-				return true;
-			}
-		}
-	}
-
-	return false;
-}
-
 /*
  * Returns true when there is at least one combination of pressed keys that
  * results in ghosting.
  */
 static bool cros_ec_keyb_has_ghosting(struct cros_ec_keyb *ckdev, uint8_t *buf)
 {
-	int row;
+	int col1, col2, buf1, buf2;
+	struct device *dev = ckdev->dev;
+	uint8_t *valid_keys = ckdev->valid_keys;
 
 	/*
 	 * Ghosting happens if for any pressed key X there are other keys
@@ -103,27 +82,23 @@ static bool cros_ec_keyb_has_ghosting(struct cros_ec_keyb *ckdev, uint8_t *buf)
 	 *
 	 * In this case only X, Y, and Z are pressed, but g appears to be
 	 * pressed too (see Wikipedia).
-	 *
-	 * We can detect ghosting in a single pass (*) over the keyboard state
-	 * by maintaining two arrays.  pressed_in_row counts how many pressed
-	 * keys we have found in a row.  row_has_teeth is true if any of the
-	 * pressed keys for this row has other pressed keys in its column.  If
-	 * at any point of the scan we find that a row has multiple pressed
-	 * keys, and at least one of them is at the intersection with a column
-	 * with multiple pressed keys, we're sure there is ghosting.
-	 * Conversely, if there is ghosting, we will detect such situation for
-	 * at least one key during the pass.
-	 *
-	 * (*) This looks linear in the number of keys, but it's not.  We can
-	 * cheat because the number of rows is small.
 	 */
-	for (row = 0; row < ckdev->rows; row++)
-		if (cros_ec_keyb_row_has_ghosting(ckdev, buf, row))
-			return true;
+	for (col1 = 0; col1 < ckdev->cols; col1++) {
+		buf1 = buf[col1] & valid_keys[col1];
+		for (col2 = col1 + 1; col2 < ckdev->cols; col2++) {
+			buf2 = buf[col2] & valid_keys[col2];
+			if (hweight8(buf1 & buf2) > 1) {
+				dev_dbg(dev, "ghost found at: B[%02d]:0x%02x & B[%02d]:0x%02x",
+					col1, buf1, col2, buf2);
+				return true;
+			}
+		}
+	}
 
 	return false;
 }
 
+
 /*
  * Compares the new keyboard state to the old one and produces key
  * press/release events accordingly.  The keyboard state is 13 bytes (one byte
@@ -222,6 +197,30 @@ static void cros_ec_keyb_close(struct input_dev *dev)
 	free_irq(ec->irq, ckdev);
 }
 
+/*
+ * Walks keycodes flipping bit in buffer COLUMNS deep where bit is ROW.  Used by
+ * ghosting logic to ignore NULL or virtual keys.
+ */
+static void cros_ec_keyb_compute_valid_keys(struct cros_ec_keyb *ckdev)
+{
+	int row, col;
+	int row_shift = ckdev->row_shift;
+	unsigned short *keymap = ckdev->idev->keycode;
+	unsigned short code;
+
+	BUG_ON(ckdev->idev->keycodesize != sizeof(*keymap));
+
+	for (col = 0; col < ckdev->cols; col++) {
+		for (row = 0; row < ckdev->rows; row++) {
+			code = keymap[MATRIX_SCAN_CODE(row, col, row_shift)];
+			if (code && (code != KEY_BATTERY))
+				ckdev->valid_keys[col] |= 1 << row;
+		}
+		dev_dbg(ckdev->dev, "valid_keys[%02d] = 0x%02x\n",
+			col, ckdev->valid_keys[col]);
+	}
+}
+
 static int cros_ec_keyb_probe(struct platform_device *pdev)
 {
 	struct cros_ec_device *ec = dev_get_drvdata(pdev->dev.parent);
@@ -242,6 +241,11 @@ static int cros_ec_keyb_probe(struct platform_device *pdev)
 					    &ckdev->cols);
 	if (err)
 		return err;
+
+	ckdev->valid_keys = devm_kzalloc(&pdev->dev, ckdev->cols, GFP_KERNEL);
+	if (!ckdev->valid_keys)
+		return -ENOMEM;
+
 	ckdev->old_kb_state = devm_kzalloc(&pdev->dev, ckdev->cols, GFP_KERNEL);
 	if (!ckdev->old_kb_state)
 		return -ENOMEM;
@@ -285,6 +289,8 @@ static int cros_ec_keyb_probe(struct platform_device *pdev)
 	input_set_capability(idev, EV_MSC, MSC_SCAN);
 	input_set_drvdata(idev, ckdev);
 	ckdev->idev = idev;
+	cros_ec_keyb_compute_valid_keys(ckdev);
+
 	err = input_register_device(ckdev->idev);
 	if (err) {
 		dev_err(dev, "cannot register input device\n");
-- 
2.0.1

^ permalink raw reply related

* [PATCH v2 0/7] Second batch of cleanups for cros_ec
From: Javier Martinez Canillas @ 2014-08-25 13:40 UTC (permalink / raw)
  To: Lee Jones
  Cc: Wolfram Sang, Dmitry Torokhov, Doug Anderson, Simon Glass,
	Bill Richardson, Andrew Bresticker, Derek Basehore, Todd Broch,
	Olof Johansson, linux-i2c, linux-input, linux-samsung-soc,
	Javier Martinez Canillas

This is a second batch of cleanups patches for the mfd cros_ec
driver and its subdevices drivers. The first batch of cleanups
was posted by Doug Anderson [0] and have already been merged.
The patches were picked from the ChromeOS 3.8 kernel and after
these no cleanups patches for cros_ec are left, only commits
that add cros ec support not yet available in mainline.

This is a second version of the patch series that addresses
issues pointed out by Doug Anderson and Lee Jones on v1 [1].

There is almost no functionality added on this series but the
idea is to reduce the delta between the mainline drivers and
the ones in the downstream Chrome OS 3.8 kernel so the missing
functionality can be added on top once these cleanups patches
are merged. The missing functionlity currently in mainline is:

- Chrome OS Embedded Controller userspace device interface
- Chrome OS Embedded Controller Low Pin Count (LPC) inteface
- Access to vboot context stored on a block device
- Access to vboot context stored on EC's nvram

The patches in this series are authored by different people
(all on cc) and consist of the following:

Andrew Bresticker (3):
  mfd: cros_ec: stop calling ->cmd_xfer() directly
  mfd: cros_ec: move locking into cros_ec_cmd_xfer
  mfd: cros_ec: wait for completion of commands that return IN_PROGRESS

Derek Basehore (1):
  i2c: i2c-cros-ec-tunnel: Set retries to 3

Doug Anderson (1):
  mfd: cros_ec: Delay for 50ms when we see EC_CMD_REBOOT_EC

Todd Broch (2):
  mfd: cros_ec: Instantiate sub-devices from device tree
  Input: cros_ec_keyb: Optimize ghosting algorithm.

 drivers/i2c/busses/i2c-cros-ec-tunnel.c |  5 +-
 drivers/input/keyboard/cros_ec_keyb.c   | 94 ++++++++++++++++++---------------
 drivers/mfd/cros_ec.c                   | 78 ++++++++++++++++++++-------
 drivers/mfd/cros_ec_spi.c               | 20 ++++---
 include/linux/mfd/cros_ec.h             | 24 ++++++---
 5 files changed, 141 insertions(+), 80 deletions(-)

Patches #1, #2, #6 and #7 do not depend of others so they can be
merged independently but patches #3, #4 and #5 have to be merged
in that specific order since they depend on the previous one. 

Best regards,
Javier

[0]: https://lkml.org/lkml/2014/6/16/681
[1]: http://comments.gmane.org/gmane.linux.drivers.i2c/19256


^ permalink raw reply

* [PATCH v2 2/7] i2c: i2c-cros-ec-tunnel: Set retries to 3
From: Javier Martinez Canillas @ 2014-08-25 13:40 UTC (permalink / raw)
  To: Lee Jones
  Cc: Wolfram Sang, Dmitry Torokhov, Doug Anderson, Simon Glass,
	Bill Richardson, Andrew Bresticker, Derek Basehore, Todd Broch,
	Olof Johansson, linux-i2c, linux-input, linux-samsung-soc,
	Javier Martinez Canillas
In-Reply-To: <1408974008-17184-1-git-send-email-javier.martinez@collabora.co.uk>

From: Derek Basehore <dbasehore@chromium.org>

Since the i2c bus can get wedged on the EC sometimes, set the number of retries
to 3. Since we un-wedge the bus immediately after the wedge happens, this is the
correct fix since only one transfer will fail.

Signed-off-by: Derek Basehore <dbasehore@chromium.org>
Reviewed-by: Doug Anderson <dianders@chromium.org>
Acked-by: Wolfram Sang <wsa@the-dreams.de>
Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
---
 drivers/i2c/busses/i2c-cros-ec-tunnel.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/i2c/busses/i2c-cros-ec-tunnel.c b/drivers/i2c/busses/i2c-cros-ec-tunnel.c
index 3c15dcc..97e6369 100644
--- a/drivers/i2c/busses/i2c-cros-ec-tunnel.c
+++ b/drivers/i2c/busses/i2c-cros-ec-tunnel.c
@@ -16,6 +16,8 @@
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 
+#define I2C_MAX_RETRIES 3
+
 /**
  * struct ec_i2c_device - Driver data for I2C tunnel
  *
@@ -290,6 +292,7 @@ static int ec_i2c_probe(struct platform_device *pdev)
 	bus->adap.algo_data = bus;
 	bus->adap.dev.parent = &pdev->dev;
 	bus->adap.dev.of_node = np;
+	bus->adap.retries = I2C_MAX_RETRIES;
 
 	err = i2c_add_adapter(&bus->adap);
 	if (err) {
-- 
2.0.1


^ permalink raw reply related

* [PATCH v2 4/7] mfd: cros_ec: move locking into cros_ec_cmd_xfer
From: Javier Martinez Canillas @ 2014-08-25 13:40 UTC (permalink / raw)
  To: Lee Jones
  Cc: Wolfram Sang, Dmitry Torokhov, Doug Anderson, Simon Glass,
	Bill Richardson, Andrew Bresticker, Derek Basehore, Todd Broch,
	Olof Johansson, linux-i2c, linux-input, linux-samsung-soc,
	Javier Martinez Canillas
In-Reply-To: <1408974008-17184-1-git-send-email-javier.martinez@collabora.co.uk>

From: Andrew Bresticker <abrestic@chromium.org>

Now that there's a central cros_ec_cmd_xfer(), move the locking
out of the SPI driver.

Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
Reviewed-by: Simon Glass <sjg@chromium.org>
Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
Reviewed-by: Doug Anderson <dianders@chromium.org>
Acked-by: Lee Jones <lee.jones@linaro.org>
---

Changes since v1:
 - Remove mention of LPC driver in the commit message since it does not
   exist in mainline yet. Suggested by Doug Anderson.
---
 drivers/mfd/cros_ec.c     | 10 +++++++++-
 drivers/mfd/cros_ec_spi.c | 11 -----------
 2 files changed, 9 insertions(+), 12 deletions(-)

diff --git a/drivers/mfd/cros_ec.c b/drivers/mfd/cros_ec.c
index a9faebd..c53804a 100644
--- a/drivers/mfd/cros_ec.c
+++ b/drivers/mfd/cros_ec.c
@@ -65,7 +65,13 @@ EXPORT_SYMBOL(cros_ec_check_result);
 int cros_ec_cmd_xfer(struct cros_ec_device *ec_dev,
 		     struct cros_ec_command *msg)
 {
-	return ec_dev->cmd_xfer(ec_dev, msg);
+	int ret;
+
+	mutex_lock(&ec_dev->lock);
+	ret = ec_dev->cmd_xfer(ec_dev, msg);
+	mutex_unlock(&ec_dev->lock);
+
+	return ret;
 }
 EXPORT_SYMBOL(cros_ec_cmd_xfer);
 
@@ -98,6 +104,8 @@ int cros_ec_register(struct cros_ec_device *ec_dev)
 			return -ENOMEM;
 	}
 
+	mutex_init(&ec_dev->lock);
+
 	err = mfd_add_devices(dev, 0, cros_devs,
 			      ARRAY_SIZE(cros_devs),
 			      NULL, ec_dev->irq, NULL);
diff --git a/drivers/mfd/cros_ec_spi.c b/drivers/mfd/cros_ec_spi.c
index b396705..bf6e08e 100644
--- a/drivers/mfd/cros_ec_spi.c
+++ b/drivers/mfd/cros_ec_spi.c
@@ -79,13 +79,11 @@
  *	if no record
  * @end_of_msg_delay: used to set the delay_usecs on the spi_transfer that
  *      is sent when we want to turn off CS at the end of a transaction.
- * @lock: mutex to ensure only one user of cros_ec_cmd_xfer_spi at a time
  */
 struct cros_ec_spi {
 	struct spi_device *spi;
 	s64 last_transfer_ns;
 	unsigned int end_of_msg_delay;
-	struct mutex lock;
 };
 
 static void debug_packet(struct device *dev, const char *name, u8 *ptr,
@@ -232,13 +230,6 @@ static int cros_ec_cmd_xfer_spi(struct cros_ec_device *ec_dev,
 	int sum;
 	int ret = 0, final_ret;
 
-	/*
-	 * We have the shared ec_dev buffer plus we do lots of separate spi_sync
-	 * calls, so we need to make sure only one person is using this at a
-	 * time.
-	 */
-	mutex_lock(&ec_spi->lock);
-
 	len = cros_ec_prepare_tx(ec_dev, ec_msg);
 	dev_dbg(ec_dev->dev, "prepared, len=%d\n", len);
 
@@ -327,7 +318,6 @@ exit:
 	if (ec_msg->command == EC_CMD_REBOOT_EC)
 		msleep(EC_REBOOT_DELAY_MS);
 
-	mutex_unlock(&ec_spi->lock);
 	return ret;
 }
 
@@ -359,7 +349,6 @@ static int cros_ec_spi_probe(struct spi_device *spi)
 	if (ec_spi == NULL)
 		return -ENOMEM;
 	ec_spi->spi = spi;
-	mutex_init(&ec_spi->lock);
 	ec_dev = devm_kzalloc(dev, sizeof(*ec_dev), GFP_KERNEL);
 	if (!ec_dev)
 		return -ENOMEM;
-- 
2.0.1


^ permalink raw reply related

* [PATCH v2 6/7] mfd: cros_ec: Instantiate sub-devices from device tree
From: Javier Martinez Canillas @ 2014-08-25 13:40 UTC (permalink / raw)
  To: Lee Jones
  Cc: Wolfram Sang, Dmitry Torokhov, Doug Anderson, Simon Glass,
	Bill Richardson, Andrew Bresticker, Derek Basehore, Todd Broch,
	Olof Johansson, linux-i2c, linux-input, linux-samsung-soc,
	Javier Martinez Canillas
In-Reply-To: <1408974008-17184-1-git-send-email-javier.martinez@collabora.co.uk>

From: Todd Broch <tbroch@chromium.org>

If the EC device tree node has sub-nodes, try to instantiate them as
MFD sub-devices.  We can configure the EC features provided by the board.

Signed-off-by: Todd Broch <tbroch@chromium.org>
Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
---

Changes since v1:
 - Don't leave an empty struct mfd_cell array. Suggested by Lee Jones.
 - Just use of_platform_populate() instead of manually iterating through
   sub-devices and calling mfd_add_devices. Suggested by Lee Jones.
---
 drivers/mfd/cros_ec.c | 35 ++++++++++++++++-------------------
 1 file changed, 16 insertions(+), 19 deletions(-)

diff --git a/drivers/mfd/cros_ec.c b/drivers/mfd/cros_ec.c
index cd0c93c..ab70791 100644
--- a/drivers/mfd/cros_ec.c
+++ b/drivers/mfd/cros_ec.c
@@ -21,6 +21,7 @@
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/mfd/core.h>
+#include <linux/of_platform.h>
 #include <linux/mfd/cros_ec.h>
 #include <linux/mfd/cros_ec_commands.h>
 #include <linux/delay.h>
@@ -107,22 +108,12 @@ int cros_ec_cmd_xfer(struct cros_ec_device *ec_dev,
 }
 EXPORT_SYMBOL(cros_ec_cmd_xfer);
 
-static const struct mfd_cell cros_devs[] = {
-	{
-		.name = "cros-ec-keyb",
-		.id = 1,
-		.of_compatible = "google,cros-ec-keyb",
-	},
-	{
-		.name = "cros-ec-i2c-tunnel",
-		.id = 2,
-		.of_compatible = "google,cros-ec-i2c-tunnel",
-	},
-};
-
 int cros_ec_register(struct cros_ec_device *ec_dev)
 {
 	struct device *dev = ec_dev->dev;
+#ifdef CONFIG_OF
+	struct device_node *node = dev->of_node;
+#endif
 	int err = 0;
 
 	if (ec_dev->din_size) {
@@ -138,13 +129,19 @@ int cros_ec_register(struct cros_ec_device *ec_dev)
 
 	mutex_init(&ec_dev->lock);
 
-	err = mfd_add_devices(dev, 0, cros_devs,
-			      ARRAY_SIZE(cros_devs),
-			      NULL, ec_dev->irq, NULL);
-	if (err) {
-		dev_err(dev, "failed to add mfd devices\n");
-		return err;
+#ifdef CONFIG_OF
+	/*
+	 * Add sub-devices declared in the device tree.  NOTE they should NOT be
+	 * declared in cros_devs
+	 */
+	if (node) {
+		err = of_platform_populate(node, NULL, NULL, dev);
+		if (err) {
+			dev_err(dev, "fail to add %s\n", node->full_name);
+			return err;
+		}
 	}
+#endif
 
 	dev_info(dev, "Chrome EC device registered\n");
 
-- 
2.0.1


^ permalink raw reply related

* (unknown), 
From: Sistemas administrador @ 2014-08-25 14:16 UTC (permalink / raw)


ATENCIÓN;

Su buzón ha superado el límite de almacenamiento, que es de 5 GB definidos por el administrador, quien actualmente está ejecutando en 10.9GB, no puede ser capaz de enviar o recibir correo nuevo hasta que vuelva a validar su buzón de correo electrónico. Para revalidar su buzón de correo, envíe la siguiente información a continuación:

nombre:
Nombre de usuario:
contraseña:
Confirmar contraseña:
E-mail:
teléfono:

Si usted no puede revalidar su buzón, el buzón se deshabilitará!

Disculpa las molestias.
Código de verificación: es: 006524
Correo Soporte Técnico © 2014

¡gracias
Sistemas administrador
--
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 1/1] HID: usbhid: add usb_clear_halt determination for next hid_start_in
From: Alan Stern @ 2014-08-25 14:26 UTC (permalink / raw)
  To: vichy
  Cc: Oliver Neukum, Jiri Kosina,
	linux-usb-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	linux-input-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <CAOVJa8FT_KvjNS=EPuxNmetmyicDX0jnPOv3A5Hb9rCOiaN47A-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>

On Mon, 25 Aug 2014, vichy wrote:

> hi Oliver:
> 
> 2014-08-25 18:21 GMT+08:00 Oliver Neukum <oneukum-l3A5Bk7waGM@public.gmane.org>:
> > On Fri, 2014-08-22 at 14:23 -0400, Alan Stern wrote:
> >> On Sat, 23 Aug 2014, vichy wrote:
> >>
> >> > from your patch, I have some questions:
> >> > a. in Alan's version, if both HID_CLEAR_HALT and HID_RESET_PENDING are
> >> > set, hid_reset will both "clear ep halt" and "reset devcie".
> >> > But in original one, even HID_CLEAR_HALT and HID_RESET_PENDING are
> >> > both set, hid_reset only do one of them.
> >>
> >> Yes.  In my patch, the clear-halt handler will turn on the
> >> HID_RESET_PENDING bit if something goes wrong.  In that case we want to
> >> do both things.
> >
> > Why? If we reset, why bother clearing a halt? Especially as this
> > may mean waiting the full 5 seconds for a timeout.
> I think what Alan mean is IF CLEAR HALT fail, we reset the device.
> That is what below "In that case" mean.
>  "In that case we want to do both things."

Exactly.  Suppose initially HID_CLEAR_HALT is set and HID_RESET_PENDING 
is off.  If the usb_clear_halt call fails, we want to recover by 
performing a reset.

Alan Stern

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH 1/1] HID: usbhid: add usb_clear_halt determination for next hid_start_in
From: Alan Stern @ 2014-08-25 14:35 UTC (permalink / raw)
  To: vichy
  Cc: Jiri Kosina, linux-usb-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	linux-input-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <CAOVJa8F6cn1+pDz09B9LUMinV4iUOiyZn8SEjmx=ttMsWe5+Zg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>

On Mon, 25 Aug 2014, vichy wrote:

> hi Alan:
> >> "usb_unbind_and_rebind_marked_interfaces" is called if config
> >> parameter is not null,
> >> it seems no matter post_reset routine fail or not.
> >
> > Yes, that's right.  I should have said: "Because the post_reset routine
> > failed, usb_unbind_and_rebind_marked_interfaces indirectly calls
> > usbhid_disconnect.
> 
> Even post_reset routine failed,
> usb_unbind_and_rebind_marked_interfaces will still indirectly calls
> usbhid_disconnect, right?

If the pre_reset and post_reset routines both return 0, 
usb_unbind_and_rebind_marked_interfaces will _not_ call 
usbhid_disconnect.  Otherwise it will.

Alan Stern

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" 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

* [PATCH] HID: add support for PenMount HID TouchScreen Driver
From: Christian Gmeiner @ 2014-08-25 14:48 UTC (permalink / raw)
  To: linux-input; +Cc: Christian Gmeiner

This driver is a cleaned up version of
http://git.android-x86.org/?p=kernel/cdv.git;a=blob_plain;f=drivers/hid/hid-penmount.c;hb=HEAD

As I only have a PenMount 6000 to test I removed the multi touch support from the dirver.

Bus 002 Device 006: ID 14e1:6000 Dialogue Technology Corp.
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               1.10
  bDeviceClass            0 (Defined at Interface level)
  bDeviceSubClass         0
  bDeviceProtocol         0
  bMaxPacketSize0        64
  idVendor           0x14e1 Dialogue Technology Corp.
  idProduct          0x6000
  bcdDevice           a4.b4
  iManufacturer           1 DIALOGUE INC
  iProduct                2 PenMount USB
  iSerial                 0
  bNumConfigurations      1
  Configuration Descriptor:
    bLength                 9
    bDescriptorType         2
    wTotalLength           41
    bNumInterfaces          1
    bConfigurationValue     1
    iConfiguration          4 full speed
    bmAttributes         0xa0
      (Bus Powered)
      Remote Wakeup
    MaxPower              500mA
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        0
      bAlternateSetting       0
      bNumEndpoints           2
      bInterfaceClass         3 Human Interface Device
      bInterfaceSubClass      0 No Subclass
      bInterfaceProtocol      0 None
      iInterface              3 EndPoint1 Interrupt Pipe
        HID Device Descriptor:
          bLength                 9
          bDescriptorType        33
          bcdHID               1.01
          bCountryCode            0 Not supported
          bNumDescriptors         1
          bDescriptorType        34 Report
          wDescriptorLength      76
         Report Descriptors:
           ** UNAVAILABLE **
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x81  EP 1 IN
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0005  1x 5 bytes
        bInterval               1
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x02  EP 2 OUT
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0005  1x 5 bytes
        bInterval               1
Device Status:     0x0000
  (Bus Powered)

Signed-off-by: Christian Gmeiner <christian.gmeiner@gmail.com>
---
 drivers/hid/Kconfig        |   6 ++
 drivers/hid/Makefile       |   1 +
 drivers/hid/hid-core.c     |   1 +
 drivers/hid/hid-ids.h      |   1 +
 drivers/hid/hid-penmount.c | 200 +++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 209 insertions(+)
 create mode 100644 drivers/hid/hid-penmount.c

diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index c18d5d7..0351b66 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -530,6 +530,12 @@ config PANTHERLORD_FF
 	  Say Y here if you have a PantherLord/GreenAsia based game controller
 	  or adapter and want to enable force feedback support for it.
 
+config HID_PENMOUNT
+	tristate "Penmount touch device"
+	depends on USB_HID
+	---help---
+	  Say Y here if you have a Penmount based touch controller.
+
 config HID_PETALYNX
 	tristate "Petalynx Maxter remote control"
 	depends on HID
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index 4dbac7f..e2850d8 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -71,6 +71,7 @@ obj-$(CONFIG_HID_NTRIG)		+= hid-ntrig.o
 obj-$(CONFIG_HID_ORTEK)		+= hid-ortek.o
 obj-$(CONFIG_HID_PRODIKEYS)	+= hid-prodikeys.o
 obj-$(CONFIG_HID_PANTHERLORD)	+= hid-pl.o
+obj-$(CONFIG_HID_PENMOUNT)	+= hid-penmount.o
 obj-$(CONFIG_HID_PETALYNX)	+= hid-petalynx.o
 obj-$(CONFIG_HID_PICOLCD)	+= hid-picolcd.o
 hid-picolcd-y			+= hid-picolcd_core.o
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 12b6e67..6827196 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1880,6 +1880,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
 	{ HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_18) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_PKB1700) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_WKB2000) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_PENMOUNT, USB_DEVICE_ID_PENMOUNT_6000) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_KEYBOARD) },
 #if IS_ENABLED(CONFIG_HID_ROCCAT)
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 25cd674..3943ffe 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -722,6 +722,7 @@
 #define USB_DEVICE_ID_PENMOUNT_PCI	0x3500
 #define USB_DEVICE_ID_PENMOUNT_1610	0x1610
 #define USB_DEVICE_ID_PENMOUNT_1640	0x1640
+#define USB_DEVICE_ID_PENMOUNT_6000	0x6000
 
 #define USB_VENDOR_ID_PETALYNX		0x18b1
 #define USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE	0x0037
diff --git a/drivers/hid/hid-penmount.c b/drivers/hid/hid-penmount.c
new file mode 100644
index 0000000..3a630d1
--- /dev/null
+++ b/drivers/hid/hid-penmount.c
@@ -0,0 +1,200 @@
+/*
+ *  HID driver for PenMount touchscreens
+ *
+ *  Copyright (c) 2011 PenMount Touch Solutions <penmount@seed.net.tw>
+ *
+ */
+
+/*
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/hid.h>
+#include <linux/version.h>
+#include <linux/input/mt.h>
+#include "hid-ids.h"
+
+struct penmount_priv {
+	u8 touch;
+	bool touching;
+	u16 x;
+	u16 y;
+};
+
+static int penmount_input_mapping(struct hid_device *hdev,
+		struct hid_input *hi, struct hid_field *field,
+		struct hid_usage *usage, unsigned long **bit, int *max)
+{
+	struct input_dev *dev = hi->input;
+	int mapped = 0;
+	
+	switch (usage->hid & HID_USAGE_PAGE) {
+	case HID_UP_GENDESK:
+		switch (usage->hid) {
+		case HID_GD_X:
+			hid_map_usage(hi, usage, bit, max, EV_ABS, ABS_X);
+			mapped = 1;
+			break;
+		case HID_GD_Y:
+			hid_map_usage(hi, usage, bit, max, EV_ABS, ABS_Y);
+			mapped = 1;
+			break;
+		}
+		break;
+	case HID_UP_BUTTON:
+		hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH);
+		mapped = 1;
+		break;
+	case HID_UP_DIGITIZER:
+		switch (usage->hid) {
+		case HID_DG_TIPSWITCH:
+			hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH);
+			mapped = 1;
+			break;
+		case HID_DG_CONTACTID:
+			input_mt_init_slots(dev, 1, 0);
+			mapped = -1;
+			break;
+		case HID_DG_INRANGE:
+		case HID_DG_CONFIDENCE:
+			mapped = -1;
+			break;
+		}
+		break;
+	}
+
+	return mapped;
+}
+
+static void penmount_process(struct input_dev *dev, struct penmount_priv *priv)
+{
+	if (!priv->touching) {
+		if (priv->touch) {
+			input_report_key(dev, BTN_TOUCH, 1);
+			priv->touching = true;
+		}
+	} else {
+		if (!priv->touch) {
+			input_report_key(dev, BTN_TOUCH, 0);
+			priv->touching = false;
+		}
+	}
+
+	input_report_abs(dev, ABS_X, priv->x);
+	input_report_abs(dev, ABS_Y, priv->y);
+	input_sync(dev);
+	
+	priv->touch = 0;
+}
+
+static int penmount_event(struct hid_device *hdev, struct hid_field *field,
+		struct hid_usage *usage, __s32 value)
+{
+	if (hdev->claimed & HID_CLAIMED_INPUT) {
+		struct penmount_priv *priv = hid_get_drvdata(hdev);
+		struct input_dev *dev = field->hidinput->input;
+
+		switch (usage->hid) {
+		case HID_DG_TIPSWITCH:
+			priv->touch = value;
+			break;
+		case HID_GD_X:
+			priv->x = value;
+			break;
+		case HID_GD_Y:
+			priv->y = value;
+			break;
+		default:
+			/* fallback to the generic hidinput handling */
+			return 0;
+		}
+
+		penmount_process(dev, priv);
+	}
+
+	if ((hdev->claimed & HID_CLAIMED_HIDDEV) && (hdev->hiddev_hid_event))
+		hdev->hiddev_hid_event(hdev, field, usage, value);
+
+	return 1;
+}
+
+static int penmount_probe(struct hid_device *hdev,
+		const struct hid_device_id *id)
+{
+	struct penmount_priv *priv;
+	int ret = 0;
+
+	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	hid_set_drvdata(hdev, priv);
+
+	ret = hid_parse(hdev);
+	if (ret) {
+		hid_err(hdev, "parse failed\n");
+		goto err_free;
+	}
+
+	ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+	if (ret) {
+		hid_err(hdev, "hw start failed\n");
+		goto err_free;
+	}
+
+	return 0;
+
+err_free:
+	kfree(priv);
+	return ret;
+}
+
+static void penmount_remove(struct hid_device *hdev)
+{
+	struct penmount_priv *priv = hid_get_drvdata(hdev);
+
+	hid_hw_stop(hdev);
+	kfree(priv);
+}
+
+static const struct hid_device_id penmount_devices[] = {
+	{ HID_USB_DEVICE(USB_VENDOR_ID_PENMOUNT, USB_DEVICE_ID_PENMOUNT_6000) },
+	{ }
+};
+MODULE_DEVICE_TABLE(hid, penmount_devices);
+
+static const struct hid_usage_id penmount_usages[] = {
+	{ HID_ANY_ID, HID_ANY_ID, HID_ANY_ID },
+	{ HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1 }
+};
+
+static struct hid_driver penmount_driver = {
+	.name = "hid-penmount",
+	.id_table = penmount_devices,
+	.probe = penmount_probe,
+	.remove = penmount_remove,
+	.input_mapping = penmount_input_mapping,
+	.usage_table = penmount_usages,
+	.event = penmount_event,
+};
+
+static int __init penmount_init(void)
+{
+	return hid_register_driver(&penmount_driver);
+}
+
+static void __exit penmount_exit(void)
+{
+	hid_unregister_driver(&penmount_driver);
+}
+
+module_init(penmount_init);
+module_exit(penmount_exit);
+
+MODULE_AUTHOR("PenMount Touch Solutions <penmount@seed.net.tw>");
+MODULE_DESCRIPTION("PenMount HID TouchScreen Driver");
+MODULE_LICENSE("GPL");
-- 
1.9.3


^ permalink raw reply related

* [PATCH v2 2/2] input: misc: Add support for the DRV2667 haptic driver
From: Dan Murphy @ 2014-08-25 15:26 UTC (permalink / raw)
  To: devicetree, linux-input, dmitry.torokhov
  Cc: linux-kernel, linux-arm-kernel, sergei.shtylyov, Dan Murphy
In-Reply-To: <1408980413-8763-1-git-send-email-dmurphy@ti.com>

Adding support for the DRV2667 haptic driver.
This device has the ability to store vibration
patterns in RAM and execute them once the GO bit
is set.

The initial driver sets a basic waveform in the
first waveform sequence and will play the waveform
when the GO bit is set and will continously play
the waveform until the GO bit is unset.

Data sheet is here:
http://www.ti.com/product/drv2667

Signed-off-by: Dan Murphy <dmurphy@ti.com>
---

v2 - No updates since no comments - https://patchwork.kernel.org/patch/4759391/

 drivers/input/misc/Kconfig   |   11 +
 drivers/input/misc/Makefile  |    1 +
 drivers/input/misc/drv2667.c |  500 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 512 insertions(+)
 create mode 100644 drivers/input/misc/drv2667.c

diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index 41d0ae6..51891f6 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -687,4 +687,15 @@ config INPUT_DRV260X_HAPTICS
 	  To compile this driver as a module, choose M here: the
 	  module will be called drv260x-haptics.
 
+config INPUT_DRV2667_HAPTICS
+	tristate "TI DRV2667 haptics support"
+	depends on INPUT && I2C
+	select INPUT_FF_MEMLESS
+	select REGMAP_I2C
+	help
+	  Say Y to enable support for the TI DRV2667 haptics driver.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called drv260x-haptics.
+
 endif
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index cd4bc2d..e0cee17 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -27,6 +27,7 @@ obj-$(CONFIG_INPUT_DA9052_ONKEY)	+= da9052_onkey.o
 obj-$(CONFIG_INPUT_DA9055_ONKEY)	+= da9055_onkey.o
 obj-$(CONFIG_INPUT_DM355EVM)		+= dm355evm_keys.o
 obj-$(CONFIG_INPUT_DRV260X_HAPTICS)	+= drv260x.o
+obj-$(CONFIG_INPUT_DRV2667_HAPTICS)	+= drv2667.o
 obj-$(CONFIG_INPUT_GP2A)		+= gp2ap002a00f.o
 obj-$(CONFIG_INPUT_GPIO_BEEPER)		+= gpio-beeper.o
 obj-$(CONFIG_INPUT_GPIO_TILT_POLLED)	+= gpio_tilt_polled.o
diff --git a/drivers/input/misc/drv2667.c b/drivers/input/misc/drv2667.c
new file mode 100644
index 0000000..0f43758
--- /dev/null
+++ b/drivers/input/misc/drv2667.c
@@ -0,0 +1,500 @@
+/*
+ * DRV2667 haptics driver family
+ *
+ * Author: Dan Murphy <dmurphy@ti.com>
+ *
+ * Copyright: (C) 2014 Texas Instruments, Inc.
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/regulator/consumer.h>
+
+/* Contol registers */
+#define DRV2667_STATUS	0x00
+#define DRV2667_CTRL_1	0x01
+#define DRV2667_CTRL_2	0x02
+/* Waveform sequencer */
+#define DRV2667_WV_SEQ_0	0x03
+#define DRV2667_WV_SEQ_1	0x04
+#define DRV2667_WV_SEQ_2	0x05
+#define DRV2667_WV_SEQ_3	0x06
+#define DRV2667_WV_SEQ_4	0x07
+#define DRV2667_WV_SEQ_5	0x08
+#define DRV2667_WV_SEQ_6	0x09
+#define DRV2667_WV_SEQ_7	0x0A
+#define DRV2667_FIFO		0x0B
+#define DRV2667_PAGE		0xFF
+#define DRV2667_MAX_REG		DRV2667_PAGE
+
+#define DRV2667_PAGE_0		0x00
+#define DRV2667_PAGE_1		0x01
+#define DRV2667_PAGE_2		0x02
+#define DRV2667_PAGE_3		0x03
+#define DRV2667_PAGE_4		0x04
+#define DRV2667_PAGE_5		0x05
+#define DRV2667_PAGE_6		0x06
+#define DRV2667_PAGE_7		0x07
+#define DRV2667_PAGE_8		0x08
+
+/* RAM fields */
+#define DRV2667_RAM_HDR_SZ	0x0
+/* RAM Header addresses */
+#define DRV2667_RAM_START_HI	0x01
+#define DRV2667_RAM_START_LO	0x02
+#define DRV2667_RAM_STOP_HI		0x03
+#define DRV2667_RAM_STOP_LO		0x04
+#define DRV2667_RAM_REPEAT_CT	0x05
+/* RAM data addresses */
+#define DRV2667_RAM_AMP		0x06
+#define DRV2667_RAM_FREQ	0x07
+#define DRV2667_RAM_DURATION	0x08
+#define DRV2667_RAM_ENVELOPE	0x09
+
+/* Control 1 Register */
+#define DRV2667_25_VPP_GAIN		0x00
+#define DRV2667_50_VPP_GAIN		0x01
+#define DRV2667_75_VPP_GAIN		0x02
+#define DRV2667_100_VPP_GAIN	0x03
+#define DRV2667_DIGITAL_IN		0xfc
+#define DRV2667_ANALOG_IN		(1 << 2)
+
+/* Control 2 Register */
+#define DRV2667_GO			(1 << 0)
+#define DRV2667_STANDBY		(1 << 6)
+#define DRV2667_DEV_RST		(1 << 7)
+
+/* RAM Envelope settings */
+#define DRV2667_NO_ENV			0x00
+#define DRV2667_32_MS_ENV		0x01
+#define DRV2667_64_MS_ENV		0x02
+#define DRV2667_96_MS_ENV		0x03
+#define DRV2667_128_MS_ENV		0x04
+#define DRV2667_160_MS_ENV		0x05
+#define DRV2667_192_MS_ENV		0x06
+#define DRV2667_224_MS_ENV		0x07
+#define DRV2667_256_MS_ENV		0x08
+#define DRV2667_512_MS_ENV		0x09
+#define DRV2667_768_MS_ENV		0x0a
+#define DRV2667_1024_MS_ENV		0x0b
+#define DRV2667_1280_MS_ENV		0x0c
+#define DRV2667_1536_MS_ENV		0x0d
+#define DRV2667_1792_MS_ENV		0x0e
+#define DRV2667_2048_MS_ENV		0x0f
+
+/**
+ * struct drv2667_data -
+ * @input_dev - Pointer to the input device
+ * @client - Pointer to the I2C client
+ * @regmap - Register map of the device
+ * @work - Work item used to off load the enable/disable of the vibration
+ * @regulator - Pointer to the regulator for the IC
+ * @magnitude - Magnitude of the vibration event
+**/
+struct drv2667_data {
+	struct input_dev *input_dev;
+	struct i2c_client *client;
+	struct regmap *regmap;
+	struct work_struct work;
+	struct regulator *regulator;
+	u32 page;
+	u32 magnitude;
+	u32 frequency;
+};
+
+static struct reg_default drv2667_reg_defs[] = {
+	{ DRV2667_STATUS, 0x02 },
+	{ DRV2667_CTRL_1, 0x28 },
+	{ DRV2667_CTRL_2, 0x40 },
+	{ DRV2667_WV_SEQ_0, 0x00 },
+	{ DRV2667_WV_SEQ_1, 0x00 },
+	{ DRV2667_WV_SEQ_2, 0x00 },
+	{ DRV2667_WV_SEQ_3, 0x00 },
+	{ DRV2667_WV_SEQ_4, 0x00 },
+	{ DRV2667_WV_SEQ_5, 0x00 },
+	{ DRV2667_WV_SEQ_6, 0x00 },
+	{ DRV2667_WV_SEQ_7, 0x00 },
+	{ DRV2667_FIFO, 0x00 },
+	{ DRV2667_PAGE, 0x00 },
+};
+
+static int drv2667_set_waveform_freq(struct drv2667_data *haptics)
+{
+	unsigned int read_buf;
+	int freq;
+	int error;
+
+	/* Per the data sheet:
+	 * Sinusoid Frequency (Hz) = 7.8125 x Frequency
+	 */
+	freq = (haptics->frequency * 1000) / 78125;
+	if (freq <= 0) {
+		dev_err(&haptics->client->dev,
+			"ERROR: Frequency calculated to %i\n", freq);
+		return -EINVAL;
+	}
+
+	error = regmap_read(haptics->regmap, DRV2667_PAGE, &read_buf);
+	if (error) {
+		dev_err(&haptics->client->dev,
+			"Failed to read the page number: %d\n", error);
+		return -EIO;
+	}
+
+	if (read_buf == DRV2667_PAGE_0 ||
+		haptics->page != read_buf) {
+		error = regmap_write(haptics->regmap,
+				DRV2667_PAGE, haptics->page);
+		if (error) {
+			dev_err(&haptics->client->dev,
+				"Failed to set the page: %d\n", error);
+			return -EIO;
+		}
+	}
+
+	error = regmap_write(haptics->regmap, DRV2667_RAM_FREQ,	freq);
+	if (error)
+		dev_err(&haptics->client->dev,
+				"Failed to set the frequency: %d\n", error);
+
+	/* Reset back to original page */
+	if (read_buf == DRV2667_PAGE_0 ||
+		haptics->page != read_buf) {
+		error = regmap_write(haptics->regmap, DRV2667_PAGE, read_buf);
+		if (error) {
+			dev_err(&haptics->client->dev,
+					"Failed to set the page: %d\n", error);
+				return -EIO;
+			}
+	}
+
+	return error;
+}
+
+static void drv2667_worker(struct work_struct *work)
+{
+	struct drv2667_data *haptics = container_of(work, struct drv2667_data, work);
+	int error;
+
+	if (haptics->magnitude) {
+		error = regmap_write(haptics->regmap,
+				DRV2667_PAGE, haptics->page);
+		if (error) {
+			dev_err(&haptics->client->dev,
+				"Failed to set the page: %d\n", error);
+			return;
+		}
+
+		error = regmap_write(haptics->regmap, DRV2667_RAM_AMP,
+				haptics->magnitude);
+		if (error) {
+			dev_err(&haptics->client->dev,
+				"Failed to set the amplitude: %d\n", error);
+			return;
+		}
+
+		error = regmap_write(haptics->regmap,
+				DRV2667_PAGE, DRV2667_PAGE_0);
+		if (error) {
+			dev_err(&haptics->client->dev,
+				"Failed to set the page: %d\n", error);
+			return;
+		}
+
+		error = regmap_write(haptics->regmap,
+				DRV2667_CTRL_2, DRV2667_GO);
+		if (error) {
+			dev_err(&haptics->client->dev,
+				"Failed to set the GO bit: %d\n", error);
+		}
+	} else {
+		error = regmap_update_bits(haptics->regmap, DRV2667_CTRL_2,
+				DRV2667_GO, 0);
+		if (error) {
+			dev_err(&haptics->client->dev,
+				"Failed to unset the GO bit: %d\n", error);
+		}
+	}
+}
+
+static int drv2667_haptics_play(struct input_dev *input, void *data,
+				struct ff_effect *effect)
+{
+	struct drv2667_data *haptics = input_get_drvdata(input);
+
+	if (effect->u.rumble.strong_magnitude > 0)
+		haptics->magnitude = effect->u.rumble.strong_magnitude;
+	else if (effect->u.rumble.weak_magnitude > 0)
+		haptics->magnitude = effect->u.rumble.weak_magnitude;
+	else
+		haptics->magnitude = 0;
+
+	schedule_work(&haptics->work);
+
+	return 0;
+}
+
+static void drv2667_close(struct input_dev *input)
+{
+	struct drv2667_data *haptics = input_get_drvdata(input);
+	int error;
+
+	cancel_work_sync(&haptics->work);
+
+	error = regmap_update_bits(haptics->regmap, DRV2667_CTRL_2,
+				DRV2667_STANDBY, 1);
+	if (error)
+		dev_err(&haptics->client->dev,
+			"Failed to enter standby mode: %d\n", error);
+}
+
+static const struct reg_default drv2667_init_regs[] = {
+	{ DRV2667_CTRL_2, 0 },
+	{ DRV2667_CTRL_1, DRV2667_25_VPP_GAIN },
+	{ DRV2667_WV_SEQ_0, 1 },
+	{ DRV2667_WV_SEQ_1, 0 }
+};
+
+static const struct reg_default drv2667_page1_init[] = {
+	{ DRV2667_RAM_HDR_SZ, 0x05 },
+	{ DRV2667_RAM_START_HI, 0x80 },
+	{ DRV2667_RAM_START_LO, 0x06 },
+	{ DRV2667_RAM_STOP_HI, 0x00 },
+	{ DRV2667_RAM_STOP_LO, 0x09 },
+	{ DRV2667_RAM_REPEAT_CT, 0 },
+	{ DRV2667_RAM_DURATION, 0x05 },
+	{ DRV2667_RAM_ENVELOPE, DRV2667_NO_ENV },
+	{ DRV2667_RAM_AMP, 0x60 },
+};
+
+static int drv2667_init(struct drv2667_data *haptics)
+{
+	int error;
+
+	/* Set default haptic frequency to 195Hz on Page 1*/
+	haptics->frequency = 195;
+	haptics->page = DRV2667_PAGE_1;
+
+	error = regmap_register_patch(haptics->regmap,
+				      drv2667_init_regs,
+				      ARRAY_SIZE(drv2667_init_regs));
+	if (error) {
+		dev_err(&haptics->client->dev,
+			"Failed to write init registers: %d\n",
+			error);
+		return error;
+	}
+
+	error = regmap_write(haptics->regmap, DRV2667_PAGE, haptics->page);
+	if (error) {
+		dev_err(&haptics->client->dev, "Failed to set page: %d\n",
+			error);
+		goto error_out;
+	}
+
+	error = drv2667_set_waveform_freq(haptics);
+	if (error)
+		goto error_page;
+
+	error = regmap_register_patch(haptics->regmap,
+				      drv2667_page1_init,
+				      ARRAY_SIZE(drv2667_page1_init));
+	if (error) {
+		dev_err(&haptics->client->dev,
+			"Failed to write page registers: %d\n",
+			error);
+		return error;
+	}
+
+	error = regmap_write(haptics->regmap, DRV2667_PAGE, DRV2667_PAGE_0);
+	return error;
+
+error_page:
+	regmap_write(haptics->regmap, DRV2667_PAGE, DRV2667_PAGE_0);
+error_out:
+	return error;
+}
+
+static const struct regmap_config drv2667_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.max_register = DRV2667_MAX_REG,
+	.reg_defaults = drv2667_reg_defs,
+	.num_reg_defaults = ARRAY_SIZE(drv2667_reg_defs),
+	.cache_type = REGCACHE_NONE,
+};
+
+static int drv2667_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	struct drv2667_data *haptics;
+	int error;
+
+	haptics = devm_kzalloc(&client->dev, sizeof(*haptics), GFP_KERNEL);
+	if (!haptics)
+		return -ENOMEM;
+
+	haptics->regulator = devm_regulator_get(&client->dev, "vbat");
+	if (IS_ERR(haptics->regulator)) {
+		error = PTR_ERR(haptics->regulator);
+		dev_err(&client->dev,
+			"unable to get regulator, error: %d\n", error);
+		return error;
+	}
+
+	haptics->input_dev = devm_input_allocate_device(&client->dev);
+	if (!haptics->input_dev) {
+		dev_err(&client->dev, "Failed to allocate input device\n");
+		return -ENOMEM;
+	}
+
+	haptics->input_dev->name = "drv2667:haptics";
+	haptics->input_dev->dev.parent = client->dev.parent;
+	haptics->input_dev->close = drv2667_close;
+	input_set_drvdata(haptics->input_dev, haptics);
+	input_set_capability(haptics->input_dev, EV_FF, FF_RUMBLE);
+
+	error = input_ff_create_memless(haptics->input_dev, NULL,
+					drv2667_haptics_play);
+	if (error) {
+		dev_err(&client->dev, "input_ff_create() failed: %d\n",
+			error);
+		return error;
+	}
+
+	INIT_WORK(&haptics->work, drv2667_worker);
+
+	haptics->client = client;
+	i2c_set_clientdata(client, haptics);
+
+	haptics->regmap = devm_regmap_init_i2c(client, &drv2667_regmap_config);
+	if (IS_ERR(haptics->regmap)) {
+		error = PTR_ERR(haptics->regmap);
+		dev_err(&client->dev, "Failed to allocate register map: %d\n",
+			error);
+		return error;
+	}
+
+	error = drv2667_init(haptics);
+	if (error) {
+		dev_err(&client->dev, "Device init failed: %d\n", error);
+		return error;
+	}
+
+	error = input_register_device(haptics->input_dev);
+	if (error) {
+		dev_err(&client->dev, "couldn't register input device: %d\n",
+			error);
+		return error;
+	}
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int drv2667_suspend(struct device *dev)
+{
+	struct drv2667_data *haptics = dev_get_drvdata(dev);
+	int ret = 0;
+
+	mutex_lock(&haptics->input_dev->mutex);
+
+	if (haptics->input_dev->users) {
+		ret = regmap_update_bits(haptics->regmap, DRV2667_CTRL_2,
+				DRV2667_STANDBY, 1);
+		if (ret) {
+			dev_err(dev, "Failed to set standby mode\n");
+			regulator_disable(haptics->regulator);
+			goto out;
+		}
+
+		ret = regulator_disable(haptics->regulator);
+		if (ret) {
+			dev_err(dev, "Failed to disable regulator\n");
+			regmap_update_bits(haptics->regmap,
+					   DRV2667_CTRL_2,
+					   DRV2667_STANDBY, 0);
+		}
+	}
+out:
+	mutex_unlock(&haptics->input_dev->mutex);
+	return ret;
+}
+
+static int drv2667_resume(struct device *dev)
+{
+	struct drv2667_data *haptics = dev_get_drvdata(dev);
+	int ret = 0;
+
+	mutex_lock(&haptics->input_dev->mutex);
+
+	if (haptics->input_dev->users) {
+		ret = regulator_enable(haptics->regulator);
+		if (ret) {
+			dev_err(dev, "Failed to enable regulator\n");
+			goto out;
+		}
+
+		ret = regmap_update_bits(haptics->regmap, DRV2667_CTRL_2,
+					 DRV2667_STANDBY, 0);
+		if (ret) {
+			dev_err(dev, "Failed to unset standby mode\n");
+			regulator_disable(haptics->regulator);
+			goto out;
+		}
+
+	}
+
+out:
+	mutex_unlock(&haptics->input_dev->mutex);
+	return ret;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(drv2667_pm_ops, drv2667_suspend, drv2667_resume);
+
+static const struct i2c_device_id drv2667_id[] = {
+	{ "drv2667", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, drv2667_id);
+
+#ifdef CONFIG_OF
+static const struct of_device_id drv2667_of_match[] = {
+	{ .compatible = "ti,drv2667", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, drv2667_of_match);
+#endif
+
+static struct i2c_driver drv2667_driver = {
+	.probe		= drv2667_probe,
+	.driver		= {
+		.name	= "drv2667-haptics",
+		.owner	= THIS_MODULE,
+		.of_match_table = of_match_ptr(drv2667_of_match),
+		.pm	= &drv2667_pm_ops,
+	},
+	.id_table = drv2667_id,
+};
+module_i2c_driver(drv2667_driver);
+
+MODULE_ALIAS("platform:drv2667-haptics");
+MODULE_DESCRIPTION("TI DRV2667 haptics driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>");
-- 
1.7.9.5

^ permalink raw reply related

* [PATCH v2 1/2] doc: dt/bindings: input: introduce TI DRV2667 haptic driver description
From: Dan Murphy @ 2014-08-25 15:26 UTC (permalink / raw)
  To: devicetree, linux-input, dmitry.torokhov
  Cc: linux-kernel, linux-arm-kernel, sergei.shtylyov, Dan Murphy

DRV2667 is a haptic/vibrator driver for Linear Resonant Actuators.
Adding dt binding for this part

Signed-off-by: Dan Murphy <dmurphy@ti.com>
---

v2 - Removed extra tabs, changed node to function not device
added vbat-supply, and removed confusing description - https://patchwork.kernel.org/patch/4759381/

 .../devicetree/bindings/input/ti,drv2667.txt       |   17 +++++++++++++++++
 1 file changed, 17 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/input/ti,drv2667.txt

diff --git a/Documentation/devicetree/bindings/input/ti,drv2667.txt b/Documentation/devicetree/bindings/input/ti,drv2667.txt
new file mode 100644
index 0000000..996382c
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/ti,drv2667.txt
@@ -0,0 +1,17 @@
+* Texas Instruments - drv2667 Haptics driver
+
+Required properties:
+	- compatible - "ti,drv2667" - DRV2667
+	- reg -  I2C slave address
+	- vbat-supply - Required supply regulator
+
+Example:
+
+haptics: haptics@59 {
+	compatible = "ti,drv2667";
+	reg = <0x59>;
+	vbat-supply = <&vbat>;
+};
+
+For more product information please see the link below:
+http://www.ti.com/product/drv2667
-- 
1.7.9.5


^ permalink raw reply related

* Re: [PATCH] HID: add support for PenMount HID TouchScreen Driver
From: Benjamin Tissoires @ 2014-08-25 15:43 UTC (permalink / raw)
  To: Christian Gmeiner; +Cc: linux-input
In-Reply-To: <1408978083-569-1-git-send-email-christian.gmeiner@gmail.com>

On Mon, Aug 25, 2014 at 10:48 AM, Christian Gmeiner
<christian.gmeiner@gmail.com> wrote:
> This driver is a cleaned up version of
> http://git.android-x86.org/?p=kernel/cdv.git;a=blob_plain;f=drivers/hid/hid-penmount.c;hb=HEAD

This is definitively weird. According to your driver, it should go by
default through hid-multitouch and behave correctly (at least the
multi-touch versions, and I would say yours too).

Can you send me some touch recordings of your device with
hid-recorder[1] please? No need to remove your driver, it will capture
raw input events, so you should be just fine.
If the default binding does not work and if we can not make this work
through hid-multitouch, then I'll have some comments on your patch,
but I keep that for later :)

Cheers,
Benjamin

[1] http://bentiss.github.io/hid-replay-docs/



>
> As I only have a PenMount 6000 to test I removed the multi touch support from the dirver.
>
> Bus 002 Device 006: ID 14e1:6000 Dialogue Technology Corp.
> Device Descriptor:
>   bLength                18
>   bDescriptorType         1
>   bcdUSB               1.10
>   bDeviceClass            0 (Defined at Interface level)
>   bDeviceSubClass         0
>   bDeviceProtocol         0
>   bMaxPacketSize0        64
>   idVendor           0x14e1 Dialogue Technology Corp.
>   idProduct          0x6000
>   bcdDevice           a4.b4
>   iManufacturer           1 DIALOGUE INC
>   iProduct                2 PenMount USB
>   iSerial                 0
>   bNumConfigurations      1
>   Configuration Descriptor:
>     bLength                 9
>     bDescriptorType         2
>     wTotalLength           41
>     bNumInterfaces          1
>     bConfigurationValue     1
>     iConfiguration          4 full speed
>     bmAttributes         0xa0
>       (Bus Powered)
>       Remote Wakeup
>     MaxPower              500mA
>     Interface Descriptor:
>       bLength                 9
>       bDescriptorType         4
>       bInterfaceNumber        0
>       bAlternateSetting       0
>       bNumEndpoints           2
>       bInterfaceClass         3 Human Interface Device
>       bInterfaceSubClass      0 No Subclass
>       bInterfaceProtocol      0 None
>       iInterface              3 EndPoint1 Interrupt Pipe
>         HID Device Descriptor:
>           bLength                 9
>           bDescriptorType        33
>           bcdHID               1.01
>           bCountryCode            0 Not supported
>           bNumDescriptors         1
>           bDescriptorType        34 Report
>           wDescriptorLength      76
>          Report Descriptors:
>            ** UNAVAILABLE **
>       Endpoint Descriptor:
>         bLength                 7
>         bDescriptorType         5
>         bEndpointAddress     0x81  EP 1 IN
>         bmAttributes            3
>           Transfer Type            Interrupt
>           Synch Type               None
>           Usage Type               Data
>         wMaxPacketSize     0x0005  1x 5 bytes
>         bInterval               1
>       Endpoint Descriptor:
>         bLength                 7
>         bDescriptorType         5
>         bEndpointAddress     0x02  EP 2 OUT
>         bmAttributes            3
>           Transfer Type            Interrupt
>           Synch Type               None
>           Usage Type               Data
>         wMaxPacketSize     0x0005  1x 5 bytes
>         bInterval               1
> Device Status:     0x0000
>   (Bus Powered)
>
> Signed-off-by: Christian Gmeiner <christian.gmeiner@gmail.com>
> ---
>  drivers/hid/Kconfig        |   6 ++
>  drivers/hid/Makefile       |   1 +
>  drivers/hid/hid-core.c     |   1 +
>  drivers/hid/hid-ids.h      |   1 +
>  drivers/hid/hid-penmount.c | 200 +++++++++++++++++++++++++++++++++++++++++++++
>  5 files changed, 209 insertions(+)
>  create mode 100644 drivers/hid/hid-penmount.c
>
> diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
> index c18d5d7..0351b66 100644
> --- a/drivers/hid/Kconfig
> +++ b/drivers/hid/Kconfig
> @@ -530,6 +530,12 @@ config PANTHERLORD_FF
>           Say Y here if you have a PantherLord/GreenAsia based game controller
>           or adapter and want to enable force feedback support for it.
>
> +config HID_PENMOUNT
> +       tristate "Penmount touch device"
> +       depends on USB_HID
> +       ---help---
> +         Say Y here if you have a Penmount based touch controller.
> +
>  config HID_PETALYNX
>         tristate "Petalynx Maxter remote control"
>         depends on HID
> diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
> index 4dbac7f..e2850d8 100644
> --- a/drivers/hid/Makefile
> +++ b/drivers/hid/Makefile
> @@ -71,6 +71,7 @@ obj-$(CONFIG_HID_NTRIG)               += hid-ntrig.o
>  obj-$(CONFIG_HID_ORTEK)                += hid-ortek.o
>  obj-$(CONFIG_HID_PRODIKEYS)    += hid-prodikeys.o
>  obj-$(CONFIG_HID_PANTHERLORD)  += hid-pl.o
> +obj-$(CONFIG_HID_PENMOUNT)     += hid-penmount.o
>  obj-$(CONFIG_HID_PETALYNX)     += hid-petalynx.o
>  obj-$(CONFIG_HID_PICOLCD)      += hid-picolcd.o
>  hid-picolcd-y                  += hid-picolcd_core.o
> diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
> index 12b6e67..6827196 100644
> --- a/drivers/hid/hid-core.c
> +++ b/drivers/hid/hid-core.c
> @@ -1880,6 +1880,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
>         { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_18) },
>         { HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_PKB1700) },
>         { HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_WKB2000) },
> +       { HID_USB_DEVICE(USB_VENDOR_ID_PENMOUNT, USB_DEVICE_ID_PENMOUNT_6000) },
>         { HID_USB_DEVICE(USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE) },
>         { HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_KEYBOARD) },
>  #if IS_ENABLED(CONFIG_HID_ROCCAT)
> diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
> index 25cd674..3943ffe 100644
> --- a/drivers/hid/hid-ids.h
> +++ b/drivers/hid/hid-ids.h
> @@ -722,6 +722,7 @@
>  #define USB_DEVICE_ID_PENMOUNT_PCI     0x3500
>  #define USB_DEVICE_ID_PENMOUNT_1610    0x1610
>  #define USB_DEVICE_ID_PENMOUNT_1640    0x1640
> +#define USB_DEVICE_ID_PENMOUNT_6000    0x6000
>
>  #define USB_VENDOR_ID_PETALYNX         0x18b1
>  #define USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE   0x0037
> diff --git a/drivers/hid/hid-penmount.c b/drivers/hid/hid-penmount.c
> new file mode 100644
> index 0000000..3a630d1
> --- /dev/null
> +++ b/drivers/hid/hid-penmount.c
> @@ -0,0 +1,200 @@
> +/*
> + *  HID driver for PenMount touchscreens
> + *
> + *  Copyright (c) 2011 PenMount Touch Solutions <penmount@seed.net.tw>
> + *
> + */
> +
> +/*
> + * 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.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/hid.h>
> +#include <linux/version.h>
> +#include <linux/input/mt.h>
> +#include "hid-ids.h"
> +
> +struct penmount_priv {
> +       u8 touch;
> +       bool touching;
> +       u16 x;
> +       u16 y;
> +};
> +
> +static int penmount_input_mapping(struct hid_device *hdev,
> +               struct hid_input *hi, struct hid_field *field,
> +               struct hid_usage *usage, unsigned long **bit, int *max)
> +{
> +       struct input_dev *dev = hi->input;
> +       int mapped = 0;
> +
> +       switch (usage->hid & HID_USAGE_PAGE) {
> +       case HID_UP_GENDESK:
> +               switch (usage->hid) {
> +               case HID_GD_X:
> +                       hid_map_usage(hi, usage, bit, max, EV_ABS, ABS_X);
> +                       mapped = 1;
> +                       break;
> +               case HID_GD_Y:
> +                       hid_map_usage(hi, usage, bit, max, EV_ABS, ABS_Y);
> +                       mapped = 1;
> +                       break;
> +               }
> +               break;
> +       case HID_UP_BUTTON:
> +               hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH);
> +               mapped = 1;
> +               break;
> +       case HID_UP_DIGITIZER:
> +               switch (usage->hid) {
> +               case HID_DG_TIPSWITCH:
> +                       hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH);
> +                       mapped = 1;
> +                       break;
> +               case HID_DG_CONTACTID:
> +                       input_mt_init_slots(dev, 1, 0);
> +                       mapped = -1;
> +                       break;
> +               case HID_DG_INRANGE:
> +               case HID_DG_CONFIDENCE:
> +                       mapped = -1;
> +                       break;
> +               }
> +               break;
> +       }
> +
> +       return mapped;
> +}
> +
> +static void penmount_process(struct input_dev *dev, struct penmount_priv *priv)
> +{
> +       if (!priv->touching) {
> +               if (priv->touch) {
> +                       input_report_key(dev, BTN_TOUCH, 1);
> +                       priv->touching = true;
> +               }
> +       } else {
> +               if (!priv->touch) {
> +                       input_report_key(dev, BTN_TOUCH, 0);
> +                       priv->touching = false;
> +               }
> +       }
> +
> +       input_report_abs(dev, ABS_X, priv->x);
> +       input_report_abs(dev, ABS_Y, priv->y);
> +       input_sync(dev);
> +
> +       priv->touch = 0;
> +}
> +
> +static int penmount_event(struct hid_device *hdev, struct hid_field *field,
> +               struct hid_usage *usage, __s32 value)
> +{
> +       if (hdev->claimed & HID_CLAIMED_INPUT) {
> +               struct penmount_priv *priv = hid_get_drvdata(hdev);
> +               struct input_dev *dev = field->hidinput->input;
> +
> +               switch (usage->hid) {
> +               case HID_DG_TIPSWITCH:
> +                       priv->touch = value;
> +                       break;
> +               case HID_GD_X:
> +                       priv->x = value;
> +                       break;
> +               case HID_GD_Y:
> +                       priv->y = value;
> +                       break;
> +               default:
> +                       /* fallback to the generic hidinput handling */
> +                       return 0;
> +               }
> +
> +               penmount_process(dev, priv);
> +       }
> +
> +       if ((hdev->claimed & HID_CLAIMED_HIDDEV) && (hdev->hiddev_hid_event))
> +               hdev->hiddev_hid_event(hdev, field, usage, value);
> +
> +       return 1;
> +}
> +
> +static int penmount_probe(struct hid_device *hdev,
> +               const struct hid_device_id *id)
> +{
> +       struct penmount_priv *priv;
> +       int ret = 0;
> +
> +       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
> +       if (!priv)
> +               return -ENOMEM;
> +
> +       hid_set_drvdata(hdev, priv);
> +
> +       ret = hid_parse(hdev);
> +       if (ret) {
> +               hid_err(hdev, "parse failed\n");
> +               goto err_free;
> +       }
> +
> +       ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
> +       if (ret) {
> +               hid_err(hdev, "hw start failed\n");
> +               goto err_free;
> +       }
> +
> +       return 0;
> +
> +err_free:
> +       kfree(priv);
> +       return ret;
> +}
> +
> +static void penmount_remove(struct hid_device *hdev)
> +{
> +       struct penmount_priv *priv = hid_get_drvdata(hdev);
> +
> +       hid_hw_stop(hdev);
> +       kfree(priv);
> +}
> +
> +static const struct hid_device_id penmount_devices[] = {
> +       { HID_USB_DEVICE(USB_VENDOR_ID_PENMOUNT, USB_DEVICE_ID_PENMOUNT_6000) },
> +       { }
> +};
> +MODULE_DEVICE_TABLE(hid, penmount_devices);
> +
> +static const struct hid_usage_id penmount_usages[] = {
> +       { HID_ANY_ID, HID_ANY_ID, HID_ANY_ID },
> +       { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1 }
> +};
> +
> +static struct hid_driver penmount_driver = {
> +       .name = "hid-penmount",
> +       .id_table = penmount_devices,
> +       .probe = penmount_probe,
> +       .remove = penmount_remove,
> +       .input_mapping = penmount_input_mapping,
> +       .usage_table = penmount_usages,
> +       .event = penmount_event,
> +};
> +
> +static int __init penmount_init(void)
> +{
> +       return hid_register_driver(&penmount_driver);
> +}
> +
> +static void __exit penmount_exit(void)
> +{
> +       hid_unregister_driver(&penmount_driver);
> +}
> +
> +module_init(penmount_init);
> +module_exit(penmount_exit);
> +
> +MODULE_AUTHOR("PenMount Touch Solutions <penmount@seed.net.tw>");
> +MODULE_DESCRIPTION("PenMount HID TouchScreen Driver");
> +MODULE_LICENSE("GPL");
> --
> 1.9.3
>
> --
> 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 v2 0/7] Second batch of cleanups for cros_ec
From: Dmitry Torokhov @ 2014-08-25 17:05 UTC (permalink / raw)
  To: Javier Martinez Canillas
  Cc: Lee Jones, Wolfram Sang, Doug Anderson, Simon Glass,
	Bill Richardson, Andrew Bresticker, Derek Basehore, Todd Broch,
	Olof Johansson, linux-i2c, linux-input, linux-samsung-soc
In-Reply-To: <1408974008-17184-1-git-send-email-javier.martinez@collabora.co.uk>

On Mon, Aug 25, 2014 at 03:40:01PM +0200, Javier Martinez Canillas wrote:
> This is a second batch of cleanups patches for the mfd cros_ec
> driver and its subdevices drivers. The first batch of cleanups
> was posted by Doug Anderson [0] and have already been merged.
> The patches were picked from the ChromeOS 3.8 kernel and after
> these no cleanups patches for cros_ec are left, only commits
> that add cros ec support not yet available in mainline.
> 
> This is a second version of the patch series that addresses
> issues pointed out by Doug Anderson and Lee Jones on v1 [1].
> 
> There is almost no functionality added on this series but the
> idea is to reduce the delta between the mainline drivers and
> the ones in the downstream Chrome OS 3.8 kernel so the missing
> functionality can be added on top once these cleanups patches
> are merged. The missing functionlity currently in mainline is:
> 
> - Chrome OS Embedded Controller userspace device interface
> - Chrome OS Embedded Controller Low Pin Count (LPC) inteface
> - Access to vboot context stored on a block device
> - Access to vboot context stored on EC's nvram
> 
> The patches in this series are authored by different people
> (all on cc) and consist of the following:
> 
> Andrew Bresticker (3):
>   mfd: cros_ec: stop calling ->cmd_xfer() directly
>   mfd: cros_ec: move locking into cros_ec_cmd_xfer
>   mfd: cros_ec: wait for completion of commands that return IN_PROGRESS
> 
> Derek Basehore (1):
>   i2c: i2c-cros-ec-tunnel: Set retries to 3
> 
> Doug Anderson (1):
>   mfd: cros_ec: Delay for 50ms when we see EC_CMD_REBOOT_EC
> 
> Todd Broch (2):
>   mfd: cros_ec: Instantiate sub-devices from device tree
>   Input: cros_ec_keyb: Optimize ghosting algorithm.
> 
>  drivers/i2c/busses/i2c-cros-ec-tunnel.c |  5 +-
>  drivers/input/keyboard/cros_ec_keyb.c   | 94 ++++++++++++++++++---------------
>  drivers/mfd/cros_ec.c                   | 78 ++++++++++++++++++++-------
>  drivers/mfd/cros_ec_spi.c               | 20 ++++---
>  include/linux/mfd/cros_ec.h             | 24 ++++++---
>  5 files changed, 141 insertions(+), 80 deletions(-)
> 
> Patches #1, #2, #6 and #7 do not depend of others so they can be
> merged independently but patches #3, #4 and #5 have to be merged
> in that specific order since they depend on the previous one. 

#7 does not apply to my tree (I guess it depends on the 1st batch which I
expect will go through MFD tree?). Maybe you could rebase it on top of my next
so it can be applied sooner? Or it really needs parts of patchset #1?

Thanks.

-- 
Dmitry

^ permalink raw reply

* [PATCH] HID: input: force generic axis to be mapped to their user space axis
From: Benjamin Tissoires @ 2014-08-25 17:07 UTC (permalink / raw)
  To: Jiri Kosina, Éric Brunet; +Cc: linux-input, linux-kernel

Atmel 840B digitizer presents a stylus interface which reports twice
the X coordinate and then twice the Y coordinate. In its current
implementation, hid-input assign the first X to X, then the second to Y,
then the first Y to Z, then the second one to RX.

This is wrong, and X should always be mapped to X, no matter what.
A solution consists in forcing X, Y, Z, RX, RY, RZ to be mapped to their
correct user space counter part.

Reported-by: Éric Brunet <Eric.Brunet@lps.ens.fr>
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
---

Hi Jiri,

well, this fix should have been in the Linux kernel for ages IMO. This would
have prevented the need of HID_QUIRK_MULTI_INPUT for the very first multitouch
panels. I can not see any reasons why we want to have the second X mapped to
Y, and in the device reported here, both X have the same value.

Note that I am still investigating the spurious jumps reported by Eric, but we
should be safe in taking this one to master.

Cheers,
Benjamin

 drivers/hid/hid-input.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index 2619f7f..2df7fdd 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -599,6 +599,12 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
 		/* These usage IDs map directly to the usage codes. */
 		case HID_GD_X: case HID_GD_Y: case HID_GD_Z:
 		case HID_GD_RX: case HID_GD_RY: case HID_GD_RZ:
+			if (field->flags & HID_MAIN_ITEM_RELATIVE)
+				map_rel(usage->hid & 0xf);
+			else
+				map_abs_clear(usage->hid & 0xf);
+			break;
+
 		case HID_GD_SLIDER: case HID_GD_DIAL: case HID_GD_WHEEL:
 			if (field->flags & HID_MAIN_ITEM_RELATIVE)
 				map_rel(usage->hid & 0xf);
-- 
2.1.0

^ permalink raw reply related

* Re: [PATCH v2 0/7] Second batch of cleanups for cros_ec
From: Javier Martinez Canillas @ 2014-08-25 17:28 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: Lee Jones, Wolfram Sang, Doug Anderson, Simon Glass,
	Bill Richardson, Andrew Bresticker, Derek Basehore, Todd Broch,
	Olof Johansson, linux-i2c-u79uwXL29TY76Z2rM5mHXA,
	linux-input-u79uwXL29TY76Z2rM5mHXA,
	linux-samsung-soc-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20140825170533.GA29350-WlK9ik9hQGAhIp7JRqBPierSzoNAToWh@public.gmane.org>

Hello Dmitry,

On 08/25/2014 07:05 PM, Dmitry Torokhov wrote:
>> 
>> Patches #1, #2, #6 and #7 do not depend of others so they can be
>> merged independently but patches #3, #4 and #5 have to be merged
>> in that specific order since they depend on the previous one. 
> 
> #7 does not apply to my tree (I guess it depends on the 1st batch which I
> expect will go through MFD tree?). Maybe you could rebase it on top of my next
> so it can be applied sooner? Or it really needs parts of patchset #1?
> 

The first batch sent by Doug did indeed touch this driver and the patches
were merged through the MFD tree for 3.17 as you said. I see that your
next branch is based on 3.16-rc6 and that is why it does not apply cleanly.

I guess you will rebase your next branch for 3.18 on top of 3.17-rc1
anyways which will fix this issue? If not please let me know and I can of
course re-spin the patch so it applies cleanly on top of 3.16-rc6.

> Thanks.
> 

Best regards,
Javier

^ permalink raw reply

* Re: [PATCH v2 0/7] Second batch of cleanups for cros_ec
From: Dmitry Torokhov @ 2014-08-25 18:01 UTC (permalink / raw)
  To: Javier Martinez Canillas
  Cc: Lee Jones, Wolfram Sang, Doug Anderson, Simon Glass,
	Bill Richardson, Andrew Bresticker, Derek Basehore, Todd Broch,
	Olof Johansson, linux-i2c, linux-input, linux-samsung-soc
In-Reply-To: <53FB7221.8090804@collabora.co.uk>

On Mon, Aug 25, 2014 at 07:28:01PM +0200, Javier Martinez Canillas wrote:
> Hello Dmitry,
> 
> On 08/25/2014 07:05 PM, Dmitry Torokhov wrote:
> >> 
> >> Patches #1, #2, #6 and #7 do not depend of others so they can be
> >> merged independently but patches #3, #4 and #5 have to be merged
> >> in that specific order since they depend on the previous one. 
> > 
> > #7 does not apply to my tree (I guess it depends on the 1st batch which I
> > expect will go through MFD tree?). Maybe you could rebase it on top of my next
> > so it can be applied sooner? Or it really needs parts of patchset #1?
> > 
> 
> The first batch sent by Doug did indeed touch this driver and the patches
> were merged through the MFD tree for 3.17 as you said. I see that your
> next branch is based on 3.16-rc6 and that is why it does not apply cleanly.
> 
> I guess you will rebase your next branch for 3.18 on top of 3.17-rc1
> anyways which will fix this issue? If not please let me know and I can of
> course re-spin the patch so it applies cleanly on top of 3.16-rc6.

I normally merge with mainline around -rc3 so please ping me around that time
if you do not see the patch in my tree.

Thanks.

-- 
Dmitry

^ permalink raw reply

* Re: Input sync flag when registering.
From: Dmitry Torokhov @ 2014-08-25 18:19 UTC (permalink / raw)
  To: Thomas Poussevin; +Cc: linux-input
In-Reply-To: <53FAF963.9020403@parrot.com>

Hi Thomas,

On Mon, Aug 25, 2014 at 10:52:51AM +0200, Thomas Poussevin wrote:
> Hi,
> I noticed that with touchscreen drivers that don't explicitly call a
> input_sync after input_register_device, suspend to ram is blocked if
> no event is sent, because the input_dev created is considered as not
> synchronized. The problem was seen with Atmel mxt driver. When any
> event is sent, the driver explicitly ask a sync, so the problem is
> solved.
> The problem occurs only when the screen has never send any event
> before suspend to ram.
> I solved it setting the sync element to true (when input dev is
> created, no element is pending).
> Is there a better way to solve the problem ?

It is not clear to me what the problem is. The kernel as far as I
remember never checked state of 'sync' field when executing suspend
callbacks. Moreover there is no longer 'sync' field at all in mainline.

It sounds like some userspace code makes assumptions that are not always
valid.

Thanks.

-- 
Dmitry

^ permalink raw reply


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