Re: [PATCH 2/2] input: Add LED support to Synaptics device

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



At Fri, 16 Apr 2010 10:00:20 +0200,
I wrote:
> 
> At Thu, 15 Apr 2010 21:12:18 +0200,
> Pavel Machek wrote:
> > 
> > Hi!
> > 
> > > The new Synaptics devices have an LED on the top-left corner.
> > > This is controlled via the command 0x0a with parameters 0x88 or 0x10.
> > > 
> > > The detection of the LED isn't clear yet.  It should have been the new
> > > capability bits that indicate the presence, but on real machines, it
> > > doesn't fit.  So, for the time being, the driver checks the product id
> > > in the ext capability bits and assumes that LED exists on the known
> > > devices.
> > > 
> > > The support of LED is controlled via a normal input event with EV_LED
> > > bit mask.  It supports LED_MUTE bit.  X driver can detect the LED
> > > support by checking these bits.
> > 
> > Could we use generic LED API for this?
> 
> Yeah, actually I started implementing with LED ADI at first.
> 
> But, then it turned out to be that it's much easier to use the
> existing LED input bits since this LED is really tightly coupled with
> the synaptics input device.  An individual LED device makes hard to
> find out the corresponding input device.
> 
> If we assume there is only one synaptics and only one synaptics-LED
> device, then yes, the situation can be a bit easier, though.
> 
> > It is not really 'mute' led after all...
> 
> If the problem is the misuse of LED_MUTE bit, how about adding a new
> LED bit, e.g. LED_TOUCHPAD?

The revised patch with an addition of LED_TOUCHPAD is below.


thanks,

Takashi

===

From: Takashi Iwai <tiwai@xxxxxxx>
Subject: [PATCH] input: Add LED support to Synaptics device

The new Synaptics devices have an LED on the top-left corner.
This is controlled via the command 0x0a with parameters 0x88 or 0x10.

The detection of the LED isn't clear yet.  It should have been the new
capability bits that indicate the presence, but on real machines, it
doesn't fit.  So, for the time being, the driver checks the product id
in the ext capability bits and assumes that LED exists on the known
devices.

The support of LED is controlled via a normal input event with EV_LED
bit mask.  A new LED bitmask, LED_TOUCHPAD, is added.  X driver can
detect the LED support by checking these bits.

Signed-off-by: Takashi Iwai <tiwai@xxxxxxx>
---
 drivers/input/mouse/synaptics.c |   64 +++++++++++++++++++++++++++++++++++++++
 drivers/input/mouse/synaptics.h |    5 +++
 include/linux/input.h           |    1 +
 3 files changed, 70 insertions(+), 0 deletions(-)

diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
index c7b5285..bffa474 100644
--- a/drivers/input/mouse/synaptics.c
+++ b/drivers/input/mouse/synaptics.c
@@ -28,6 +28,7 @@
 #include <linux/input.h>
 #include <linux/serio.h>
 #include <linux/libps2.h>
+#include <linux/workqueue.h>
 #include <linux/slab.h>
 #include "psmouse.h"
 #include "synaptics.h"
@@ -339,6 +340,52 @@ static void synaptics_pt_create(struct psmouse *psmouse)
  *	Functions to interpret the absolute mode packets
  ****************************************************************************/
 
