Skip to content

Commit

Permalink
HID: wacom: Add LED selector control for Wacom Intuos4 WL
Browse files Browse the repository at this point in the history
Add sysfs attribute to control LED selector on Wacom Intuos4. There are 4
different LEDs on the tablet and they can be turned on by something like:

echo 50 > /sys/class/leds/(device # here)\:selector\:1/brightness

Only one can be lit at a time. The brightness range is 0 to 127. This patch
also contains short ABI description.

Signed-off-by: Przemo Firszt <przemo@firszt.eu>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
  • Loading branch information
Przemo Firszt authored and Jiri Kosina committed May 11, 2012
1 parent c653dab commit d13f545
Show file tree
Hide file tree
Showing 3 changed files with 135 additions and 0 deletions.
8 changes: 8 additions & 0 deletions Documentation/ABI/testing/sysfs-driver-wacom
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@ Description:
or 0 otherwise. Writing to this file one of these values
switches reporting speed.

What: /sys/class/leds/0005\:056A\:00BD.0001\:selector\:*/
Date: May 2012
Kernel Version: 3.5
Contact: linux-bluetooth@vger.kernel.org
Description:
LED selector for Intuos4 WL. There are 4 leds, but only one LED
can be lit at a time. Max brightness is 127.

What: /sys/bus/usb/devices/<busnum>-<devnum>:<cfg>.<intf>/wacom_led/led
Date: August 2011
Contact: linux-input@vger.kernel.org
Expand Down
1 change: 1 addition & 0 deletions drivers/hid/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -596,6 +596,7 @@ config HID_WACOM
tristate "Wacom Bluetooth devices support"
depends on BT_HIDP
select POWER_SUPPLY
select LEDS_CLASS
---help---
Support for Wacom Graphire Bluetooth and Intuos4 WL tablets.

Expand Down
126 changes: 126 additions & 0 deletions drivers/hid/hid-wacom.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,16 @@
#include <linux/device.h>
#include <linux/hid.h>
#include <linux/module.h>
#include <linux/leds.h>
#include <linux/slab.h>
#include <linux/power_supply.h>

#include "hid-ids.h"

#define PAD_DEVICE_ID 0x0F

#define WAC_CMD_LED_CONTROL 0x20

struct wacom_data {
__u16 tool;
__u16 butstate;
Expand All @@ -44,6 +47,8 @@ struct wacom_data {
__u8 ps_connected;
struct power_supply battery;
struct power_supply ac;
__u8 led_selector;
struct led_classdev *leds[4];
};

/*percent of battery capacity for Graphire
Expand All @@ -64,6 +69,117 @@ static enum power_supply_property wacom_ac_props[] = {
POWER_SUPPLY_PROP_SCOPE,
};

static void wacom_leds_set_brightness(struct led_classdev *led_dev,
enum led_brightness value)
{
struct device *dev = led_dev->dev->parent;
struct hid_device *hdev;
struct wacom_data *wdata;
unsigned char *buf;
__u8 led = 0;
int i;

hdev = container_of(dev, struct hid_device, dev);
wdata = hid_get_drvdata(hdev);
for (i = 0; i < 4; ++i) {
if (wdata->leds[i] == led_dev)
wdata->led_selector = i;
}

led = wdata->led_selector | 0x04;
buf = kzalloc(9, GFP_KERNEL);
if (buf) {
buf[0] = WAC_CMD_LED_CONTROL;
buf[1] = led;
buf[2] = value;
hdev->hid_output_raw_report(hdev, buf, 9, HID_FEATURE_REPORT);
kfree(buf);
}

return;
}

static enum led_brightness wacom_leds_get_brightness(struct led_classdev *led_dev)
{
struct wacom_data *wdata;
struct device *dev = led_dev->dev->parent;
int value = 0;
int i;

wdata = hid_get_drvdata(container_of(dev, struct hid_device, dev));

for (i = 0; i < 4; ++i) {
if (wdata->leds[i] == led_dev) {
value = wdata->leds[i]->brightness;
break;
}
}

return value;
}


static int wacom_initialize_leds(struct hid_device *hdev)
{
struct wacom_data *wdata = hid_get_drvdata(hdev);
struct led_classdev *led;
struct device *dev = &hdev->dev;
size_t namesz = strlen(dev_name(dev)) + 12;
char *name;
int i, ret;

wdata->led_selector = 0;

for (i = 0; i < 4; i++) {
led = kzalloc(sizeof(struct led_classdev) + namesz, GFP_KERNEL);
if (!led) {
hid_warn(hdev,
"can't allocate memory for LED selector\n");
ret = -ENOMEM;
goto err;
}

name = (void *)&led[1];
snprintf(name, namesz, "%s:selector:%d", dev_name(dev), i);
led->name = name;
led->brightness = 0;
led->max_brightness = 127;
led->brightness_get = wacom_leds_get_brightness;
led->brightness_set = wacom_leds_set_brightness;

wdata->leds[i] = led;

ret = led_classdev_register(dev, wdata->leds[i]);

if (ret) {
wdata->leds[i] = NULL;
kfree(led);
hid_warn(hdev, "can't register LED\n");
goto err;
}
}

err:
return ret;
}

static void wacom_destroy_leds(struct hid_device *hdev)
{
struct wacom_data *wdata = hid_get_drvdata(hdev);
struct led_classdev *led;
int i;

for (i = 0; i < 4; ++i) {
if (wdata->leds[i]) {
led = wdata->leds[i];
wdata->leds[i] = NULL;
led_classdev_unregister(led);
kfree(led);
}
}

}

static int wacom_battery_get_property(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
Expand Down Expand Up @@ -602,6 +718,12 @@ static int wacom_probe(struct hid_device *hdev,
sprintf(hdev->name, "%s", "Wacom Intuos4 WL");
wdata->features = 0;
wacom_set_features(hdev);
ret = wacom_initialize_leds(hdev);
if (ret) {
hid_warn(hdev,
"can't create led attribute, err: %d\n", ret);
goto destroy_leds;
}
break;
}

Expand Down Expand Up @@ -644,6 +766,8 @@ static int wacom_probe(struct hid_device *hdev,
err_battery:
device_remove_file(&hdev->dev, &dev_attr_speed);
hid_hw_stop(hdev);
destroy_leds:
wacom_destroy_leds(hdev);
err_free:
kfree(wdata);
return ret;
Expand All @@ -652,6 +776,8 @@ static int wacom_probe(struct hid_device *hdev,
static void wacom_remove(struct hid_device *hdev)
{
struct wacom_data *wdata = hid_get_drvdata(hdev);

wacom_destroy_leds(hdev);
device_remove_file(&hdev->dev, &dev_attr_speed);
hid_hw_stop(hdev);

Expand Down

0 comments on commit d13f545

Please sign in to comment.