* [PATCH v3 1/2] uapi/input.h: Add INPUT_PROP_TOPBUTTONPAD device property
From: Hans de Goede @ 2014-04-15 7:24 UTC (permalink / raw)
To: Dmitry Torokhov
Cc: Benjamin Tissoires, Peter Hutterer, linux-input, Hans de Goede
In-Reply-To: <1397546663-4447-1-git-send-email-hdegoede@redhat.com>
On some newer laptops with a trackpoint the physical buttons for the
trackpoint have been removed to allow for a larger touchpad. On these
laptops the buttonpad has clearly marked areas on the top which are to be
used as trackpad buttons.
Users of the event device-node need to know about this, so that they can
properly interpret BTN_LEFT events as being a left / right / middle click
depending on where on the button pad the clicking finger is.
This commits adds a INPUT_PROP_TOPBUTTONPAD device property which drivers
for such buttonpads will use to signal to the user that this buttonpad not
only has the normal bottom button area, but also a top button area.
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
include/uapi/linux/input.h | 1 +
1 file changed, 1 insertion(+)
diff --git a/include/uapi/linux/input.h b/include/uapi/linux/input.h
index bd24470..f484952 100644
--- a/include/uapi/linux/input.h
+++ b/include/uapi/linux/input.h
@@ -164,6 +164,7 @@ struct input_keymap_entry {
#define INPUT_PROP_DIRECT 0x01 /* direct input devices */
#define INPUT_PROP_BUTTONPAD 0x02 /* has button(s) under pad */
#define INPUT_PROP_SEMI_MT 0x03 /* touch rectangle only */
+#define INPUT_PROP_TOPBUTTONPAD 0x04 /* softbuttons at top of pad */
#define INPUT_PROP_MAX 0x1f
#define INPUT_PROP_CNT (INPUT_PROP_MAX + 1)
--
1.9.0
^ permalink raw reply related
* [PATCH v3 0/2] uapi/input.h: Add INPUT_PROP_TOPBUTTONPAD device property
From: Hans de Goede @ 2014-04-15 7:24 UTC (permalink / raw)
To: Dmitry Torokhov; +Cc: Benjamin Tissoires, Peter Hutterer, linux-input
Hi All,
I've received an updated list of pnpids from synaptics so here is an updated
version of the patch-set.
Changes in v2:
-Drop adding of pnp_id to struct serio (drop patches 2/4 and 3/4 of v1)
-Modify the synaptics patch to use firmware_id instead of pnp_id
Changes in v3:
-Update topbuttonpad pnpid list in synaptics.c
Regards,
Hans
^ permalink raw reply
* Re: HID vendor access from user space
From: David Herrmann @ 2014-04-15 2:16 UTC (permalink / raw)
To: Nestor Lopez Casado
Cc: Jiri Kosina, Dmitry Torokhov, open list:HID CORE LAYER,
Olivier Gay, Benjamin Tissoires, Mathieu Meisser
In-Reply-To: <CAE7qMro259DVdPqDw4CN1hNp8kQ933F6f6ZMa7BPCOXuNWTQ8Q@mail.gmail.com>
Hi
On Mon, Apr 14, 2014 at 12:00 PM, Nestor Lopez Casado
<nlopezcasad@logitech.com> wrote:
> David, Jiri,
>
> After considering our discussion here, which is your position on
> extending the hidraw nodes to include separate nodes for top level
> vendor collections ?
Patches, patches, patches!
I am currently on the road, but it's always easier to see real code
than just the theory. I have no real objections to provide multiple
hidraw interfaces. However, I think that doesn't solve your problem.
For instance, you still need to set proper access-rights on the hidraw
node. However, some other devices might export unsafe interfaces via
vendor-extensions, and you don't wanna make those hidraw nodes
user-accessible. Therefore, you still need a udev-rule to match on
Logitech-stuff. You could do that as a small Logitech-driver in the
kernel. But ok, I'm fine with moving those whitelists to user-space.
Thanks
David
^ permalink raw reply
* [PATCH 2/4] HID: (thingm) remove the "fade" sysfs attribute
From: Vivien Didelot @ 2014-04-14 20:50 UTC (permalink / raw)
To: linux-input
Cc: Vivien Didelot, Jiri Kosina, linux-leds, Bryan Wu, Richard Purdie,
linux-kernel, kernel
In-Reply-To: <1397508620-15244-1-git-send-email-vivien.didelot@savoirfairelinux.com>
As for the "play" sysfs attribute, remove this other non-standard
attribute, so the driver only implements what is required to switch the
LED on and off. Thus, a fade time won't be ideal for some fast-changing
triggers.
Signed-off-by: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
---
Documentation/ABI/testing/sysfs-driver-hid-thingm | 8 -----
drivers/hid/hid-thingm.c | 41 -----------------------
2 files changed, 49 deletions(-)
diff --git a/Documentation/ABI/testing/sysfs-driver-hid-thingm b/Documentation/ABI/testing/sysfs-driver-hid-thingm
index fda6185..735c5cb 100644
--- a/Documentation/ABI/testing/sysfs-driver-hid-thingm
+++ b/Documentation/ABI/testing/sysfs-driver-hid-thingm
@@ -6,11 +6,3 @@ Description: The ThingM blink1 is an USB RGB LED. The color notation is
color. Write the 24-bit hexadecimal color to change the current
LED color. The default color is full white (0xFFFFFF).
For instance, set the color to green with: echo 00FF00 > rgb
-
-What: /sys/class/leds/blink1::<serial>/fade
-Date: January 2013
-Contact: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
-Description: This attribute allows to set a fade time in milliseconds for
- the next color change. Read the attribute to know the current
- fade time. The default value is set to 0 (no fade time). For
- instance, set a fade time of 2 seconds with: echo 2000 > fade
diff --git a/drivers/hid/hid-thingm.c b/drivers/hid/hid-thingm.c
index 7e376b8..e3b6647 100644
--- a/drivers/hid/hid-thingm.c
+++ b/drivers/hid/hid-thingm.c
@@ -26,14 +26,12 @@
* @hdev: HID device.
* @led_cdev: LED class instance.
* @rgb: 8-bit per channel RGB notation.
- * @fade: fade time in hundredths of a second.
* @brightness: brightness coefficient.
*/
struct blink1_data {
struct hid_device *hdev;
struct led_classdev led_cdev;
u32 rgb;
- u16 fade;
u8 brightness;
};
@@ -64,12 +62,6 @@ static int blink1_update_color(struct blink1_data *data)
buf[4] = DIV_ROUND_CLOSEST(blink1_rgb_to_b(data->rgb), coef);
}
- if (data->fade) {
- buf[1] = 'c';
- buf[5] = (data->fade & 0xFF00) >> 8;
- buf[6] = (data->fade & 0x00FF);
- }
-
return blink1_send_command(data, buf);
}
@@ -121,42 +113,9 @@ static ssize_t blink1_store_rgb(struct device *dev,
static DEVICE_ATTR(rgb, S_IRUGO | S_IWUSR, blink1_show_rgb, blink1_store_rgb);
-static ssize_t blink1_show_fade(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct blink1_data *data = dev_get_drvdata(dev->parent);
-
- return sprintf(buf, "%d\n", data->fade * 10);
-}
-
-static ssize_t blink1_store_fade(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- struct blink1_data *data = dev_get_drvdata(dev->parent);
- long unsigned int fade;
- int ret;
-
- ret = kstrtoul(buf, 10, &fade);
- if (ret)
- return ret;
-
- /* blink(1) accepts 16-bit fade time, number of 10ms ticks */
- fade = DIV_ROUND_CLOSEST(fade, 10);
- if (fade > 65535)
- return -EINVAL;
-
- data->fade = fade;
-
- return count;
-}
-
-static DEVICE_ATTR(fade, S_IRUGO | S_IWUSR,
- blink1_show_fade, blink1_store_fade);
-
static const struct attribute_group blink1_sysfs_group = {
.attrs = (struct attribute *[]) {
&dev_attr_rgb.attr,
- &dev_attr_fade.attr,
NULL
},
};
--
1.9.1
^ permalink raw reply related
* [PATCH 0/4] HID: (thingm) introduces blink(1) mk2
From: Vivien Didelot @ 2014-04-14 20:50 UTC (permalink / raw)
To: linux-input
Cc: Vivien Didelot, Jiri Kosina, linux-leds, Bryan Wu, Richard Purdie,
linux-kernel, kernel
This patchset introduces the support of the blink(1) mk2 device, after a
refactoring of the thingm driver. It removes non-standard sysfs attributes and
uses work queues to fix the usage of triggers with this device.
Vivien Didelot (4):
HID: (thingm) remove the "play" sysfs attribute
HID: (thingm) remove the "fade" sysfs attribute
HID: (thingm) refactor blink(1) support
HID: (thingm) add support for blink(1) mk2
Documentation/ABI/testing/sysfs-driver-hid-thingm | 23 --
drivers/hid/hid-thingm.c | 361 ++++++++++++----------
drivers/leds/Kconfig | 2 +
3 files changed, 203 insertions(+), 183 deletions(-)
delete mode 100644 Documentation/ABI/testing/sysfs-driver-hid-thingm
--
1.9.1
^ permalink raw reply
* [PATCH 4/4] HID: (thingm) add support for blink(1) mk2
From: Vivien Didelot @ 2014-04-14 20:50 UTC (permalink / raw)
To: linux-input
Cc: Vivien Didelot, Jiri Kosina, linux-leds, Bryan Wu, Richard Purdie,
linux-kernel, kernel
In-Reply-To: <1397508620-15244-1-git-send-email-vivien.didelot@savoirfairelinux.com>
The blink(1) mk2 is a new version of the blink(1) USB RGB LED. The new
generation has 2 individually-controllable RGB chips.
This patch adds support for this device to the thingm driver, which
registers 3 new standard LED class instances for the second RGB chip.
Note that the 'n' (set) command does not support setting a color for a
single RGB chip, so it was changed to 'c' (fade) with a timeout of 0.
Signed-off-by: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
---
drivers/hid/hid-thingm.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/drivers/hid/hid-thingm.c b/drivers/hid/hid-thingm.c
index 0af0eb4..31de890 100644
--- a/drivers/hid/hid-thingm.c
+++ b/drivers/hid/hid-thingm.c
@@ -23,6 +23,7 @@
/* Firmware major number of supported devices */
#define THINGM_MAJOR_MK1 '1'
+#define THINGM_MAJOR_MK2 '2'
struct thingm_fwinfo {
char major;
@@ -35,6 +36,10 @@ const struct thingm_fwinfo thingm_fwinfo[] = {
.major = THINGM_MAJOR_MK1,
.numrgb = 1,
.first = 0,
+ }, {
+ .major = THINGM_MAJOR_MK2,
+ .numrgb = 2,
+ .first = 1,
}
};
@@ -117,7 +122,7 @@ static int thingm_version(struct thingm_device *tdev)
static int thingm_write_color(struct thingm_rgb *rgb)
{
- u8 buf[REPORT_SIZE] = { REPORT_ID, 'n', 0, 0, 0, 0, 0, 0, 0 };
+ u8 buf[REPORT_SIZE] = { REPORT_ID, 'c', 0, 0, 0, 0, 0, rgb->num, 0 };
buf[2] = rgb->red.ldev.brightness;
buf[3] = rgb->green.ldev.brightness;
--
1.9.1
^ permalink raw reply related
* [PATCH 3/4] HID: (thingm) refactor blink(1) support
From: Vivien Didelot @ 2014-04-14 20:50 UTC (permalink / raw)
To: linux-input
Cc: Vivien Didelot, Jiri Kosina, linux-leds, Bryan Wu, Richard Purdie,
linux-kernel, kernel
In-Reply-To: <1397508620-15244-1-git-send-email-vivien.didelot@savoirfairelinux.com>
This patch refactors the way the thingm driver registers a blink(1) LED.
In order to make the driver simpler and more standard, drop the "rgb"
sysfs attribute and create one instance of LED class per RGB channel.
Actually, the name of the LED class instance registered for a blink(1)
device is "blink1::ABCD", where ABCD is the last 4 chars of the serial
number. The driver now registers 3 instances per RGB chip, named
"thingmX:{red,green,blue}:ledY" where X is the hidraw minor number and Y
is the RGB chip number (as seen by the firmware).
This patch also uses work queues to defer calls with the device, which
now allows triggers to work as expected with this LED device.
Also remove the brightness structure field and the brightness_get
backend, as it is already handled by the LED class, and changes the
prefix of functions and structures to thingm_ to match the driver name.
Signed-off-by: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
---
Documentation/ABI/testing/sysfs-driver-hid-thingm | 8 -
drivers/hid/hid-thingm.c | 304 +++++++++++++++-------
drivers/leds/Kconfig | 2 +
3 files changed, 209 insertions(+), 105 deletions(-)
delete mode 100644 Documentation/ABI/testing/sysfs-driver-hid-thingm
diff --git a/Documentation/ABI/testing/sysfs-driver-hid-thingm b/Documentation/ABI/testing/sysfs-driver-hid-thingm
deleted file mode 100644
index 735c5cb..0000000
--- a/Documentation/ABI/testing/sysfs-driver-hid-thingm
+++ /dev/null
@@ -1,8 +0,0 @@
-What: /sys/class/leds/blink1::<serial>/rgb
-Date: January 2013
-Contact: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
-Description: The ThingM blink1 is an USB RGB LED. The color notation is
- 3-byte hexadecimal. Read this attribute to get the last set
- color. Write the 24-bit hexadecimal color to change the current
- LED color. The default color is full white (0xFFFFFF).
- For instance, set the color to green with: echo 00FF00 > rgb
diff --git a/drivers/hid/hid-thingm.c b/drivers/hid/hid-thingm.c
index e3b6647..0af0eb4 100644
--- a/drivers/hid/hid-thingm.c
+++ b/drivers/hid/hid-thingm.c
@@ -1,7 +1,7 @@
/*
* ThingM blink(1) USB RGB LED driver
*
- * Copyright 2013 Savoir-faire Linux Inc.
+ * Copyright 2013-2014 Savoir-faire Linux Inc.
* Vivien Didelot <vivien.didelot@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or
@@ -10,170 +10,280 @@
*/
#include <linux/hid.h>
+#include <linux/hidraw.h>
#include <linux/leds.h>
#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
#include "hid-ids.h"
-#define BLINK1_CMD_SIZE 9
+#define REPORT_ID 1
+#define REPORT_SIZE 9
-#define blink1_rgb_to_r(rgb) ((rgb & 0xFF0000) >> 16)
-#define blink1_rgb_to_g(rgb) ((rgb & 0x00FF00) >> 8)
-#define blink1_rgb_to_b(rgb) ((rgb & 0x0000FF) >> 0)
+/* Firmware major number of supported devices */
+#define THINGM_MAJOR_MK1 '1'
-/**
- * struct blink1_data - blink(1) device specific data
- * @hdev: HID device.
- * @led_cdev: LED class instance.
- * @rgb: 8-bit per channel RGB notation.
- * @brightness: brightness coefficient.
- */
-struct blink1_data {
+struct thingm_fwinfo {
+ char major;
+ unsigned numrgb;
+ unsigned first;
+};
+
+const struct thingm_fwinfo thingm_fwinfo[] = {
+ {
+ .major = THINGM_MAJOR_MK1,
+ .numrgb = 1,
+ .first = 0,
+ }
+};
+
+/* A red, green or blue channel, part of an RGB chip */
+struct thingm_led {
+ struct thingm_rgb *rgb;
+ struct led_classdev ldev;
+ char name[32];
+};
+
+/* Basically a WS2812 5050 RGB LED chip */
+struct thingm_rgb {
+ struct thingm_device *tdev;
+ struct thingm_led red;
+ struct thingm_led green;
+ struct thingm_led blue;
+ struct work_struct work;
+ u8 num;
+};
+
+struct thingm_device {
struct hid_device *hdev;
- struct led_classdev led_cdev;
- u32 rgb;
- u8 brightness;
+ struct {
+ char major;
+ char minor;
+ } version;
+ const struct thingm_fwinfo *fwinfo;
+ struct mutex lock;
+ struct thingm_rgb *rgb;
};
-static int blink1_send_command(struct blink1_data *data,
- u8 buf[BLINK1_CMD_SIZE])
+static int thingm_send(struct thingm_device *tdev, u8 buf[REPORT_SIZE])
{
int ret;
- hid_dbg(data->hdev, "command: %d%c%.2x%.2x%.2x%.2x%.2x%.2x%.2x\n",
+ hid_dbg(tdev->hdev, "-> %d %c %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx\n",
buf[0], buf[1], buf[2], buf[3], buf[4],
buf[5], buf[6], buf[7], buf[8]);
- ret = hid_hw_raw_request(data->hdev, buf[0], buf, BLINK1_CMD_SIZE,
- HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
+ ret = hid_hw_raw_request(tdev->hdev, buf[0], buf, REPORT_SIZE,
+ HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
return ret < 0 ? ret : 0;
}
-static int blink1_update_color(struct blink1_data *data)
+static int thingm_recv(struct thingm_device *tdev, u8 buf[REPORT_SIZE])
{
- u8 buf[BLINK1_CMD_SIZE] = { 1, 'n', 0, 0, 0, 0, 0, 0, 0 };
+ int ret;
- if (data->brightness) {
- unsigned int coef = DIV_ROUND_CLOSEST(255, data->brightness);
+ ret = hid_hw_raw_request(tdev->hdev, buf[0], buf, REPORT_SIZE,
+ HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
+ if (ret < 0)
+ return ret;
- buf[2] = DIV_ROUND_CLOSEST(blink1_rgb_to_r(data->rgb), coef);
- buf[3] = DIV_ROUND_CLOSEST(blink1_rgb_to_g(data->rgb), coef);
- buf[4] = DIV_ROUND_CLOSEST(blink1_rgb_to_b(data->rgb), coef);
- }
+ hid_dbg(tdev->hdev, "<- %d %c %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx\n",
+ buf[0], buf[1], buf[2], buf[3], buf[4],
+ buf[5], buf[6], buf[7], buf[8]);
- return blink1_send_command(data, buf);
+ return 0;
}
-static void blink1_led_set(struct led_classdev *led_cdev,
- enum led_brightness brightness)
+static int thingm_version(struct thingm_device *tdev)
{
- struct blink1_data *data = dev_get_drvdata(led_cdev->dev->parent);
+ u8 buf[REPORT_SIZE] = { REPORT_ID, 'v', 0, 0, 0, 0, 0, 0, 0 };
+ int err;
+
+ err = thingm_send(tdev, buf);
+ if (err)
+ return err;
+
+ err = thingm_recv(tdev, buf);
+ if (err)
+ return err;
- data->brightness = brightness;
- if (blink1_update_color(data))
- hid_err(data->hdev, "failed to update color\n");
+ tdev->version.major = buf[3];
+ tdev->version.minor = buf[4];
+
+ return 0;
}
-static enum led_brightness blink1_led_get(struct led_classdev *led_cdev)
+static int thingm_write_color(struct thingm_rgb *rgb)
{
- struct blink1_data *data = dev_get_drvdata(led_cdev->dev->parent);
+ u8 buf[REPORT_SIZE] = { REPORT_ID, 'n', 0, 0, 0, 0, 0, 0, 0 };
+
+ buf[2] = rgb->red.ldev.brightness;
+ buf[3] = rgb->green.ldev.brightness;
+ buf[4] = rgb->blue.ldev.brightness;
- return data->brightness;
+ return thingm_send(rgb->tdev, buf);
}
-static ssize_t blink1_show_rgb(struct device *dev,
- struct device_attribute *attr, char *buf)
+static void thingm_work(struct work_struct *work)
{
- struct blink1_data *data = dev_get_drvdata(dev->parent);
+ struct thingm_rgb *rgb = container_of(work, struct thingm_rgb, work);
- return sprintf(buf, "%.6X\n", data->rgb);
+ mutex_lock(&rgb->tdev->lock);
+
+ if (thingm_write_color(rgb))
+ hid_err(rgb->tdev->hdev, "failed to write color\n");
+
+ mutex_unlock(&rgb->tdev->lock);
}
-static ssize_t blink1_store_rgb(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
+static void thingm_led_set(struct led_classdev *ldev,
+ enum led_brightness brightness)
{
- struct blink1_data *data = dev_get_drvdata(dev->parent);
- long unsigned int rgb;
- int ret;
+ struct thingm_led *led = container_of(ldev, struct thingm_led, ldev);
- ret = kstrtoul(buf, 16, &rgb);
- if (ret)
- return ret;
+ /* the ledclass has already stored the brightness value */
+ schedule_work(&led->rgb->work);
+}
- /* RGB triplet notation is 24-bit hexadecimal */
- if (rgb > 0xFFFFFF)
- return -EINVAL;
+static int thingm_init_rgb(struct thingm_rgb *rgb)
+{
+ const int minor = ((struct hidraw *) rgb->tdev->hdev->hidraw)->minor;
+ int err;
+
+ /* Register the red diode */
+ snprintf(rgb->red.name, sizeof(rgb->red.name),
+ "thingm%d:red:led%d", minor, rgb->num);
+ rgb->red.ldev.name = rgb->red.name;
+ rgb->red.ldev.max_brightness = 255;
+ rgb->red.ldev.brightness_set = thingm_led_set;
+ rgb->red.rgb = rgb;
+
+ err = led_classdev_register(&rgb->tdev->hdev->dev, &rgb->red.ldev);
+ if (err)
+ return err;
+
+ /* Register the green diode */
+ snprintf(rgb->green.name, sizeof(rgb->green.name),
+ "thingm%d:green:led%d", minor, rgb->num);
+ rgb->green.ldev.name = rgb->green.name;
+ rgb->green.ldev.max_brightness = 255;
+ rgb->green.ldev.brightness_set = thingm_led_set;
+ rgb->green.rgb = rgb;
+
+ err = led_classdev_register(&rgb->tdev->hdev->dev, &rgb->green.ldev);
+ if (err)
+ goto unregister_red;
+
+ /* Register the blue diode */
+ snprintf(rgb->blue.name, sizeof(rgb->blue.name),
+ "thingm%d:blue:led%d", minor, rgb->num);
+ rgb->blue.ldev.name = rgb->blue.name;
+ rgb->blue.ldev.max_brightness = 255;
+ rgb->blue.ldev.brightness_set = thingm_led_set;
+ rgb->blue.rgb = rgb;
+
+ err = led_classdev_register(&rgb->tdev->hdev->dev, &rgb->blue.ldev);
+ if (err)
+ goto unregister_green;
+
+ INIT_WORK(&rgb->work, thingm_work);
- data->rgb = rgb;
- ret = blink1_update_color(data);
+ return 0;
- return ret ? ret : count;
-}
+unregister_green:
+ led_classdev_unregister(&rgb->green.ldev);
-static DEVICE_ATTR(rgb, S_IRUGO | S_IWUSR, blink1_show_rgb, blink1_store_rgb);
+unregister_red:
+ led_classdev_unregister(&rgb->red.ldev);
-static const struct attribute_group blink1_sysfs_group = {
- .attrs = (struct attribute *[]) {
- &dev_attr_rgb.attr,
- NULL
- },
-};
+ return err;
+}
+
+static void thingm_remove_rgb(struct thingm_rgb *rgb)
+{
+ flush_work(&rgb->work);
+ led_classdev_unregister(&rgb->red.ldev);
+ led_classdev_unregister(&rgb->green.ldev);
+ led_classdev_unregister(&rgb->blue.ldev);
+}
static int thingm_probe(struct hid_device *hdev, const struct hid_device_id *id)
{
- struct blink1_data *data;
- struct led_classdev *led;
- char led_name[13];
- int ret;
+ struct thingm_device *tdev;
+ int i, err;
- data = devm_kzalloc(&hdev->dev, sizeof(struct blink1_data), GFP_KERNEL);
- if (!data)
+ tdev = devm_kzalloc(&hdev->dev, sizeof(struct thingm_device),
+ GFP_KERNEL);
+ if (!tdev)
return -ENOMEM;
- hid_set_drvdata(hdev, data);
- data->hdev = hdev;
- data->rgb = 0xFFFFFF; /* set a default white color */
+ tdev->hdev = hdev;
+ hid_set_drvdata(hdev, tdev);
- ret = hid_parse(hdev);
- if (ret)
+ err = hid_parse(hdev);
+ if (err)
goto error;
- ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW);
- if (ret)
+ err = hid_hw_start(hdev, HID_CONNECT_HIDRAW);
+ if (err)
goto error;
- /* blink(1) serial numbers range is 0x1A001000 to 0x1A002FFF */
- led = &data->led_cdev;
- snprintf(led_name, sizeof(led_name), "blink1::%s", hdev->uniq + 4);
- led->name = led_name;
- led->brightness_set = blink1_led_set;
- led->brightness_get = blink1_led_get;
- ret = led_classdev_register(&hdev->dev, led);
- if (ret)
+ mutex_init(&tdev->lock);
+
+ err = thingm_version(tdev);
+ if (err)
goto stop;
- ret = sysfs_create_group(&led->dev->kobj, &blink1_sysfs_group);
- if (ret)
- goto remove_led;
+ hid_dbg(hdev, "firmware version: %c.%c\n",
+ tdev->version.major, tdev->version.minor);
- return 0;
+ for (i = 0; i < ARRAY_SIZE(thingm_fwinfo) && !tdev->fwinfo; ++i)
+ if (thingm_fwinfo[i].major == tdev->version.major)
+ tdev->fwinfo = &thingm_fwinfo[i];
+
+ if (!tdev->fwinfo) {
+ hid_err(hdev, "unsupported firmware %c\n", tdev->version.major);
+ goto stop;
+ }
+
+ tdev->rgb = devm_kzalloc(&hdev->dev,
+ sizeof(struct thingm_rgb) * tdev->fwinfo->numrgb,
+ GFP_KERNEL);
+ if (!tdev->rgb) {
+ err = -ENOMEM;
+ goto stop;
+ }
+
+ for (i = 0; i < tdev->fwinfo->numrgb; ++i) {
+ struct thingm_rgb *rgb = tdev->rgb + i;
+
+ rgb->tdev = tdev;
+ rgb->num = tdev->fwinfo->first + i;
+ err = thingm_init_rgb(rgb);
+ if (err) {
+ while (--i >= 0)
+ thingm_remove_rgb(tdev->rgb + i);
+ goto stop;
+ }
+ }
-remove_led:
- led_classdev_unregister(led);
+ return 0;
stop:
hid_hw_stop(hdev);
error:
- return ret;
+ return err;
}
static void thingm_remove(struct hid_device *hdev)
{
- struct blink1_data *data = hid_get_drvdata(hdev);
- struct led_classdev *led = &data->led_cdev;
+ struct thingm_device *tdev = hid_get_drvdata(hdev);
+ int i;
+
+ for (i = 0; i < tdev->fwinfo->numrgb; ++i)
+ thingm_remove_rgb(tdev->rgb + i);
- sysfs_remove_group(&led->dev->kobj, &blink1_sysfs_group);
- led_classdev_unregister(led);
hid_hw_stop(hdev);
}
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 72156c1..46c7d79 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -479,6 +479,8 @@ config LEDS_OT200
This option enables support for the LEDs on the Bachmann OT200.
Say Y to enable LEDs on the Bachmann OT200.
+comment "LED driver for blink(1) USB RGB LED is under Special HID drivers (HID_THINGM)"
+
config LEDS_BLINKM
tristate "LED support for the BlinkM I2C RGB LED"
depends on LEDS_CLASS
--
1.9.1
^ permalink raw reply related
* [PATCH 1/4] HID: (thingm) remove the "play" sysfs attribute
From: Vivien Didelot @ 2014-04-14 20:50 UTC (permalink / raw)
To: linux-input
Cc: Vivien Didelot, Jiri Kosina, linux-leds, Bryan Wu, Richard Purdie,
linux-kernel, kernel
In-Reply-To: <1397508620-15244-1-git-send-email-vivien.didelot@savoirfairelinux.com>
When the thingm driver registers an instance of LED class, it creates a
"play" sysfs attribute for this blink(1) specific feature.
Since this feature is not specific to the RGB chip but to the HID device
itself, let's remove this attribute from the LED instance and only
implement what is useful to switch on and off the LED.
This feature is still easily accessible through hidraw.
Signed-off-by: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
---
Documentation/ABI/testing/sysfs-driver-hid-thingm | 7 -----
drivers/hid/hid-thingm.c | 33 -----------------------
2 files changed, 40 deletions(-)
diff --git a/Documentation/ABI/testing/sysfs-driver-hid-thingm b/Documentation/ABI/testing/sysfs-driver-hid-thingm
index abcffee..fda6185 100644
--- a/Documentation/ABI/testing/sysfs-driver-hid-thingm
+++ b/Documentation/ABI/testing/sysfs-driver-hid-thingm
@@ -14,10 +14,3 @@ Description: This attribute allows to set a fade time in milliseconds for
the next color change. Read the attribute to know the current
fade time. The default value is set to 0 (no fade time). For
instance, set a fade time of 2 seconds with: echo 2000 > fade
-
-What: /sys/class/leds/blink1::<serial>/play
-Date: January 2013
-Contact: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
-Description: This attribute is used to play/pause the light patterns. Write 1
- to start playing, 0 to stop. Reading this attribute returns the
- current playing status.
diff --git a/drivers/hid/hid-thingm.c b/drivers/hid/hid-thingm.c
index a97c788..7e376b8 100644
--- a/drivers/hid/hid-thingm.c
+++ b/drivers/hid/hid-thingm.c
@@ -28,7 +28,6 @@
* @rgb: 8-bit per channel RGB notation.
* @fade: fade time in hundredths of a second.
* @brightness: brightness coefficient.
- * @play: play/pause in-memory patterns.
*/
struct blink1_data {
struct hid_device *hdev;
@@ -36,7 +35,6 @@ struct blink1_data {
u32 rgb;
u16 fade;
u8 brightness;
- bool play;
};
static int blink1_send_command(struct blink1_data *data,
@@ -155,41 +153,10 @@ static ssize_t blink1_store_fade(struct device *dev,
static DEVICE_ATTR(fade, S_IRUGO | S_IWUSR,
blink1_show_fade, blink1_store_fade);
-static ssize_t blink1_show_play(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct blink1_data *data = dev_get_drvdata(dev->parent);
-
- return sprintf(buf, "%d\n", data->play);
-}
-
-static ssize_t blink1_store_play(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- struct blink1_data *data = dev_get_drvdata(dev->parent);
- u8 cmd[BLINK1_CMD_SIZE] = { 1, 'p', 0, 0, 0, 0, 0, 0, 0 };
- long unsigned int play;
- int ret;
-
- ret = kstrtoul(buf, 10, &play);
- if (ret)
- return ret;
-
- data->play = !!play;
- cmd[2] = data->play;
- ret = blink1_send_command(data, cmd);
-
- return ret ? ret : count;
-}
-
-static DEVICE_ATTR(play, S_IRUGO | S_IWUSR,
- blink1_show_play, blink1_store_play);
-
static const struct attribute_group blink1_sysfs_group = {
.attrs = (struct attribute *[]) {
&dev_attr_rgb.attr,
&dev_attr_fade.attr,
- &dev_attr_play.attr,
NULL
},
};
--
1.9.1
^ permalink raw reply related
* Re: [patch]GPIO button is supposed to wake the system up if the wakeup attribute is set
From: Li, Aubrey @ 2014-04-14 15:42 UTC (permalink / raw)
To: One Thousand Gnomes; +Cc: dmitry.torokhov, sachin.kamat, linux-input
In-Reply-To: <20140410114810.73e1d4b6@alan.etchedpixels.co.uk>
ping...
On 2014/4/10 18:48, One Thousand Gnomes wrote:
> On Thu, 10 Apr 2014 10:11:09 +0800
> "Li, Aubrey" <aubrey.li@linux.intel.com> wrote:
>
>> When the wakeup attribute is set, GPIO button is supposed to set
>> irqflag - IRQF_NO_SUSPEND to request irq. So when the system enters
>> the suspend sleep mode, the GPIO irq keeps enabled and is able to
>> wake the system up.
>>
>> The affected/tested machines include Dell Venue 11 Pro and Asus T100TA.
>>
>> Signed-off-by: Aubrey Li <aubrey.li@linux.intel.com>
>
> Tested-by: Alan Cox <alan@linux.intel.com>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-input" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
>
^ permalink raw reply
* [PATCH v2] synaptics: Add min/max quirk for ThinkPad T431s, L440, S1 Yoga and X1
From: Hans de Goede @ 2014-04-14 15:02 UTC (permalink / raw)
To: Dmitry Torokhov; +Cc: Benjamin Tissoires, Peter Hutterer, linux-input
Hi All,
This v2 is an unchanges resend of v1 with Cc: stable added, as I should have
done for v1 already.
Regards,
Hans
^ permalink raw reply
* [PATCH v2] synaptics: Add min/max quirk for ThinkPad T431s, L440, S1 Yoga and X1
From: Hans de Goede @ 2014-04-14 15:02 UTC (permalink / raw)
To: Dmitry Torokhov
Cc: Benjamin Tissoires, Peter Hutterer, linux-input, Hans de Goede,
stable, Benjamin Tissoires
In-Reply-To: <1397487765-28856-1-git-send-email-hdegoede@redhat.com>
We expect that all the Haswell series will need such quirks, sigh.
The T431s seems to be T430 hardware in a T440s case, using the T440s touchpad,
with the same min/max issue.
The X1 Carbon 3rd generation name says 2nd while it is a 3rd generation.
The X1 and T431s share a PnPID with the T540p, but the reported ranges are
closer to those of the T440s.
HdG: Squashed 4 quirk patches into one. T431s + L440 are written by me,
S1 Yoga and X1 are written by Benjamin Tissoires.
Cc: stable@vger.kernel.org
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
drivers/input/mouse/synaptics.c | 34 ++++++++++++++++++++++++++++++++++
1 file changed, 34 insertions(+)
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
index b9d2259..521a8e7 100644
--- a/drivers/input/mouse/synaptics.c
+++ b/drivers/input/mouse/synaptics.c
@@ -1557,6 +1557,14 @@ static const struct dmi_system_id min_max_dmi_table[] __initconst = {
.driver_data = (int []){1232, 5710, 1156, 4696},
},
{
+ /* Lenovo ThinkPad T431s */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T431"),
+ },
+ .driver_data = (int []){1024, 5112, 2024, 4832},
+ },
+ {
/* Lenovo ThinkPad T440s */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
@@ -1565,6 +1573,14 @@ static const struct dmi_system_id min_max_dmi_table[] __initconst = {
.driver_data = (int []){1024, 5112, 2024, 4832},
},
{
+ /* Lenovo ThinkPad L440 */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad L440"),
+ },
+ .driver_data = (int []){1024, 5112, 2024, 4832},
+ },
+ {
/* Lenovo ThinkPad T540p */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
@@ -1572,6 +1588,24 @@ static const struct dmi_system_id min_max_dmi_table[] __initconst = {
},
.driver_data = (int []){1024, 5056, 2058, 4832},
},
+ {
+ /* Lenovo Yoga S1 */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_VERSION,
+ "ThinkPad S1 Yoga"),
+ },
+ .driver_data = (int []){1232, 5711, 1159, 4700},
+ },
+ {
+ /* Lenovo ThinkPad X1 Carbon Haswell (3rd generation) */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_VERSION,
+ "ThinkPad X1 Carbon 2nd"),
+ },
+ .driver_data = (int []){1131, 5113, 2021, 4831},
+ },
#endif
{ }
};
--
1.9.0
^ permalink raw reply related
* [PATCH v5 6/7] HID: sony: Add blink support to the Sixaxis and DualShock 4 LEDs
From: Frank Praznik @ 2014-04-14 14:11 UTC (permalink / raw)
To: linux-input; +Cc: jkosina, simon, Frank Praznik
In-Reply-To: <1397484697-2389-1-git-send-email-frank.praznik@oh.rr.com>
Add support for setting the blink rate of the LEDs. The Sixaxis allows control
over each individual LED, but the Dualshock 4 only has one global control for
controlling the hardware blink rate so individual colors will fall back to
software timers.
Setting the brightness cancels the blinking as per the LED class specifications.
The Sixaxis and Dualshock 4 controllers accept delays in decisecond increments
from 0 to 255 (2550 milliseconds).
The value at index 1 of the DualShock 4 USB output report must be 0xFF or the
light bar won't blink.
Signed-off-by: Frank Praznik <frank.praznik@oh.rr.com>
---
v5 addresses some usability issues that arose during testing.
The Sixaxis, when on USB, has an annoying quirk where it will override any LED
settings and flash the whole light bar until the PS button is pushed. Since
the driver can't tell if the controller is overriding the user LED settings,
all led brightness requests are sent to the controller even if they are
redundant. This allows for the user to stop the blinking by setting the
brightness even if the current brightness is already in the desired state.
The DualShock 4 now has an extra 'global' LED control that allows the
whole light bar to be turned on and off synchronously instead of having all
of the individual LEDs map to one global set of delay values.
This fixes inconsistencies that arose in the old system where each individual
LED mapped to one hardware blink delay. This caused conflicts if different
LEDs had different triggers assigned to each one and the triggers overrode
each other's settings. It also made it impossible to flash the light bar
synchronously with triggers like 'heartbeat' that control blinking by running
a software timer and directly manipulating the brightness value, nor could a
user set the blink rate of the individual colors if they wanted to.
This change also allows for the removal of some DS4 specific special-case code
in the blink and brightness functions that was present in the previous
patches.
drivers/hid/hid-sony.c | 149 ++++++++++++++++++++++++++++++++++++++++---------
1 file changed, 124 insertions(+), 25 deletions(-)
diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c
index f1649d0..54a04ba 100644
--- a/drivers/hid/hid-sony.c
+++ b/drivers/hid/hid-sony.c
@@ -773,6 +773,8 @@ struct sony_sc {
__u8 battery_charging;
__u8 battery_capacity;
__u8 led_state[MAX_LEDS];
+ __u8 led_delay_on[MAX_LEDS];
+ __u8 led_delay_off[MAX_LEDS];
__u8 led_count;
};
@@ -1168,6 +1170,7 @@ static void sony_led_set_brightness(struct led_classdev *led,
struct sony_sc *drv_data;
int n;
+ int force_update;
drv_data = hid_get_drvdata(hdev);
if (!drv_data) {
@@ -1175,13 +1178,29 @@ static void sony_led_set_brightness(struct led_classdev *led,
return;
}
+ /*
+ * The Sixaxis on USB will override any LED settings sent to it
+ * and keep flashing all of the LEDs until the PS button is pressed.
+ * Updates, even if redundant, must be always be sent to the
+ * controller to avoid having to toggle the state of an LED just to
+ * stop the flashing later on.
+ */
+ force_update = !!(drv_data->quirks & SIXAXIS_CONTROLLER_USB);
+
for (n = 0; n < drv_data->led_count; n++) {
- if (led == drv_data->leds[n]) {
- if (value != drv_data->led_state[n]) {
- drv_data->led_state[n] = value;
- sony_set_leds(drv_data, drv_data->led_state,
- drv_data->led_count);
- }
+ if (led == drv_data->leds[n] && (force_update ||
+ (value != drv_data->led_state[n] ||
+ drv_data->led_delay_on[n] ||
+ drv_data->led_delay_off[n]))) {
+
+ drv_data->led_state[n] = value;
+
+ /* Setting the brightness stops the blinking */
+ drv_data->led_delay_on[n] = 0;
+ drv_data->led_delay_off[n] = 0;
+
+ sony_set_leds(drv_data, drv_data->led_state,
+ drv_data->led_count);
break;
}
}
@@ -1209,6 +1228,53 @@ static enum led_brightness sony_led_get_brightness(struct led_classdev *led)
return LED_OFF;
}
+static int sony_led_blink_set(struct led_classdev *led, unsigned long *delay_on,
+ unsigned long *delay_off)
+{
+ struct device *dev = led->dev->parent;
+ struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct sony_sc *drv_data = hid_get_drvdata(hdev);
+ int n;
+ __u8 new_on, new_off;
+
+ if (!drv_data) {
+ hid_err(hdev, "No device data\n");
+ return -EINVAL;
+ }
+
+ /* Max delay is 255 deciseconds or 2550 milliseconds */
+ if (*delay_on > 2550)
+ *delay_on = 2550;
+ if (*delay_off > 2550)
+ *delay_off = 2550;
+
+ /* Blink at 1 Hz if both values are zero */
+ if (!*delay_on && !*delay_off)
+ *delay_on = *delay_off = 500;
+
+ new_on = *delay_on / 10;
+ new_off = *delay_off / 10;
+
+ for (n = 0; n < drv_data->led_count; n++) {
+ if (led == drv_data->leds[n])
+ break;
+ }
+
+ /* This LED is not registered on this device */
+ if (n >= drv_data->led_count)
+ return -EINVAL;
+
+ /* Don't schedule work if the values didn't change */
+ if (new_on != drv_data->led_delay_on[n] ||
+ new_off != drv_data->led_delay_off[n]) {
+ drv_data->led_delay_on[n] = new_on;
+ drv_data->led_delay_off[n] = new_off;
+ schedule_work(&drv_data->state_worker);
+ }
+
+ return 0;
+}
+
static void sony_leds_remove(struct sony_sc *sc)
{
struct led_classdev *led;
@@ -1232,22 +1298,23 @@ static int sony_leds_init(struct sony_sc *sc)
{
struct hid_device *hdev = sc->hdev;
int n, ret = 0;
- int max_brightness;
- int use_colors;
+ int use_ds4_names;
struct led_classdev *led;
size_t name_sz;
char *name;
size_t name_len;
const char *name_fmt;
- static const char * const color_str[] = { "red", "green", "blue" };
+ static const char * const ds4_name_str[] = { "red", "green", "blue",
+ "global" };
__u8 initial_values[MAX_LEDS] = { 0 };
+ __u8 max_brightness[MAX_LEDS] = { 1 };
+ __u8 use_hw_blink[MAX_LEDS] = { 0 };
BUG_ON(!(sc->quirks & SONY_LED_SUPPORT));
if (sc->quirks & BUZZ_CONTROLLER) {
sc->led_count = 4;
- max_brightness = 1;
- use_colors = 0;
+ use_ds4_names = 0;
name_len = strlen("::buzz#");
name_fmt = "%s::buzz%d";
/* Validate expected report characteristics. */
@@ -1255,16 +1322,18 @@ static int sony_leds_init(struct sony_sc *sc)
return -ENODEV;
} else if (sc->quirks & DUALSHOCK4_CONTROLLER) {
dualshock4_set_leds_from_id(sc->device_id, initial_values);
- sc->led_count = 3;
- max_brightness = 255;
- use_colors = 1;
+ initial_values[3] = 1;
+ sc->led_count = 4;
+ memset(max_brightness, 255, 3);
+ use_hw_blink[3] = 1;
+ use_ds4_names = 1;
name_len = 0;
name_fmt = "%s:%s";
} else {
sixaxis_set_leds_from_id(sc->device_id, initial_values);
sc->led_count = 4;
- max_brightness = 1;
- use_colors = 0;
+ memset(use_hw_blink, 1, 4);
+ use_ds4_names = 0;
name_len = strlen("::sony#");
name_fmt = "%s::sony%d";
}
@@ -1280,8 +1349,8 @@ static int sony_leds_init(struct sony_sc *sc)
for (n = 0; n < sc->led_count; n++) {
- if (use_colors)
- name_sz = strlen(dev_name(&hdev->dev)) + strlen(color_str[n]) + 2;
+ if (use_ds4_names)
+ name_sz = strlen(dev_name(&hdev->dev)) + strlen(ds4_name_str[n]) + 2;
led = kzalloc(sizeof(struct led_classdev) + name_sz, GFP_KERNEL);
if (!led) {
@@ -1291,16 +1360,20 @@ static int sony_leds_init(struct sony_sc *sc)
}
name = (void *)(&led[1]);
- if (use_colors)
- snprintf(name, name_sz, name_fmt, dev_name(&hdev->dev), color_str[n]);
+ if (use_ds4_names)
+ snprintf(name, name_sz, name_fmt, dev_name(&hdev->dev),
+ ds4_name_str[n]);
else
snprintf(name, name_sz, name_fmt, dev_name(&hdev->dev), n + 1);
led->name = name;
led->brightness = initial_values[n];
- led->max_brightness = max_brightness;
+ led->max_brightness = max_brightness[n];
led->brightness_get = sony_led_get_brightness;
led->brightness_set = sony_led_set_brightness;
+ if (use_hw_blink[n])
+ led->blink_set = sony_led_blink_set;
+
sc->leds[n] = led;
ret = led_classdev_register(&hdev->dev, led);
@@ -1323,6 +1396,7 @@ error_leds:
static void sixaxis_state_worker(struct work_struct *work)
{
struct sony_sc *sc = container_of(work, struct sony_sc, state_worker);
+ int n;
union sixaxis_output_report_01 report = {
.buf = {
0x01,
@@ -1346,6 +1420,22 @@ static void sixaxis_state_worker(struct work_struct *work)
report.data.leds_bitmap |= sc->led_state[2] << 3;
report.data.leds_bitmap |= sc->led_state[3] << 4;
+ /*
+ * The LEDs in the report are indexed in reverse order to their
+ * corresponding light on the controller.
+ * Index 0 = LED 4, index 1 = LED 3, etc...
+ *
+ * In the case of both delay values being zero (blinking disabled) the
+ * default report values should be used or the controller LED will be
+ * always off.
+ */
+ for (n = 0; n < 4; n++) {
+ if (sc->led_delay_on[n] || sc->led_delay_off[n]) {
+ report.data.led[3 - n].duty_off = sc->led_delay_off[n];
+ report.data.led[3 - n].duty_on = sc->led_delay_on[n];
+ }
+ }
+
hid_hw_raw_request(sc->hdev, report.data.report_id, report.buf,
sizeof(report), HID_OUTPUT_REPORT, HID_REQ_SET_REPORT);
}
@@ -1360,7 +1450,7 @@ static void dualshock4_state_worker(struct work_struct *work)
if (sc->quirks & DUALSHOCK4_CONTROLLER_USB) {
buf[0] = 0x05;
- buf[1] = 0x03;
+ buf[1] = 0xFF;
offset = 4;
} else {
buf[0] = 0x11;
@@ -1376,9 +1466,18 @@ static void dualshock4_state_worker(struct work_struct *work)
offset += 2;
#endif
- buf[offset++] = sc->led_state[0];
- buf[offset++] = sc->led_state[1];
- buf[offset++] = sc->led_state[2];
+ /* LED 3 is the global control */
+ if (sc->led_state[3]) {
+ buf[offset++] = sc->led_state[0];
+ buf[offset++] = sc->led_state[1];
+ buf[offset++] = sc->led_state[2];
+ } else {
+ offset += 3;
+ }
+
+ /* If both delay values are zero the DualShock 4 disables blinking. */
+ buf[offset++] = sc->led_delay_on[3];
+ buf[offset++] = sc->led_delay_off[3];
if (sc->quirks & DUALSHOCK4_CONTROLLER_USB)
hid_hw_output_report(hdev, buf, 32);
--
1.8.5.3
^ permalink raw reply related
* [PATCH v5 7/7] HID: hid-sony - allow 3rd party INTEC controller to turn off all leds
From: Frank Praznik @ 2014-04-14 14:11 UTC (permalink / raw)
To: linux-input; +Cc: jkosina, simon, Frank Praznik
In-Reply-To: <1397484697-2389-1-git-send-email-frank.praznik@oh.rr.com>
From: Simon Wood <simon@mungewell.org>
Without this patch the 3rd party INTEC (PS3) controller will blink all
leds when user turns them off, it appears to require an extra flag set.
Signed-off-by: Simon Wood <simon@mungewell.org>
Signed-off-by: Frank Praznik <frank.praznik@oh.rr.com>
---
drivers/hid/hid-sony.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c
index 54a04ba..bc3c6ee 100644
--- a/drivers/hid/hid-sony.c
+++ b/drivers/hid/hid-sony.c
@@ -1420,6 +1420,10 @@ static void sixaxis_state_worker(struct work_struct *work)
report.data.leds_bitmap |= sc->led_state[2] << 3;
report.data.leds_bitmap |= sc->led_state[3] << 4;
+ /* Set flag for all leds off, required for 3rd party INTEC controller */
+ if ((report.data.leds_bitmap & 0x1E) == 0)
+ report.data.leds_bitmap |= 0x20;
+
/*
* The LEDs in the report are indexed in reverse order to their
* corresponding light on the controller.
--
1.8.5.3
^ permalink raw reply related
* [PATCH v5 5/7] HID: sony: Initialize the controller LEDs with a device ID value
From: Frank Praznik @ 2014-04-14 14:11 UTC (permalink / raw)
To: linux-input; +Cc: jkosina, simon, Frank Praznik
In-Reply-To: <1397484697-2389-1-git-send-email-frank.praznik@oh.rr.com>
Add an IDA id allocator to assign unique, sequential device ids to Sixaxis and
DualShock 4 controllers.
Use the device ID to initialize the Sixaxis and DualShock 4 controller LEDs to
default values. The number or color of the controller is set relative to other
connected Sony controllers.
Set the LED class brightness values to the initial values and add the new led to
the array before calling led_classdev_register so that the correct brightness
value shows up in the LED sysfs entry.
Use explicit module init and exit functions since the IDA allocator must be
manually destroyed when the module is unloaded.
Signed-off-by: Frank Praznik <frank.praznik@oh.rr.com>
---
drivers/hid/hid-sony.c | 119 ++++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 114 insertions(+), 5 deletions(-)
diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c
index c709161..f1649d0 100644
--- a/drivers/hid/hid-sony.c
+++ b/drivers/hid/hid-sony.c
@@ -33,6 +33,7 @@
#include <linux/power_supply.h>
#include <linux/spinlock.h>
#include <linux/list.h>
+#include <linux/idr.h>
#include <linux/input/mt.h>
#include "hid-ids.h"
@@ -749,6 +750,7 @@ union sixaxis_output_report_01 {
static spinlock_t sony_dev_list_lock;
static LIST_HEAD(sony_device_list);
+static DEFINE_IDA(sony_device_id_allocator);
struct sony_sc {
spinlock_t lock;
@@ -758,6 +760,7 @@ struct sony_sc {
unsigned long quirks;
struct work_struct state_worker;
struct power_supply battery;
+ int device_id;
#ifdef CONFIG_SONY_FF
__u8 left;
@@ -1078,6 +1081,52 @@ static int dualshock4_set_operational_bt(struct hid_device *hdev)
HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
}
+static void sixaxis_set_leds_from_id(int id, __u8 values[MAX_LEDS])
+{
+ static const __u8 sixaxis_leds[10][4] = {
+ { 0x01, 0x00, 0x00, 0x00 },
+ { 0x00, 0x01, 0x00, 0x00 },
+ { 0x00, 0x00, 0x01, 0x00 },
+ { 0x00, 0x00, 0x00, 0x01 },
+ { 0x01, 0x00, 0x00, 0x01 },
+ { 0x00, 0x01, 0x00, 0x01 },
+ { 0x00, 0x00, 0x01, 0x01 },
+ { 0x01, 0x00, 0x01, 0x01 },
+ { 0x00, 0x01, 0x01, 0x01 },
+ { 0x01, 0x01, 0x01, 0x01 }
+ };
+
+ BUG_ON(MAX_LEDS < ARRAY_SIZE(sixaxis_leds[0]));
+
+ if (id < 0)
+ return;
+
+ id %= 10;
+ memcpy(values, sixaxis_leds[id], sizeof(sixaxis_leds[id]));
+}
+
+static void dualshock4_set_leds_from_id(int id, __u8 values[MAX_LEDS])
+{
+ /* The first 4 color/index entries match what the PS4 assigns */
+ static const __u8 color_code[7][3] = {
+ /* Blue */ { 0x00, 0x00, 0x01 },
+ /* Red */ { 0x01, 0x00, 0x00 },
+ /* Green */ { 0x00, 0x01, 0x00 },
+ /* Pink */ { 0x02, 0x00, 0x01 },
+ /* Orange */ { 0x02, 0x01, 0x00 },
+ /* Teal */ { 0x00, 0x01, 0x01 },
+ /* White */ { 0x01, 0x01, 0x01 }
+ };
+
+ BUG_ON(MAX_LEDS < ARRAY_SIZE(color_code[0]));
+
+ if (id < 0)
+ return;
+
+ id %= 7;
+ memcpy(values, color_code[id], sizeof(color_code[id]));
+}
+
static void buzz_set_leds(struct hid_device *hdev, const __u8 *leds)
{
struct list_head *report_list =
@@ -1191,7 +1240,7 @@ static int sony_leds_init(struct sony_sc *sc)
size_t name_len;
const char *name_fmt;
static const char * const color_str[] = { "red", "green", "blue" };
- static const __u8 initial_values[MAX_LEDS] = { 0x00, 0x00, 0x00, 0x00 };
+ __u8 initial_values[MAX_LEDS] = { 0 };
BUG_ON(!(sc->quirks & SONY_LED_SUPPORT));
@@ -1205,12 +1254,14 @@ static int sony_leds_init(struct sony_sc *sc)
if (!hid_validate_values(hdev, HID_OUTPUT_REPORT, 0, 0, 7))
return -ENODEV;
} else if (sc->quirks & DUALSHOCK4_CONTROLLER) {
+ dualshock4_set_leds_from_id(sc->device_id, initial_values);
sc->led_count = 3;
max_brightness = 255;
use_colors = 1;
name_len = 0;
name_fmt = "%s:%s";
} else {
+ sixaxis_set_leds_from_id(sc->device_id, initial_values);
sc->led_count = 4;
max_brightness = 1;
use_colors = 0;
@@ -1245,19 +1296,20 @@ static int sony_leds_init(struct sony_sc *sc)
else
snprintf(name, name_sz, name_fmt, dev_name(&hdev->dev), n + 1);
led->name = name;
- led->brightness = 0;
+ led->brightness = initial_values[n];
led->max_brightness = max_brightness;
led->brightness_get = sony_led_get_brightness;
led->brightness_set = sony_led_set_brightness;
+ sc->leds[n] = led;
+
ret = led_classdev_register(&hdev->dev, led);
if (ret) {
hid_err(hdev, "Failed to register LED %d\n", n);
+ sc->leds[n] = NULL;
kfree(led);
goto error_leds;
}
-
- sc->leds[n] = led;
}
return ret;
@@ -1603,6 +1655,38 @@ static int sony_check_add(struct sony_sc *sc)
return sony_check_add_dev_list(sc);
}
+static int sony_set_device_id(struct sony_sc *sc)
+{
+ int ret;
+
+ /*
+ * Only DualShock 4 or Sixaxis controllers get an id.
+ * All others are set to -1.
+ */
+ if ((sc->quirks & SIXAXIS_CONTROLLER) ||
+ (sc->quirks & DUALSHOCK4_CONTROLLER)) {
+ ret = ida_simple_get(&sony_device_id_allocator, 0, 0,
+ GFP_KERNEL);
+ if (ret < 0) {
+ sc->device_id = -1;
+ return ret;
+ }
+ sc->device_id = ret;
+ } else {
+ sc->device_id = -1;
+ }
+
+ return 0;
+}
+
+static void sony_release_device_id(struct sony_sc *sc)
+{
+ if (sc->device_id >= 0) {
+ ida_simple_remove(&sony_device_id_allocator, sc->device_id);
+ sc->device_id = -1;
+ }
+}
+
static inline void sony_init_work(struct sony_sc *sc,
void(*worker)(struct work_struct *))
{
@@ -1654,6 +1738,12 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
return ret;
}
+ ret = sony_set_device_id(sc);
+ if (ret < 0) {
+ hid_err(hdev, "failed to allocate the device id\n");
+ goto err_stop;
+ }
+
if (sc->quirks & SIXAXIS_CONTROLLER_USB) {
/*
* The Sony Sixaxis does not handle HID Output Reports on the
@@ -1745,6 +1835,7 @@ err_stop:
sony_battery_remove(sc);
sony_cancel_work_sync(sc);
sony_remove_dev_list(sc);
+ sony_release_device_id(sc);
hid_hw_stop(hdev);
return ret;
}
@@ -1765,6 +1856,8 @@ static void sony_remove(struct hid_device *hdev)
sony_remove_dev_list(sc);
+ sony_release_device_id(sc);
+
hid_hw_stop(hdev);
}
@@ -1809,6 +1902,22 @@ static struct hid_driver sony_driver = {
.report_fixup = sony_report_fixup,
.raw_event = sony_raw_event
};
-module_hid_driver(sony_driver);
+
+static int __init sony_init(void)
+{
+ dbg_hid("Sony:%s\n", __func__);
+
+ return hid_register_driver(&sony_driver);
+}
+
+static void __exit sony_exit(void)
+{
+ dbg_hid("Sony:%s\n", __func__);
+
+ ida_destroy(&sony_device_id_allocator);
+ hid_unregister_driver(&sony_driver);
+}
+module_init(sony_init);
+module_exit(sony_exit);
MODULE_LICENSE("GPL");
--
1.8.5.3
^ permalink raw reply related
* [PATCH v5 4/7] HID: sony: Use the controller Bluetooth MAC address as the unique value in the battery name string
From: Frank Praznik @ 2014-04-14 14:11 UTC (permalink / raw)
To: linux-input; +Cc: jkosina, simon, Frank Praznik
In-Reply-To: <1397484697-2389-1-git-send-email-frank.praznik@oh.rr.com>
Use the controller Bluetooth MAC address as the unique identifier in the
battery name string instead of the atomic integer that was used before.
Signed-off-by: Frank Praznik <frank.praznik@oh.rr.com>
---
drivers/hid/hid-sony.c | 8 ++------
1 file changed, 2 insertions(+), 6 deletions(-)
diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c
index a86542a..c709161 100644
--- a/drivers/hid/hid-sony.c
+++ b/drivers/hid/hid-sony.c
@@ -1413,8 +1413,6 @@ static int sony_battery_get_property(struct power_supply *psy,
static int sony_battery_probe(struct sony_sc *sc)
{
- static atomic_t power_id_seq = ATOMIC_INIT(0);
- unsigned long power_id;
struct hid_device *hdev = sc->hdev;
int ret;
@@ -1424,15 +1422,13 @@ static int sony_battery_probe(struct sony_sc *sc)
*/
sc->battery_capacity = 100;
- power_id = (unsigned long)atomic_inc_return(&power_id_seq);
-
sc->battery.properties = sony_battery_props;
sc->battery.num_properties = ARRAY_SIZE(sony_battery_props);
sc->battery.get_property = sony_battery_get_property;
sc->battery.type = POWER_SUPPLY_TYPE_BATTERY;
sc->battery.use_for_apm = 0;
- sc->battery.name = kasprintf(GFP_KERNEL, "sony_controller_battery_%lu",
- power_id);
+ sc->battery.name = kasprintf(GFP_KERNEL, "sony_controller_battery_%pMR",
+ sc->mac_address);
if (!sc->battery.name)
return -ENOMEM;
--
1.8.5.3
^ permalink raw reply related
* [PATCH v5 3/7] HID: sony: Convert startup and shutdown functions to use a uniform parameter type
From: Frank Praznik @ 2014-04-14 14:11 UTC (permalink / raw)
To: linux-input; +Cc: jkosina, simon, Frank Praznik
In-Reply-To: <1397484697-2389-1-git-send-email-frank.praznik@oh.rr.com>
Convert all of the local initialization and shutdown functions to take a
parameter type of struct sony_sc* instead of using a mix of struct sony_sc* and
struct hid_device*.
Allows for the removal of some calls to hid_get_drvdata().
Signed-off-by: Frank Praznik <frank.praznik@oh.rr.com>
---
drivers/hid/hid-sony.c | 67 ++++++++++++++++++++++++--------------------------
1 file changed, 32 insertions(+), 35 deletions(-)
diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c
index ed68962..a86542a 100644
--- a/drivers/hid/hid-sony.c
+++ b/drivers/hid/hid-sony.c
@@ -1096,19 +1096,18 @@ static void buzz_set_leds(struct hid_device *hdev, const __u8 *leds)
hid_hw_request(hdev, report, HID_REQ_SET_REPORT);
}
-static void sony_set_leds(struct hid_device *hdev, const __u8 *leds, int count)
+static void sony_set_leds(struct sony_sc *sc, const __u8 *leds, int count)
{
- struct sony_sc *drv_data = hid_get_drvdata(hdev);
int n;
BUG_ON(count > MAX_LEDS);
- if (drv_data->quirks & BUZZ_CONTROLLER && count == 4) {
- buzz_set_leds(hdev, leds);
+ if (sc->quirks & BUZZ_CONTROLLER && count == 4) {
+ buzz_set_leds(sc->hdev, leds);
} else {
for (n = 0; n < count; n++)
- drv_data->led_state[n] = leds[n];
- schedule_work(&drv_data->state_worker);
+ sc->led_state[n] = leds[n];
+ schedule_work(&sc->state_worker);
}
}
@@ -1131,7 +1130,8 @@ static void sony_led_set_brightness(struct led_classdev *led,
if (led == drv_data->leds[n]) {
if (value != drv_data->led_state[n]) {
drv_data->led_state[n] = value;
- sony_set_leds(hdev, drv_data->led_state, drv_data->led_count);
+ sony_set_leds(drv_data, drv_data->led_state,
+ drv_data->led_count);
}
break;
}
@@ -1160,30 +1160,28 @@ static enum led_brightness sony_led_get_brightness(struct led_classdev *led)
return LED_OFF;
}
-static void sony_leds_remove(struct hid_device *hdev)
+static void sony_leds_remove(struct sony_sc *sc)
{
- struct sony_sc *drv_data;
struct led_classdev *led;
int n;
- drv_data = hid_get_drvdata(hdev);
- BUG_ON(!(drv_data->quirks & SONY_LED_SUPPORT));
+ BUG_ON(!(sc->quirks & SONY_LED_SUPPORT));
- for (n = 0; n < drv_data->led_count; n++) {
- led = drv_data->leds[n];
- drv_data->leds[n] = NULL;
+ for (n = 0; n < sc->led_count; n++) {
+ led = sc->leds[n];
+ sc->leds[n] = NULL;
if (!led)
continue;
led_classdev_unregister(led);
kfree(led);
}
- drv_data->led_count = 0;
+ sc->led_count = 0;
}
-static int sony_leds_init(struct hid_device *hdev)
+static int sony_leds_init(struct sony_sc *sc)
{
- struct sony_sc *drv_data;
+ struct hid_device *hdev = sc->hdev;
int n, ret = 0;
int max_brightness;
int use_colors;
@@ -1195,11 +1193,10 @@ static int sony_leds_init(struct hid_device *hdev)
static const char * const color_str[] = { "red", "green", "blue" };
static const __u8 initial_values[MAX_LEDS] = { 0x00, 0x00, 0x00, 0x00 };
- drv_data = hid_get_drvdata(hdev);
- BUG_ON(!(drv_data->quirks & SONY_LED_SUPPORT));
+ BUG_ON(!(sc->quirks & SONY_LED_SUPPORT));
- if (drv_data->quirks & BUZZ_CONTROLLER) {
- drv_data->led_count = 4;
+ if (sc->quirks & BUZZ_CONTROLLER) {
+ sc->led_count = 4;
max_brightness = 1;
use_colors = 0;
name_len = strlen("::buzz#");
@@ -1207,14 +1204,14 @@ static int sony_leds_init(struct hid_device *hdev)
/* Validate expected report characteristics. */
if (!hid_validate_values(hdev, HID_OUTPUT_REPORT, 0, 0, 7))
return -ENODEV;
- } else if (drv_data->quirks & DUALSHOCK4_CONTROLLER) {
- drv_data->led_count = 3;
+ } else if (sc->quirks & DUALSHOCK4_CONTROLLER) {
+ sc->led_count = 3;
max_brightness = 255;
use_colors = 1;
name_len = 0;
name_fmt = "%s:%s";
} else {
- drv_data->led_count = 4;
+ sc->led_count = 4;
max_brightness = 1;
use_colors = 0;
name_len = strlen("::sony#");
@@ -1226,11 +1223,11 @@ static int sony_leds_init(struct hid_device *hdev)
* only relevant if the driver is loaded after somebody actively set the
* LEDs to on
*/
- sony_set_leds(hdev, initial_values, drv_data->led_count);
+ sony_set_leds(sc, initial_values, sc->led_count);
name_sz = strlen(dev_name(&hdev->dev)) + name_len + 1;
- for (n = 0; n < drv_data->led_count; n++) {
+ for (n = 0; n < sc->led_count; n++) {
if (use_colors)
name_sz = strlen(dev_name(&hdev->dev)) + strlen(color_str[n]) + 2;
@@ -1260,13 +1257,13 @@ static int sony_leds_init(struct hid_device *hdev)
goto error_leds;
}
- drv_data->leds[n] = led;
+ sc->leds[n] = led;
}
return ret;
error_leds:
- sony_leds_remove(hdev);
+ sony_leds_remove(sc);
return ret;
}
@@ -1355,9 +1352,9 @@ static int sony_play_effect(struct input_dev *dev, void *data,
return 0;
}
-static int sony_init_ff(struct hid_device *hdev)
+static int sony_init_ff(struct sony_sc *sc)
{
- struct hid_input *hidinput = list_entry(hdev->inputs.next,
+ struct hid_input *hidinput = list_entry(sc->hdev->inputs.next,
struct hid_input, list);
struct input_dev *input_dev = hidinput->input;
@@ -1366,7 +1363,7 @@ static int sony_init_ff(struct hid_device *hdev)
}
#else
-static int sony_init_ff(struct hid_device *hdev)
+static int sony_init_ff(struct sony_sc *sc)
{
return 0;
}
@@ -1718,7 +1715,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
goto err_stop;
if (sc->quirks & SONY_LED_SUPPORT) {
- ret = sony_leds_init(hdev);
+ ret = sony_leds_init(sc);
if (ret < 0)
goto err_stop;
}
@@ -1737,7 +1734,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
}
if (sc->quirks & SONY_FF_SUPPORT) {
- ret = sony_init_ff(hdev);
+ ret = sony_init_ff(sc);
if (ret < 0)
goto err_close;
}
@@ -1747,7 +1744,7 @@ err_close:
hid_hw_close(hdev);
err_stop:
if (sc->quirks & SONY_LED_SUPPORT)
- sony_leds_remove(hdev);
+ sony_leds_remove(sc);
if (sc->quirks & SONY_BATTERY_SUPPORT)
sony_battery_remove(sc);
sony_cancel_work_sync(sc);
@@ -1761,7 +1758,7 @@ static void sony_remove(struct hid_device *hdev)
struct sony_sc *sc = hid_get_drvdata(hdev);
if (sc->quirks & SONY_LED_SUPPORT)
- sony_leds_remove(hdev);
+ sony_leds_remove(sc);
if (sc->quirks & SONY_BATTERY_SUPPORT) {
hid_hw_close(hdev);
--
1.8.5.3
^ permalink raw reply related
* [PATCH v5 2/7] HID: sony: Use a struct for the Sixaxis output report.
From: Frank Praznik @ 2014-04-14 14:11 UTC (permalink / raw)
To: linux-input; +Cc: jkosina, simon, Frank Praznik
In-Reply-To: <1397484697-2389-1-git-send-email-frank.praznik@oh.rr.com>
Use a struct for the Sixaxis output report that uses named members to set the
report fields.
Signed-off-by: Frank Praznik <frank.praznik@oh.rr.com>
---
drivers/hid/hid-sony.c | 66 +++++++++++++++++++++++++++++++++++++-------------
1 file changed, 49 insertions(+), 17 deletions(-)
diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c
index 3df3306..ed68962 100644
--- a/drivers/hid/hid-sony.c
+++ b/drivers/hid/hid-sony.c
@@ -717,6 +717,36 @@ static enum power_supply_property sony_battery_props[] = {
POWER_SUPPLY_PROP_STATUS,
};
+struct sixaxis_led {
+ __u8 time_enabled; /* the total time the led is active (0xff means forever) */
+ __u8 duty_length; /* how long a cycle is in deciseconds (0 means "really fast") */
+ __u8 enabled;
+ __u8 duty_off; /* % of duty_length the led is off (0xff means 100%) */
+ __u8 duty_on; /* % of duty_length the led is on (0xff mean 100%) */
+} __packed;
+
+struct sixaxis_rumble {
+ __u8 padding;
+ __u8 right_duration; /* Right motor duration (0xff means forever) */
+ __u8 right_motor_on; /* Right (small) motor on/off, only supports values of 0 or 1 (off/on) */
+ __u8 left_duration; /* Left motor duration (0xff means forever) */
+ __u8 left_motor_force; /* left (large) motor, supports force values from 0 to 255 */
+} __packed;
+
+struct sixaxis_output_report {
+ __u8 report_id;
+ struct sixaxis_rumble rumble;
+ __u8 padding[4];
+ __u8 leds_bitmap; /* bitmap of enabled LEDs: LED_1 = 0x02, LED_2 = 0x04, ... */
+ struct sixaxis_led led[4]; /* LEDx at (4 - x) */
+ struct sixaxis_led _reserved; /* LED5, not actually soldered */
+} __packed;
+
+union sixaxis_output_report_01 {
+ struct sixaxis_output_report data;
+ __u8 buf[36];
+};
+
static spinlock_t sony_dev_list_lock;
static LIST_HEAD(sony_device_list);
@@ -1244,29 +1274,31 @@ error_leds:
static void sixaxis_state_worker(struct work_struct *work)
{
struct sony_sc *sc = container_of(work, struct sony_sc, state_worker);
- unsigned char buf[] = {
- 0x01,
- 0x00, 0xff, 0x00, 0xff, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xff, 0x27, 0x10, 0x00, 0x32,
- 0xff, 0x27, 0x10, 0x00, 0x32,
- 0xff, 0x27, 0x10, 0x00, 0x32,
- 0xff, 0x27, 0x10, 0x00, 0x32,
- 0x00, 0x00, 0x00, 0x00, 0x00
+ union sixaxis_output_report_01 report = {
+ .buf = {
+ 0x01,
+ 0x00, 0xff, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0x27, 0x10, 0x00, 0x32,
+ 0xff, 0x27, 0x10, 0x00, 0x32,
+ 0xff, 0x27, 0x10, 0x00, 0x32,
+ 0xff, 0x27, 0x10, 0x00, 0x32,
+ 0x00, 0x00, 0x00, 0x00, 0x00
+ }
};
#ifdef CONFIG_SONY_FF
- buf[3] = sc->right ? 1 : 0;
- buf[5] = sc->left;
+ report.data.rumble.right_motor_on = sc->right ? 1 : 0;
+ report.data.rumble.left_motor_force = sc->left;
#endif
- buf[10] |= sc->led_state[0] << 1;
- buf[10] |= sc->led_state[1] << 2;
- buf[10] |= sc->led_state[2] << 3;
- buf[10] |= sc->led_state[3] << 4;
+ report.data.leds_bitmap |= sc->led_state[0] << 1;
+ report.data.leds_bitmap |= sc->led_state[1] << 2;
+ report.data.leds_bitmap |= sc->led_state[2] << 3;
+ report.data.leds_bitmap |= sc->led_state[3] << 4;
- hid_hw_raw_request(sc->hdev, 0x01, buf, sizeof(buf), HID_OUTPUT_REPORT,
- HID_REQ_SET_REPORT);
+ hid_hw_raw_request(sc->hdev, report.data.report_id, report.buf,
+ sizeof(report), HID_OUTPUT_REPORT, HID_REQ_SET_REPORT);
}
static void dualshock4_state_worker(struct work_struct *work)
--
1.8.5.3
^ permalink raw reply related
* [PATCH v5 1/7] HID: sony: Use inliners for work queue initialization and cancellation
From: Frank Praznik @ 2014-04-14 14:11 UTC (permalink / raw)
To: linux-input; +Cc: jkosina, simon, Frank Praznik
In-Reply-To: <1397484697-2389-1-git-send-email-frank.praznik@oh.rr.com>
Use inliners to make sure that the work queue initialization flag is always
checked and set correctly when initializing or cancelling the work queue.
Signed-off-by: Frank Praznik <frank.praznik@oh.rr.com>
---
drivers/hid/hid-sony.c | 29 +++++++++++++++++++----------
1 file changed, 19 insertions(+), 10 deletions(-)
diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c
index 908de27..3df3306 100644
--- a/drivers/hid/hid-sony.c
+++ b/drivers/hid/hid-sony.c
@@ -1578,6 +1578,20 @@ static int sony_check_add(struct sony_sc *sc)
return sony_check_add_dev_list(sc);
}
+static inline void sony_init_work(struct sony_sc *sc,
+ void (*worker)(struct work_struct *))
+{
+ if (!sc->worker_initialized)
+ INIT_WORK(&sc->state_worker, worker);
+
+ sc->worker_initialized = 1;
+}
+
+static inline void sony_cancel_work_sync(struct sony_sc *sc)
+{
+ if (sc->worker_initialized)
+ cancel_work_sync(&sc->state_worker);
+}
static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
{
@@ -1629,8 +1643,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
hdev->quirks |= HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP;
hdev->quirks |= HID_QUIRK_SKIP_OUTPUT_REPORT_ID;
ret = sixaxis_set_operational_usb(hdev);
- sc->worker_initialized = 1;
- INIT_WORK(&sc->state_worker, sixaxis_state_worker);
+ sony_init_work(sc, sixaxis_state_worker);
} else if (sc->quirks & SIXAXIS_CONTROLLER_BT) {
/*
* The Sixaxis wants output reports sent on the ctrl endpoint
@@ -1638,8 +1651,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
*/
hdev->quirks |= HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP;
ret = sixaxis_set_operational_bt(hdev);
- sc->worker_initialized = 1;
- INIT_WORK(&sc->state_worker, sixaxis_state_worker);
+ sony_init_work(sc, sixaxis_state_worker);
} else if (sc->quirks & DUALSHOCK4_CONTROLLER) {
if (sc->quirks & DUALSHOCK4_CONTROLLER_BT) {
/*
@@ -1661,8 +1673,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
if (ret < 0)
goto err_stop;
- sc->worker_initialized = 1;
- INIT_WORK(&sc->state_worker, dualshock4_state_worker);
+ sony_init_work(sc, dualshock4_state_worker);
} else {
ret = 0;
}
@@ -1707,8 +1718,7 @@ err_stop:
sony_leds_remove(hdev);
if (sc->quirks & SONY_BATTERY_SUPPORT)
sony_battery_remove(sc);
- if (sc->worker_initialized)
- cancel_work_sync(&sc->state_worker);
+ sony_cancel_work_sync(sc);
sony_remove_dev_list(sc);
hid_hw_stop(hdev);
return ret;
@@ -1726,8 +1736,7 @@ static void sony_remove(struct hid_device *hdev)
sony_battery_remove(sc);
}
- if (sc->worker_initialized)
- cancel_work_sync(&sc->state_worker);
+ sony_cancel_work_sync(sc);
sony_remove_dev_list(sc);
--
1.8.5.3
^ permalink raw reply related
* [PATCH v5 0/7] HID: sony: More Sony controller fixes and improvements.
From: Frank Praznik @ 2014-04-14 14:11 UTC (permalink / raw)
To: linux-input; +Cc: jkosina, simon, Frank Praznik
v5 has the following changes:
-Addresses some usability issues with the hardware blink support in the LED
code. The Sixaxis has some odd behavior where, on USB, the controller
overrides user LED settings and blinks the whole light bar until the PS button
is pushed. The new patch doesn't filter redundant state for the Sixaxis on
USB so the blinking can be stopped by the user without having to toggle the
state of an LED that is already set correctly.
-The new patch adds a 'global' LED to the DualShock 4 for synchronously
controlling the whole light bar and setting hardware blink rate. Under the
old system where all of the LEDs mapped to one global blink rate triggers
would constantly override each other if different ones were assigned to
different color LEDs and triggers that run their own timers and adjust the
brightness directly couldn't be synchronously applied to the whole light bar.
Now, the global LED controls the hardware blink rate and can synchronously
toggle the state of the whole light bar without disturbing the individual
colors. Additionally, if the user wants to apply different triggers to
the individual colors, that works as well.
-A patch from Simon Wood is included to fix a glitch with a third-party INTEC
controllers where the LEDs would blink when they were set to 'all-off'.
These are made to be applied on top of the latest code in
jikos/hid.git/for-3.15/upstream
^ permalink raw reply
* Re: [PATCH] HID: add missing hid usages
From: Olivier Gay @ 2014-04-14 12:22 UTC (permalink / raw)
To: Jiri Kosina
Cc: linux-input, Nestor Lopez Casado, Mathieu Meisser,
Dmitry Torokhov
In-Reply-To: <alpine.LNX.2.00.1404070949020.8157@pobox.suse.cz>
On Mon, Apr 7, 2014 at 9:49 AM, Jiri Kosina <jkosina@suse.cz> wrote:
>
>
> [ adding Dmitry to CC ]
>
> On Fri, 4 Apr 2014, Olivier Gay wrote:
>
> > with this patch we add some missing hid usages to the hid system.
> > Those missing hid usages are already used by some Logitech
> > products as well as some future ones.
> >
> > (Note: checkpatch.pl shows some errors but I didn't want to
> > break the current code style in hid-input.c)
>
> Thanks for the patch, Olivier. All looking good to me, but for the input.h
> additions, I'd like to get Ack from Dmitry, hence CCing him.
>
> Dmitry, ok to take this through my tree with your ack?
Hi Dmitry,
by any chance did you take a look on this commit we submitted?
Best regards,
Olivier
^ permalink raw reply
* Re: Re: [PATCH v4 7/9] ARM: sun7i/sun4i: dt: Add AXP209 support to various boards
From: Mark Brown @ 2014-04-14 11:16 UTC (permalink / raw)
To: Hans de Goede
Cc: linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Maxime Ripard,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
emilio-0Z03zUJReD5OxF6Tv1QG9Q, wens-jdAy2FN1RRM,
sameo-VuQAYsv1563Yd54FQh9/CA,
dmitry.torokhov-Re5JQEeQqe8AvxtiuMwx3w,
linux-input-u79uwXL29TY76Z2rM5mHXA,
linux-doc-u79uwXL29TY76Z2rM5mHXA,
lgirdwood-Re5JQEeQqe8AvxtiuMwx3w,
lee.jones-QSEj5FYQhm4dnm+yROfE0A,
boris.brezillon-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8
In-Reply-To: <534BB670.8030102-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
[-- Attachment #1: Type: text/plain, Size: 1727 bytes --]
On Mon, Apr 14, 2014 at 12:20:32PM +0200, Hans de Goede wrote:
Please fix your mailer to word wrap at less than 80 columns.
> As Mark has also mentioned we should probably pin the regulators to a
> certain voltage, except for those which we expect to be controlled by
> a driver, so basically all of them should be pinned to a certain
> voltage except for DCDC2 which gets used for the cpu voltage which we
> will want to scale as soon as we've a cpufreq driver.
If you don't know what to do with the regulators and don't have any
information on what's safe then you shouldn't be specifying a voltage at
all.
> While testing the latest revision of your code I also noticed that the
> kernel ends up disabling LDO3 and LDO4, which could be fine on some
> boards and a problem on other boards.
> I think we need to be careful here. For now it may be best to only add
> the DCDC2 regulator to the dts, as we know that dcdc2 is used for the
> cpu voltage everywhere, and we will actually want to control that
> later on.
You need to at least specify that regulators that need to be kept on are
always-on.
> For the others, for the boards where we've schematics (*) it would be
> good to add the other regulators with fixed voltages as specified in
> the schematics. For the rest it may be best to simply leave the
> regulators alone / at their default settings.
If everyone has been running the board at a voltage different to that in
the schematic then I'd not assume that everything has been validated at
the voltage in the schematic, if production firmware is available that's
going to be a more reliable guide than the schematic but it sounds like
all these boards have just been left to run at their default voltages.
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply
* [PATCH v3 0/2] input/serio: Add a firmware_id sysfs attribute
From: Hans de Goede @ 2014-04-14 10:30 UTC (permalink / raw)
To: Dmitry Torokhov; +Cc: Benjamin Tissoires, Peter Hutterer, linux-input
Hi All,
Here is v3 of my serio firmware_id sysfs attribute patch-set
Changes in v2:
-Add a helper function to avoid copy/pasting the code for building
the firmware_id string from pnp_ids
Changes in v3:
-Prefix the firmware_id string for 8042-pnp devices which "PNP: " so that
it will be easy to differentiate pnp-ids from ie devicetree ids in the future
Regards,
Hans
^ permalink raw reply
* [PATCH] synaptics: Add min/max quirk for ThinkPad T431s, L440, S1 Yoga and X1
From: Hans de Goede @ 2014-04-14 10:40 UTC (permalink / raw)
To: Dmitry Torokhov
Cc: Benjamin Tissoires, Peter Hutterer, linux-input, Hans de Goede,
Benjamin Tissoires
We expect that all the Haswell series will need such quirks, sigh.
The T431s seems to be T430 hardware in a T440s case, using the T440s touchpad,
with the same min/max issue.
The X1 Carbon 3rd generation name says 2nd while it is a 3rd generation.
The X1 and T431s share a PnPID with the T540p, but the reported ranges are
closer to those of the T440s.
HdG: Squashed 4 quirk patches into one. T431s + L440 are written by me,
S1 Yoga and X1 are written by Benjamin Tissoires.
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
drivers/input/mouse/synaptics.c | 34 ++++++++++++++++++++++++++++++++++
1 file changed, 34 insertions(+)
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
index b9d2259..521a8e7 100644
--- a/drivers/input/mouse/synaptics.c
+++ b/drivers/input/mouse/synaptics.c
@@ -1557,6 +1557,14 @@ static const struct dmi_system_id min_max_dmi_table[] __initconst = {
.driver_data = (int []){1232, 5710, 1156, 4696},
},
{
+ /* Lenovo ThinkPad T431s */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T431"),
+ },
+ .driver_data = (int []){1024, 5112, 2024, 4832},
+ },
+ {
/* Lenovo ThinkPad T440s */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
@@ -1565,6 +1573,14 @@ static const struct dmi_system_id min_max_dmi_table[] __initconst = {
.driver_data = (int []){1024, 5112, 2024, 4832},
},
{
+ /* Lenovo ThinkPad L440 */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad L440"),
+ },
+ .driver_data = (int []){1024, 5112, 2024, 4832},
+ },
+ {
/* Lenovo ThinkPad T540p */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
@@ -1572,6 +1588,24 @@ static const struct dmi_system_id min_max_dmi_table[] __initconst = {
},
.driver_data = (int []){1024, 5056, 2058, 4832},
},
+ {
+ /* Lenovo Yoga S1 */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_VERSION,
+ "ThinkPad S1 Yoga"),
+ },
+ .driver_data = (int []){1232, 5711, 1159, 4700},
+ },
+ {
+ /* Lenovo ThinkPad X1 Carbon Haswell (3rd generation) */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_VERSION,
+ "ThinkPad X1 Carbon 2nd"),
+ },
+ .driver_data = (int []){1131, 5113, 2021, 4831},
+ },
#endif
{ }
};
--
1.9.0
^ permalink raw reply related
* [PATCH v2 2/2] synaptics: Report INPUT_PROP_TOPBUTTONPAD property for touchpads with top buttonareas
From: Hans de Goede @ 2014-04-14 10:37 UTC (permalink / raw)
To: Dmitry Torokhov
Cc: Benjamin Tissoires, Peter Hutterer, linux-input, Hans de Goede
In-Reply-To: <1397471875-31400-1-git-send-email-hdegoede@redhat.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
drivers/input/mouse/synaptics.c | 46 +++++++++++++++++++++++++++++++++++++++--
1 file changed, 44 insertions(+), 2 deletions(-)
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
index d8d49d1..b9d2259 100644
--- a/drivers/input/mouse/synaptics.c
+++ b/drivers/input/mouse/synaptics.c
@@ -117,6 +117,35 @@ void synaptics_reset(struct psmouse *psmouse)
}
#ifdef CONFIG_MOUSE_PS2_SYNAPTICS
+/* This list has been kindly provided by synaptics */
+static const char * const topbuttonpad_pnp_ids[] = {
+ "LEN0017",
+ "LEN0018",
+ "LEN0019",
+ "LEN0023",
+ "LEN002A",
+ "LEN002B",
+ "LEN002C",
+ "LEN002D",
+ "LEN002E",
+ "LEN0033", /* Helix */
+ "LEN0034", /* T431s, T540, X1 Carbon 2nd */
+ "LEN0035", /* X240 */
+ "LEN0036", /* T440 */
+ "LEN0037",
+ "LEN0041",
+ "LEN0042", /* Yoga */
+ "LEN0045",
+ "LEN0046",
+ "LEN0047",
+ "LEN0048",
+ "LEN0049",
+ "LEN2004", /* L440 */
+ "LEN2009",
+ "LEN200A",
+ "LEN200B",
+ NULL
+};
/*****************************************************************************
* Synaptics communications functions
@@ -1255,8 +1284,10 @@ static void set_abs_position_params(struct input_dev *dev,
input_abs_set_res(dev, y_code, priv->y_res);
}
-static void set_input_params(struct input_dev *dev, struct synaptics_data *priv)
+static void set_input_params(struct psmouse *psmouse,
+ struct synaptics_data *priv)
{
+ struct input_dev *dev = psmouse->dev;
int i;
/* Things that apply to both modes */
@@ -1325,6 +1356,17 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv)
if (SYN_CAP_CLICKPAD(priv->ext_cap_0c)) {
__set_bit(INPUT_PROP_BUTTONPAD, dev->propbit);
+ /* See if this buttonpad has a top button area */
+ if (!strncmp(psmouse->ps2dev.serio->firmware_id, "PNP:", 4)) {
+ for (i = 0; topbuttonpad_pnp_ids[i]; i++) {
+ if (strstr(psmouse->ps2dev.serio->firmware_id,
+ topbuttonpad_pnp_ids[i])) {
+ __set_bit(INPUT_PROP_TOPBUTTONPAD,
+ dev->propbit);
+ break;
+ }
+ }
+ }
/* Clickpads report only left button */
__clear_bit(BTN_RIGHT, dev->keybit);
__clear_bit(BTN_MIDDLE, dev->keybit);
@@ -1593,7 +1635,7 @@ static int __synaptics_init(struct psmouse *psmouse, bool absolute_mode)
priv->capabilities, priv->ext_cap, priv->ext_cap_0c,
priv->board_id, priv->firmware_id);
- set_input_params(psmouse->dev, priv);
+ set_input_params(psmouse, priv);
/*
* Encode touchpad model so that it can be used to set
--
1.9.0
^ permalink raw reply related
* [PATCH v2 1/2] uapi/input.h: Add INPUT_PROP_TOPBUTTONPAD device property
From: Hans de Goede @ 2014-04-14 10:37 UTC (permalink / raw)
To: Dmitry Torokhov
Cc: Benjamin Tissoires, Peter Hutterer, linux-input, Hans de Goede
In-Reply-To: <1397471875-31400-1-git-send-email-hdegoede@redhat.com>
On some newer laptops with a trackpoint the physical buttons for the
trackpoint have been removed to allow for a larger touchpad. On these
laptops the buttonpad has clearly marked areas on the top which are to be
used as trackpad buttons.
Users of the event device-node need to know about this, so that they can
properly interpret BTN_LEFT events as being a left / right / middle click
depending on where on the button pad the clicking finger is.
This commits adds a INPUT_PROP_TOPBUTTONPAD device property which drivers
for such buttonpads will use to signal to the user that this buttonpad not
only has the normal bottom button area, but also a top button area.
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
include/uapi/linux/input.h | 1 +
1 file changed, 1 insertion(+)
diff --git a/include/uapi/linux/input.h b/include/uapi/linux/input.h
index bd24470..f484952 100644
--- a/include/uapi/linux/input.h
+++ b/include/uapi/linux/input.h
@@ -164,6 +164,7 @@ struct input_keymap_entry {
#define INPUT_PROP_DIRECT 0x01 /* direct input devices */
#define INPUT_PROP_BUTTONPAD 0x02 /* has button(s) under pad */
#define INPUT_PROP_SEMI_MT 0x03 /* touch rectangle only */
+#define INPUT_PROP_TOPBUTTONPAD 0x04 /* softbuttons at top of pad */
#define INPUT_PROP_MAX 0x1f
#define INPUT_PROP_CNT (INPUT_PROP_MAX + 1)
--
1.9.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox