[PATCH] dell-laptop: support synaptics touchpad led

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

 



The TP-LOCK-LED would bright while TP-disablement.
You can implement 97 command services routing of P/S2 device.
Code like below:
out 0x64,0x97 ;set 0x97 to command port;0x64 is command port
out 0x60,0x01 ;set 0x01 to data port then make LED bright;0x60 is data port
out 0x60,0x02 ;set 0x02 to data port then make LED dark

Before you send the action to the port, you must make sure the Input buffer
is empty (port 0x64).

Signed-off-by: AceLan Kao <acelan.kao@xxxxxxxxxxxxx>
---
 drivers/platform/x86/dell-laptop.c |  105 +++++++++++++++++++++++++++++++++---
 1 files changed, 98 insertions(+), 7 deletions(-)

diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c
index d3841de..65efa74 100644
--- a/drivers/platform/x86/dell-laptop.c
+++ b/drivers/platform/x86/dell-laptop.c
@@ -65,19 +65,14 @@ static int da_command_code;
 static int da_num_tokens;
 static struct calling_interface_token *da_tokens;
 
-static struct platform_driver platform_driver = {
-	.driver = {
-		.name = "dell-laptop",
-		.owner = THIS_MODULE,
-	}
-};
-
 static struct platform_device *platform_device;
 static struct backlight_device *dell_backlight_device;
 static struct rfkill *wifi_rfkill;
 static struct rfkill *bluetooth_rfkill;
 static struct rfkill *wwan_rfkill;
 
+static struct delayed_work dell_touchpadled_update_work;
+static int touchpad_led_status;
 static const struct dmi_system_id __initdata dell_device_table[] = {
 	{
 		.ident = "Dell laptop",
@@ -572,6 +567,45 @@ static const struct backlight_ops dell_ops = {
 	.update_status  = dell_send_intensity,
 };
 
+static void dell_touchpadled_on(void)
+{
+	while (inb(0x64) & 0x02)
+		udelay(100);
+	outb(0x97 , 0x64);
+
+	while (inb(0x64) & 0x02)
+		udelay(100);
+	outb(1, 0x60);
+
+	touchpad_led_status = 1;
+}
+
+static void dell_touchpadled_off(void)
+{
+	while (inb(0x64) & 0x02)
+		udelay(100);
+	outb(0x97 , 0x64);
+
+	while (inb(0x64) & 0x02)
+		udelay(100);
+	outb(2, 0x60);
+
+	touchpad_led_status = 0;
+}
+
+/*
+ * Called for each KEY_F22 key press event.
+ */
+static void dell_touchpadled_update(struct work_struct *work)
+{
+	touchpad_led_status = 1 - touchpad_led_status;
+
+	if (touchpad_led_status == 1)
+		dell_touchpadled_on();
+	else
+		dell_touchpadled_off();
+}
+
 static bool dell_laptop_i8042_filter(unsigned char data, unsigned char str,
 			      struct serio *port)
 {
@@ -589,6 +623,10 @@ static bool dell_laptop_i8042_filter(unsigned char data, unsigned char str,
 			schedule_delayed_work(&dell_rfkill_work,
 					      round_jiffies_relative(HZ));
 			break;
+		case 0x1E:	/* F22 */
+			schedule_delayed_work(&dell_touchpadled_update_work,
+					      0);
+			break;
 		}
 		extended = false;
 	}
@@ -596,11 +634,64 @@ static bool dell_laptop_i8042_filter(unsigned char data, unsigned char str,
 	return false;
 }
 
+static void restore_touchpad_led(void)
+{
+	/*
+	 * We don't want to change the value of touchpad_led_status while
+	 * resuming, so we modify the value here and it'll be changed back
+	 * in the work queue
+	 */
+	touchpad_led_status = 1 - touchpad_led_status;
+	/* The delay is needed to wait the chip wake up */
+	schedule_delayed_work(&dell_touchpadled_update_work, 1000);
+}
+
+static int __devinit dell_laptop_probe(struct platform_device *device)
+{
+	INIT_DELAYED_WORK(&dell_touchpadled_update_work,
+			  dell_touchpadled_update);
+	return 0;
+}
+
+static int dell_laptop_remove(struct platform_device *device)
+{
+	return 0;
+}
+
+static int dell_laptop_suspend(struct device *dev)
+{
+	return 0;
+}
+
+static int dell_laptop_resume(struct device *dev)
+{
+	restore_touchpad_led();
+	return 0;
+}
+
+static const struct dev_pm_ops dell_laptop_pm_ops = {
+	.suspend = dell_laptop_suspend,
+	.resume  = dell_laptop_resume,
+	.restore = dell_laptop_resume,
+};
+
+static struct platform_driver platform_driver = {
+	.driver = {
+		.name = "dell-laptop",
+		.owner = THIS_MODULE,
+		.pm    = &dell_laptop_pm_ops,
+	},
+	.probe  = dell_laptop_probe,
+	.remove = dell_laptop_remove,
+};
+
 static int __init dell_init(void)
 {
 	int max_intensity = 0;
 	int ret;
 
+	touchpad_led_status = 0;
+
 	if (!dmi_check_system(dell_device_table))
 		return -ENODEV;
 
-- 
1.7.4.1

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


[Index of Archives]     [Linux Kernel Development]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux