diff options
author | Jiri Kosina <jkosina@suse.cz> | 2010-05-19 08:04:49 -0400 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2010-05-19 08:04:49 -0400 |
commit | 7426ef52b42ebd54ba85133ffd29132e008a882c (patch) | |
tree | 5232ca850065baf025e8d7384408b48b4b462c96 /drivers/hid/hid-wacom.c | |
parent | 537b60d17894b7c19a6060feae40299d7109d6e7 (diff) | |
parent | a8ab5d58b0238b8199cc699b8dff7c5e1da24138 (diff) |
Merge branch 'upstream' into for-linus
Conflicts:
drivers/hid/hid-wacom.c
Diffstat (limited to 'drivers/hid/hid-wacom.c')
-rw-r--r-- | drivers/hid/hid-wacom.c | 229 |
1 files changed, 204 insertions, 25 deletions
diff --git a/drivers/hid/hid-wacom.c b/drivers/hid/hid-wacom.c index f947d8337e21..1e051f1171e4 100644 --- a/drivers/hid/hid-wacom.c +++ b/drivers/hid/hid-wacom.c | |||
@@ -22,14 +22,159 @@ | |||
22 | #include <linux/hid.h> | 22 | #include <linux/hid.h> |
23 | #include <linux/module.h> | 23 | #include <linux/module.h> |
24 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
25 | #ifdef CONFIG_HID_WACOM_POWER_SUPPLY | ||
26 | #include <linux/power_supply.h> | ||
27 | #endif | ||
25 | 28 | ||
26 | #include "hid-ids.h" | 29 | #include "hid-ids.h" |
27 | 30 | ||
28 | struct wacom_data { | 31 | struct wacom_data { |
29 | __u16 tool; | 32 | __u16 tool; |
30 | unsigned char butstate; | 33 | unsigned char butstate; |
34 | unsigned char high_speed; | ||
35 | #ifdef CONFIG_HID_WACOM_POWER_SUPPLY | ||
36 | int battery_capacity; | ||
37 | struct power_supply battery; | ||
38 | struct power_supply ac; | ||
39 | #endif | ||
31 | }; | 40 | }; |
32 | 41 | ||
42 | #ifdef CONFIG_HID_WACOM_POWER_SUPPLY | ||
43 | /*percent of battery capacity, 0 means AC online*/ | ||
44 | static unsigned short batcap[8] = { 1, 15, 25, 35, 50, 70, 100, 0 }; | ||
45 | |||
46 | static enum power_supply_property wacom_battery_props[] = { | ||
47 | POWER_SUPPLY_PROP_PRESENT, | ||
48 | POWER_SUPPLY_PROP_CAPACITY | ||
49 | }; | ||
50 | |||
51 | static enum power_supply_property wacom_ac_props[] = { | ||
52 | POWER_SUPPLY_PROP_PRESENT, | ||
53 | POWER_SUPPLY_PROP_ONLINE | ||
54 | }; | ||
55 | |||
56 | static int wacom_battery_get_property(struct power_supply *psy, | ||
57 | enum power_supply_property psp, | ||
58 | union power_supply_propval *val) | ||
59 | { | ||
60 | struct wacom_data *wdata = container_of(psy, | ||
61 | struct wacom_data, battery); | ||
62 | int power_state = batcap[wdata->battery_capacity]; | ||
63 | int ret = 0; | ||
64 | |||
65 | switch (psp) { | ||
66 | case POWER_SUPPLY_PROP_PRESENT: | ||
67 | val->intval = 1; | ||
68 | break; | ||
69 | case POWER_SUPPLY_PROP_CAPACITY: | ||
70 | /* show 100% battery capacity when charging */ | ||
71 | if (power_state == 0) | ||
72 | val->intval = 100; | ||
73 | else | ||
74 | val->intval = power_state; | ||
75 | break; | ||
76 | default: | ||
77 | ret = -EINVAL; | ||
78 | break; | ||
79 | } | ||
80 | return ret; | ||
81 | } | ||
82 | |||
83 | static int wacom_ac_get_property(struct power_supply *psy, | ||
84 | enum power_supply_property psp, | ||
85 | union power_supply_propval *val) | ||
86 | { | ||
87 | struct wacom_data *wdata = container_of(psy, struct wacom_data, ac); | ||
88 | int power_state = batcap[wdata->battery_capacity]; | ||
89 | int ret = 0; | ||
90 | |||
91 | switch (psp) { | ||
92 | case POWER_SUPPLY_PROP_PRESENT: | ||
93 | /* fall through */ | ||
94 | case POWER_SUPPLY_PROP_ONLINE: | ||
95 | if (power_state == 0) | ||
96 | val->intval = 1; | ||
97 | else | ||
98 | val->intval = 0; | ||
99 | break; | ||
100 | default: | ||
101 | ret = -EINVAL; | ||
102 | break; | ||
103 | } | ||
104 | return ret; | ||
105 | } | ||
106 | #endif | ||
107 | |||
108 | static void wacom_poke(struct hid_device *hdev, u8 speed) | ||
109 | { | ||
110 | struct wacom_data *wdata = hid_get_drvdata(hdev); | ||
111 | int limit, ret; | ||
112 | char rep_data[2]; | ||
113 | |||
114 | rep_data[0] = 0x03 ; rep_data[1] = 0x00; | ||
115 | limit = 3; | ||
116 | do { | ||
117 | ret = hdev->hid_output_raw_report(hdev, rep_data, 2, | ||
118 | HID_FEATURE_REPORT); | ||
119 | } while (ret < 0 && limit-- > 0); | ||
120 | |||
121 | if (ret >= 0) { | ||
122 | if (speed == 0) | ||
123 | rep_data[0] = 0x05; | ||
124 | else | ||
125 | rep_data[0] = 0x06; | ||
126 | |||
127 | rep_data[1] = 0x00; | ||
128 | limit = 3; | ||
129 | do { | ||
130 | ret = hdev->hid_output_raw_report(hdev, rep_data, 2, | ||
131 | HID_FEATURE_REPORT); | ||
132 | } while (ret < 0 && limit-- > 0); | ||
133 | |||
134 | if (ret >= 0) { | ||
135 | wdata->high_speed = speed; | ||
136 | return; | ||
137 | } | ||
138 | } | ||
139 | |||
140 | /* | ||
141 | * Note that if the raw queries fail, it's not a hard failure and it | ||
142 | * is safe to continue | ||
143 | */ | ||
144 | dev_warn(&hdev->dev, "failed to poke device, command %d, err %d\n", | ||
145 | rep_data[0], ret); | ||
146 | return; | ||
147 | } | ||
148 | |||
149 | static ssize_t wacom_show_speed(struct device *dev, | ||
150 | struct device_attribute | ||
151 | *attr, char *buf) | ||
152 | { | ||
153 | struct wacom_data *wdata = dev_get_drvdata(dev); | ||
154 | |||
155 | return snprintf(buf, PAGE_SIZE, "%i\n", wdata->high_speed); | ||
156 | } | ||
157 | |||
158 | static ssize_t wacom_store_speed(struct device *dev, | ||
159 | struct device_attribute *attr, | ||
160 | const char *buf, size_t count) | ||
161 | { | ||
162 | struct hid_device *hdev = container_of(dev, struct hid_device, dev); | ||
163 | int new_speed; | ||
164 | |||
165 | if (sscanf(buf, "%1d", &new_speed ) != 1) | ||
166 | return -EINVAL; | ||
167 | |||
168 | if (new_speed == 0 || new_speed == 1) { | ||
169 | wacom_poke(hdev, new_speed); | ||
170 | return strnlen(buf, PAGE_SIZE); | ||
171 | } else | ||
172 | return -EINVAL; | ||
173 | } | ||
174 | |||
175 | static DEVICE_ATTR(speed, S_IRUGO | S_IWUGO, | ||
176 | wacom_show_speed, wacom_store_speed); | ||
177 | |||
33 | static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report, | 178 | static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report, |
34 | u8 *raw_data, int size) | 179 | u8 *raw_data, int size) |
35 | { | 180 | { |
@@ -148,6 +293,12 @@ static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report, | |||
148 | input_sync(input); | 293 | input_sync(input); |
149 | } | 294 | } |
150 | 295 | ||
296 | #ifdef CONFIG_HID_WACOM_POWER_SUPPLY | ||
297 | /* Store current battery capacity */ | ||
298 | rw = (data[7] >> 2 & 0x07); | ||
299 | if (rw != wdata->battery_capacity) | ||
300 | wdata->battery_capacity = rw; | ||
301 | #endif | ||
151 | return 1; | 302 | return 1; |
152 | } | 303 | } |
153 | 304 | ||
@@ -157,9 +308,7 @@ static int wacom_probe(struct hid_device *hdev, | |||
157 | struct hid_input *hidinput; | 308 | struct hid_input *hidinput; |
158 | struct input_dev *input; | 309 | struct input_dev *input; |
159 | struct wacom_data *wdata; | 310 | struct wacom_data *wdata; |
160 | char rep_data[2]; | ||
161 | int ret; | 311 | int ret; |
162 | int limit; | ||
163 | 312 | ||
164 | wdata = kzalloc(sizeof(*wdata), GFP_KERNEL); | 313 | wdata = kzalloc(sizeof(*wdata), GFP_KERNEL); |
165 | if (wdata == NULL) { | 314 | if (wdata == NULL) { |
@@ -182,31 +331,53 @@ static int wacom_probe(struct hid_device *hdev, | |||
182 | goto err_free; | 331 | goto err_free; |
183 | } | 332 | } |
184 | 333 | ||
185 | /* | 334 | ret = device_create_file(&hdev->dev, &dev_attr_speed); |
186 | * Note that if the raw queries fail, it's not a hard failure and it | 335 | if (ret) |
187 | * is safe to continue | 336 | dev_warn(&hdev->dev, |
188 | */ | 337 | "can't create sysfs speed attribute err: %d\n", ret); |
189 | 338 | ||
190 | /* Set Wacom mode2 */ | 339 | /* Set Wacom mode 2 with high reporting speed */ |
191 | rep_data[0] = 0x03; rep_data[1] = 0x00; | 340 | wacom_poke(hdev, 1); |
192 | limit = 3; | ||
193 | do { | ||
194 | ret = hdev->hid_output_raw_report(hdev, rep_data, 2, | ||
195 | HID_FEATURE_REPORT); | ||
196 | } while (ret < 0 && limit-- > 0); | ||
197 | if (ret < 0) | ||
198 | dev_warn(&hdev->dev, "failed to poke device #1, %d\n", ret); | ||
199 | 341 | ||
200 | /* 0x06 - high reporting speed, 0x05 - low speed */ | 342 | #ifdef CONFIG_HID_WACOM_POWER_SUPPLY |
201 | rep_data[0] = 0x06; rep_data[1] = 0x00; | 343 | wdata->battery.properties = wacom_battery_props; |
202 | limit = 3; | 344 | wdata->battery.num_properties = ARRAY_SIZE(wacom_battery_props); |
203 | do { | 345 | wdata->battery.get_property = wacom_battery_get_property; |
204 | ret = hdev->hid_output_raw_report(hdev, rep_data, 2, | 346 | wdata->battery.name = "wacom_battery"; |
205 | HID_FEATURE_REPORT); | 347 | wdata->battery.type = POWER_SUPPLY_TYPE_BATTERY; |
206 | } while (ret < 0 && limit-- > 0); | 348 | wdata->battery.use_for_apm = 0; |
207 | if (ret < 0) | ||
208 | dev_warn(&hdev->dev, "failed to poke device #2, %d\n", ret); | ||
209 | 349 | ||
350 | ret = power_supply_register(&hdev->dev, &wdata->battery); | ||
351 | if (ret) { | ||
352 | dev_warn(&hdev->dev, | ||
353 | "can't create sysfs battery attribute, err: %d\n", ret); | ||
354 | /* | ||
355 | * battery attribute is not critical for the tablet, but if it | ||
356 | * failed then there is no need to create ac attribute | ||
357 | */ | ||
358 | goto move_on; | ||
359 | } | ||
360 | |||
361 | wdata->ac.properties = wacom_ac_props; | ||
362 | wdata->ac.num_properties = ARRAY_SIZE(wacom_ac_props); | ||
363 | wdata->ac.get_property = wacom_ac_get_property; | ||
364 | wdata->ac.name = "wacom_ac"; | ||
365 | wdata->ac.type = POWER_SUPPLY_TYPE_MAINS; | ||
366 | wdata->ac.use_for_apm = 0; | ||
367 | |||
368 | ret = power_supply_register(&hdev->dev, &wdata->ac); | ||
369 | if (ret) { | ||
370 | dev_warn(&hdev->dev, | ||
371 | "can't create ac battery attribute, err: %d\n", ret); | ||
372 | /* | ||
373 | * ac attribute is not critical for the tablet, but if it | ||
374 | * failed then we don't want to battery attribute to exist | ||
375 | */ | ||
376 | power_supply_unregister(&wdata->battery); | ||
377 | } | ||
378 | |||
379 | move_on: | ||
380 | #endif | ||
210 | hidinput = list_entry(hdev->inputs.next, struct hid_input, list); | 381 | hidinput = list_entry(hdev->inputs.next, struct hid_input, list); |
211 | input = hidinput->input; | 382 | input = hidinput->input; |
212 | 383 | ||
@@ -251,13 +422,21 @@ err_free: | |||
251 | 422 | ||
252 | static void wacom_remove(struct hid_device *hdev) | 423 | static void wacom_remove(struct hid_device *hdev) |
253 | { | 424 | { |
425 | #ifdef CONFIG_HID_WACOM_POWER_SUPPLY | ||
426 | struct wacom_data *wdata = hid_get_drvdata(hdev); | ||
427 | #endif | ||
254 | hid_hw_stop(hdev); | 428 | hid_hw_stop(hdev); |
429 | |||
430 | #ifdef CONFIG_HID_WACOM_POWER_SUPPLY | ||
431 | power_supply_unregister(&wdata->battery); | ||
432 | power_supply_unregister(&wdata->ac); | ||
433 | #endif | ||
255 | kfree(hid_get_drvdata(hdev)); | 434 | kfree(hid_get_drvdata(hdev)); |
256 | } | 435 | } |
257 | 436 | ||
258 | static const struct hid_device_id wacom_devices[] = { | 437 | static const struct hid_device_id wacom_devices[] = { |
259 | { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH) }, | 438 | { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH) }, |
260 | 439 | { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH) }, | |
261 | { } | 440 | { } |
262 | }; | 441 | }; |
263 | MODULE_DEVICE_TABLE(hid, wacom_devices); | 442 | MODULE_DEVICE_TABLE(hid, wacom_devices); |