diff options
author | Przemo Firszt <przemo@firszt.eu> | 2012-05-10 14:23:52 -0400 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2012-05-11 08:47:04 -0400 |
commit | d13f5454e4acbbe2a470cc6743c2998cfcd607a8 (patch) | |
tree | b26169f0a09e90e95a73af215579e580b116dbb2 /drivers/hid/hid-wacom.c | |
parent | c653daba895a2d339b3b8f04e69fc111443ef327 (diff) |
HID: wacom: Add LED selector control for Wacom Intuos4 WL
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>
Diffstat (limited to 'drivers/hid/hid-wacom.c')
-rw-r--r-- | drivers/hid/hid-wacom.c | 126 |
1 files changed, 126 insertions, 0 deletions
diff --git a/drivers/hid/hid-wacom.c b/drivers/hid/hid-wacom.c index a66e1aa25cac..29372edc31c0 100644 --- a/drivers/hid/hid-wacom.c +++ b/drivers/hid/hid-wacom.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/device.h> | 24 | #include <linux/device.h> |
25 | #include <linux/hid.h> | 25 | #include <linux/hid.h> |
26 | #include <linux/module.h> | 26 | #include <linux/module.h> |
27 | #include <linux/leds.h> | ||
27 | #include <linux/slab.h> | 28 | #include <linux/slab.h> |
28 | #include <linux/power_supply.h> | 29 | #include <linux/power_supply.h> |
29 | 30 | ||
@@ -31,6 +32,8 @@ | |||
31 | 32 | ||
32 | #define PAD_DEVICE_ID 0x0F | 33 | #define PAD_DEVICE_ID 0x0F |
33 | 34 | ||
35 | #define WAC_CMD_LED_CONTROL 0x20 | ||
36 | |||
34 | struct wacom_data { | 37 | struct wacom_data { |
35 | __u16 tool; | 38 | __u16 tool; |
36 | __u16 butstate; | 39 | __u16 butstate; |
@@ -44,6 +47,8 @@ struct wacom_data { | |||
44 | __u8 ps_connected; | 47 | __u8 ps_connected; |
45 | struct power_supply battery; | 48 | struct power_supply battery; |
46 | struct power_supply ac; | 49 | struct power_supply ac; |
50 | __u8 led_selector; | ||
51 | struct led_classdev *leds[4]; | ||
47 | }; | 52 | }; |
48 | 53 | ||
49 | /*percent of battery capacity for Graphire | 54 | /*percent of battery capacity for Graphire |
@@ -64,6 +69,117 @@ static enum power_supply_property wacom_ac_props[] = { | |||
64 | POWER_SUPPLY_PROP_SCOPE, | 69 | POWER_SUPPLY_PROP_SCOPE, |
65 | }; | 70 | }; |
66 | 71 | ||
72 | static void wacom_leds_set_brightness(struct led_classdev *led_dev, | ||
73 | enum led_brightness value) | ||
74 | { | ||
75 | struct device *dev = led_dev->dev->parent; | ||
76 | struct hid_device *hdev; | ||
77 | struct wacom_data *wdata; | ||
78 | unsigned char *buf; | ||
79 | __u8 led = 0; | ||
80 | int i; | ||
81 | |||
82 | hdev = container_of(dev, struct hid_device, dev); | ||
83 | wdata = hid_get_drvdata(hdev); | ||
84 | for (i = 0; i < 4; ++i) { | ||
85 | if (wdata->leds[i] == led_dev) | ||
86 | wdata->led_selector = i; | ||
87 | } | ||
88 | |||
89 | led = wdata->led_selector | 0x04; | ||
90 | buf = kzalloc(9, GFP_KERNEL); | ||
91 | if (buf) { | ||
92 | buf[0] = WAC_CMD_LED_CONTROL; | ||
93 | buf[1] = led; | ||
94 | buf[2] = value; | ||
95 | hdev->hid_output_raw_report(hdev, buf, 9, HID_FEATURE_REPORT); | ||
96 | kfree(buf); | ||
97 | } | ||
98 | |||
99 | return; | ||
100 | } | ||
101 | |||
102 | static enum led_brightness wacom_leds_get_brightness(struct led_classdev *led_dev) | ||
103 | { | ||
104 | struct wacom_data *wdata; | ||
105 | struct device *dev = led_dev->dev->parent; | ||
106 | int value = 0; | ||
107 | int i; | ||
108 | |||
109 | wdata = hid_get_drvdata(container_of(dev, struct hid_device, dev)); | ||
110 | |||
111 | for (i = 0; i < 4; ++i) { | ||
112 | if (wdata->leds[i] == led_dev) { | ||
113 | value = wdata->leds[i]->brightness; | ||
114 | break; | ||
115 | } | ||
116 | } | ||
117 | |||
118 | return value; | ||
119 | } | ||
120 | |||
121 | |||
122 | static int wacom_initialize_leds(struct hid_device *hdev) | ||
123 | { | ||
124 | struct wacom_data *wdata = hid_get_drvdata(hdev); | ||
125 | struct led_classdev *led; | ||
126 | struct device *dev = &hdev->dev; | ||
127 | size_t namesz = strlen(dev_name(dev)) + 12; | ||
128 | char *name; | ||
129 | int i, ret; | ||
130 | |||
131 | wdata->led_selector = 0; | ||
132 | |||
133 | for (i = 0; i < 4; i++) { | ||
134 | led = kzalloc(sizeof(struct led_classdev) + namesz, GFP_KERNEL); | ||
135 | if (!led) { | ||
136 | hid_warn(hdev, | ||
137 | "can't allocate memory for LED selector\n"); | ||
138 | ret = -ENOMEM; | ||
139 | goto err; | ||
140 | } | ||
141 | |||
142 | name = (void *)&led[1]; | ||
143 | snprintf(name, namesz, "%s:selector:%d", dev_name(dev), i); | ||
144 | led->name = name; | ||
145 | led->brightness = 0; | ||
146 | led->max_brightness = 127; | ||
147 | led->brightness_get = wacom_leds_get_brightness; | ||
148 | led->brightness_set = wacom_leds_set_brightness; | ||
149 | |||
150 | wdata->leds[i] = led; | ||
151 | |||
152 | ret = led_classdev_register(dev, wdata->leds[i]); | ||
153 | |||
154 | if (ret) { | ||
155 | wdata->leds[i] = NULL; | ||
156 | kfree(led); | ||
157 | hid_warn(hdev, "can't register LED\n"); | ||
158 | goto err; | ||
159 | } | ||
160 | } | ||
161 | |||
162 | err: | ||
163 | return ret; | ||
164 | } | ||
165 | |||
166 | static void wacom_destroy_leds(struct hid_device *hdev) | ||
167 | { | ||
168 | struct wacom_data *wdata = hid_get_drvdata(hdev); | ||
169 | struct led_classdev *led; | ||
170 | int i; | ||
171 | |||
172 | for (i = 0; i < 4; ++i) { | ||
173 | if (wdata->leds[i]) { | ||
174 | led = wdata->leds[i]; | ||
175 | wdata->leds[i] = NULL; | ||
176 | led_classdev_unregister(led); | ||
177 | kfree(led); | ||
178 | } | ||
179 | } | ||
180 | |||
181 | } | ||
182 | |||
67 | static int wacom_battery_get_property(struct power_supply *psy, | 183 | static int wacom_battery_get_property(struct power_supply *psy, |
68 | enum power_supply_property psp, | 184 | enum power_supply_property psp, |
69 | union power_supply_propval *val) | 185 | union power_supply_propval *val) |
@@ -602,6 +718,12 @@ static int wacom_probe(struct hid_device *hdev, | |||
602 | sprintf(hdev->name, "%s", "Wacom Intuos4 WL"); | 718 | sprintf(hdev->name, "%s", "Wacom Intuos4 WL"); |
603 | wdata->features = 0; | 719 | wdata->features = 0; |
604 | wacom_set_features(hdev); | 720 | wacom_set_features(hdev); |
721 | ret = wacom_initialize_leds(hdev); | ||
722 | if (ret) { | ||
723 | hid_warn(hdev, | ||
724 | "can't create led attribute, err: %d\n", ret); | ||
725 | goto destroy_leds; | ||
726 | } | ||
605 | break; | 727 | break; |
606 | } | 728 | } |
607 | 729 | ||
@@ -644,6 +766,8 @@ err_ac: | |||
644 | err_battery: | 766 | err_battery: |
645 | device_remove_file(&hdev->dev, &dev_attr_speed); | 767 | device_remove_file(&hdev->dev, &dev_attr_speed); |
646 | hid_hw_stop(hdev); | 768 | hid_hw_stop(hdev); |
769 | destroy_leds: | ||
770 | wacom_destroy_leds(hdev); | ||
647 | err_free: | 771 | err_free: |
648 | kfree(wdata); | 772 | kfree(wdata); |
649 | return ret; | 773 | return ret; |
@@ -652,6 +776,8 @@ err_free: | |||
652 | static void wacom_remove(struct hid_device *hdev) | 776 | static void wacom_remove(struct hid_device *hdev) |
653 | { | 777 | { |
654 | struct wacom_data *wdata = hid_get_drvdata(hdev); | 778 | struct wacom_data *wdata = hid_get_drvdata(hdev); |
779 | |||
780 | wacom_destroy_leds(hdev); | ||
655 | device_remove_file(&hdev->dev, &dev_attr_speed); | 781 | device_remove_file(&hdev->dev, &dev_attr_speed); |
656 | hid_hw_stop(hdev); | 782 | hid_hw_stop(hdev); |
657 | 783 | ||