+static void synaptics_set_led(struct psmouse *psmouse, int on)
+{
+	unsigned char param[1];
+
+	if (psmouse_sliced_command(psmouse, on ? 0x88 : 0x10))
+		return;
+	param[0] = 0x0a;
+	ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_SETRATE);
+}
+
+static void synaptics_led_work(struct work_struct *work)
+{
+	struct synaptics_data *priv = container_of(work, struct synaptics_data, led_work);
+	synaptics_set_led(priv->psmouse, priv->led_status);
+}
+
+/* input event handler: changed by x11 synaptics driver */
+static int synaptics_led_event(struct input_dev *dev, unsigned int type,
+			       unsigned int code, int value)
+{
+	struct synaptics_data *priv = dev->dev.platform_data;
+
+	if (!priv)
+		return 0;
+	if (type == EV_LED && code == LED_TOUCHPAD) {
+		priv->led_status = !!value;
+		schedule_work(&priv->led_work);
+	}
+	return 0;
+}
+
+static void synaptics_query_led(struct psmouse *psmouse)
+{
+	struct synaptics_data *priv = psmouse->private;
+
+	/* FIXME: LED is supposedly detectable in cap0c[1] 0x20, but it seems
+	 * not working on real machines.  So we check the product id to be sure
+	 */
+	if (priv->ext_cap_0c && SYN_CAP_PRODUCT_ID(priv->ext_cap) == 0xe4)
+		printk(KERN_INFO "synaptics: support LED control\n");
+		priv->has_led = 1;
+		priv->psmouse = psmouse;
+		INIT_WORK(&priv->led_work, synaptics_led_work);
+	}
+}
+
 static void synaptics_parse_hw_state(unsigned char buf[], struct synaptics_data *priv, struct synaptics_hw_state *hw)
 {
 	memset(hw, 0, sizeof(struct synaptics_hw_state));
@@ -618,10 +665,22 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv)
 		__clear_bit(BTN_RIGHT, dev->keybit);
 		__clear_bit(BTN_MIDDLE, dev->keybit);
 	}
+	if (priv->has_led) {
+		__set_bit(EV_LED, dev->evbit);
+		__set_bit(LED_TOUCHPAD, dev->ledbit);
+		dev->event = synaptics_led_event;
+		dev->dev.platform_data = priv;
+	}
 }
 
 static void synaptics_disconnect(struct psmouse *psmouse)
 {
+	struct synaptics_data *priv = psmouse->private;
+
+	if (priv->has_led) {
+		cancel_work_sync(&priv->led_work);
+		synaptics_set_led(psmouse, 0);
+	}
 	synaptics_reset(psmouse);
 	kfree(psmouse->private);
 	psmouse->private = NULL;
@@ -653,6 +712,9 @@ static int synaptics_reconnect(struct psmouse *psmouse)
 		return -1;
 	}
 
+	if (priv->has_led)
+		synaptics_set_led(psmouse, priv->led_status);
+
 	return 0;
 }
 
@@ -727,6 +789,8 @@ int synaptics_init(struct psmouse *psmouse)
 		SYN_ID_MAJOR(priv->identity), SYN_ID_MINOR(priv->identity),
 		priv->model_id, priv->capabilities, priv->ext_cap, priv->ext_cap_0c);
 
+	synaptics_query_led(psmouse);
+
 	set_input_params(psmouse->dev, priv);
 
 	/*
diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h
index ae37c5d..0b989f4 100644
--- a/drivers/input/mouse/synaptics.h
+++ b/drivers/input/mouse/synaptics.h
@@ -107,6 +107,11 @@ struct synaptics_data {
 	unsigned char pkt_type;			/* packet type - old, new, etc */
 	unsigned char mode;			/* current mode byte */
 	int scroll;
+
+	unsigned char has_led;
+	unsigned char led_status;
+	struct psmouse *psmouse;
+	struct work_struct led_work;
 };
 
 void synaptics_module_init(void);
diff --git a/include/linux/input.h b/include/linux/input.h
index 7ed2251..0aea50d 100644
--- a/include/linux/input.h
+++ b/include/linux/input.h
@@ -757,6 +757,7 @@ struct input_absinfo {
 #define LED_MISC		0x08
 #define LED_MAIL		0x09
 #define LED_CHARGING		0x0a
+#define LED_TOUCHPAD		0x0b
 #define LED_MAX			0x0f
 #define LED_CNT			(LED_MAX+1)
 
-- 
1.7.0.4

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

[Index of Archives]     [Linux Media Devel]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Linux Wireless Networking]     [Linux Omap]

  Powered by Linux