diff options
-rw-r--r-- | Documentation/ABI/testing/sysfs-driver-wacom | 8 | ||||
-rw-r--r-- | drivers/hid/Kconfig | 1 | ||||
-rw-r--r-- | drivers/hid/hid-wacom.c | 126 |
3 files changed, 135 insertions, 0 deletions
diff --git a/Documentation/ABI/testing/sysfs-driver-wacom b/Documentation/ABI/testing/sysfs-driver-wacom index 0130d6683c14..56c54558c8a4 100644 --- a/Documentation/ABI/testing/sysfs-driver-wacom +++ b/Documentation/ABI/testing/sysfs-driver-wacom | |||
@@ -9,6 +9,14 @@ Description: | |||
9 | or 0 otherwise. Writing to this file one of these values | 9 | or 0 otherwise. Writing to this file one of these values |
10 | switches reporting speed. | 10 | switches reporting speed. |
11 | 11 | ||
12 | What: /sys/class/leds/0005\:056A\:00BD.0001\:selector\:*/ | ||
13 | Date: May 2012 | ||
14 | Kernel Version: 3.5 | ||
15 | Contact: linux-bluetooth@vger.kernel.org | ||
16 | Description: | ||
17 | LED selector for Intuos4 WL. There are 4 leds, but only one LED | ||
18 | can be lit at a time. Max brightness is 127. | ||
19 | |||
12 | What: /sys/bus/usb/devices/<busnum>-<devnum>:<cfg>.<intf>/wacom_led/led | 20 | What: /sys/bus/usb/devices/<busnum>-<devnum>:<cfg>.<intf>/wacom_led/led |
13 | Date: August 2011 | 21 | Date: August 2011 |
14 | Contact: linux-input@vger.kernel.org | 22 | Contact: linux-input@vger.kernel.org |
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 4ecc25629a45..6e0d65aca308 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig | |||
@@ -596,6 +596,7 @@ config HID_WACOM | |||
596 | tristate "Wacom Bluetooth devices support" | 596 | tristate "Wacom Bluetooth devices support" |
597 | depends on BT_HIDP | 597 | depends on BT_HIDP |
598 | select POWER_SUPPLY | 598 | select POWER_SUPPLY |
599 | select LEDS_CLASS | ||
599 | ---help--- | 600 | ---help--- |
600 | Support for Wacom Graphire Bluetooth and Intuos4 WL tablets. | 601 | Support for Wacom Graphire Bluetooth and Intuos4 WL tablets. |
601 | 602 | ||
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 | ||