HID: expose wacom pen tablet battery through power_supply class
[safe/jmp/linux-2.6] / drivers / hid / hid-wacom.c
1 /*
2  *  Bluetooth Wacom Tablet support
3  *
4  *  Copyright (c) 1999 Andreas Gal
5  *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
6  *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
7  *  Copyright (c) 2006-2007 Jiri Kosina
8  *  Copyright (c) 2007 Paul Walmsley
9  *  Copyright (c) 2008 Jiri Slaby <jirislaby@gmail.com>
10  *  Copyright (c) 2006 Andrew Zabolotny <zap@homelink.ru>
11  *  Copyright (c) 2009 Bastien Nocera <hadess@hadess.net>
12  */
13
14 /*
15  * This program is free software; you can redistribute it and/or modify it
16  * under the terms of the GNU General Public License as published by the Free
17  * Software Foundation; either version 2 of the License, or (at your option)
18  * any later version.
19  */
20
21 #include <linux/device.h>
22 #include <linux/hid.h>
23 #include <linux/module.h>
24 #ifdef CONFIG_HID_WACOM_POWER_SUPPLY
25 #include <linux/power_supply.h>
26 #endif
27
28 #include "hid-ids.h"
29
30 struct wacom_data {
31         __u16 tool;
32         unsigned char butstate;
33 #ifdef CONFIG_HID_WACOM_POWER_SUPPLY
34         int battery_capacity;
35         struct power_supply battery;
36         struct power_supply ac;
37 #endif
38 };
39
40 #ifdef CONFIG_HID_WACOM_POWER_SUPPLY
41 /*percent of battery capacity, 0 means AC online*/
42 static unsigned short batcap[8] = { 1, 15, 25, 35, 50, 70, 100, 0 };
43
44 static enum power_supply_property wacom_battery_props[] = {
45         POWER_SUPPLY_PROP_PRESENT,
46         POWER_SUPPLY_PROP_CAPACITY
47 };
48
49 static enum power_supply_property wacom_ac_props[] = {
50         POWER_SUPPLY_PROP_PRESENT,
51         POWER_SUPPLY_PROP_ONLINE
52 };
53
54 static int wacom_battery_get_property(struct power_supply *psy,
55                                 enum power_supply_property psp,
56                                 union power_supply_propval *val)
57 {
58         struct wacom_data *wdata = container_of(psy,
59                                         struct wacom_data, battery);
60         int power_state = batcap[wdata->battery_capacity];
61         int ret = 0;
62
63         switch (psp) {
64         case POWER_SUPPLY_PROP_PRESENT:
65                 val->intval = 1;
66                 break;
67         case POWER_SUPPLY_PROP_CAPACITY:
68                 /* show 100% battery capacity when charging */
69                 if (power_state == 0)
70                         val->intval = 100;
71                 else
72                         val->intval = power_state;
73                 break;
74         default:
75                 ret = -EINVAL;
76                 break;
77         }
78         return ret;
79 }
80
81 static int wacom_ac_get_property(struct power_supply *psy,
82                                 enum power_supply_property psp,
83                                 union power_supply_propval *val)
84 {
85         struct wacom_data *wdata = container_of(psy, struct wacom_data, ac);
86         int power_state = batcap[wdata->battery_capacity];
87         int ret = 0;
88
89         switch (psp) {
90         case POWER_SUPPLY_PROP_PRESENT:
91                 /* fall through */
92         case POWER_SUPPLY_PROP_ONLINE:
93                 if (power_state == 0)
94                         val->intval = 1;
95                 else
96                         val->intval = 0;
97                 break;
98         default:
99                 ret = -EINVAL;
100                 break;
101         }
102         return ret;
103 }
104 #endif
105
106 static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report,
107                 u8 *raw_data, int size)
108 {
109         struct wacom_data *wdata = hid_get_drvdata(hdev);
110         struct hid_input *hidinput;
111         struct input_dev *input;
112         unsigned char *data = (unsigned char *) raw_data;
113         int tool, x, y, rw;
114
115         if (!(hdev->claimed & HID_CLAIMED_INPUT))
116                 return 0;
117
118         tool = 0;
119         hidinput = list_entry(hdev->inputs.next, struct hid_input, list);
120         input = hidinput->input;
121
122         /* Check if this is a tablet report */
123         if (data[0] != 0x03)
124                 return 0;
125
126         /* Get X & Y positions */
127         x = le16_to_cpu(*(__le16 *) &data[2]);
128         y = le16_to_cpu(*(__le16 *) &data[4]);
129
130         /* Get current tool identifier */
131         if (data[1] & 0x90) { /* If pen is in the in/active area */
132                 switch ((data[1] >> 5) & 3) {
133                 case 0: /* Pen */
134                         tool = BTN_TOOL_PEN;
135                         break;
136
137                 case 1: /* Rubber */
138                         tool = BTN_TOOL_RUBBER;
139                         break;
140
141                 case 2: /* Mouse with wheel */
142                 case 3: /* Mouse without wheel */
143                         tool = BTN_TOOL_MOUSE;
144                         break;
145                 }
146
147                 /* Reset tool if out of active tablet area */
148                 if (!(data[1] & 0x10))
149                         tool = 0;
150         }
151
152         /* If tool changed, notify input subsystem */
153         if (wdata->tool != tool) {
154                 if (wdata->tool) {
155                         /* Completely reset old tool state */
156                         if (wdata->tool == BTN_TOOL_MOUSE) {
157                                 input_report_key(input, BTN_LEFT, 0);
158                                 input_report_key(input, BTN_RIGHT, 0);
159                                 input_report_key(input, BTN_MIDDLE, 0);
160                                 input_report_abs(input, ABS_DISTANCE,
161                                                 input->absmax[ABS_DISTANCE]);
162                         } else {
163                                 input_report_key(input, BTN_TOUCH, 0);
164                                 input_report_key(input, BTN_STYLUS, 0);
165                                 input_report_key(input, BTN_STYLUS2, 0);
166                                 input_report_abs(input, ABS_PRESSURE, 0);
167                         }
168                         input_report_key(input, wdata->tool, 0);
169                         input_sync(input);
170                 }
171                 wdata->tool = tool;
172                 if (tool)
173                         input_report_key(input, tool, 1);
174         }
175
176         if (tool) {
177                 input_report_abs(input, ABS_X, x);
178                 input_report_abs(input, ABS_Y, y);
179
180                 switch ((data[1] >> 5) & 3) {
181                 case 2: /* Mouse with wheel */
182                         input_report_key(input, BTN_MIDDLE, data[1] & 0x04);
183                         rw = (data[6] & 0x01) ? -1 :
184                                 (data[6] & 0x02) ? 1 : 0;
185                         input_report_rel(input, REL_WHEEL, rw);
186                         /* fall through */
187
188                 case 3: /* Mouse without wheel */
189                         input_report_key(input, BTN_LEFT, data[1] & 0x01);
190                         input_report_key(input, BTN_RIGHT, data[1] & 0x02);
191                         /* Compute distance between mouse and tablet */
192                         rw = 44 - (data[6] >> 2);
193                         if (rw < 0)
194                                 rw = 0;
195                         else if (rw > 31)
196                                 rw = 31;
197                         input_report_abs(input, ABS_DISTANCE, rw);
198                         break;
199
200                 default:
201                         input_report_abs(input, ABS_PRESSURE,
202                                         data[6] | (((__u16) (data[1] & 0x08)) << 5));
203                         input_report_key(input, BTN_TOUCH, data[1] & 0x01);
204                         input_report_key(input, BTN_STYLUS, data[1] & 0x02);
205                         input_report_key(input, BTN_STYLUS2, (tool == BTN_TOOL_PEN) && data[1] & 0x04);
206                         break;
207                 }
208
209                 input_sync(input);
210         }
211
212         /* Report the state of the two buttons at the top of the tablet
213          * as two extra fingerpad keys (buttons 4 & 5). */
214         rw = data[7] & 0x03;
215         if (rw != wdata->butstate) {
216                 wdata->butstate = rw;
217                 input_report_key(input, BTN_0, rw & 0x02);
218                 input_report_key(input, BTN_1, rw & 0x01);
219                 input_report_key(input, BTN_TOOL_FINGER, 0xf0);
220                 input_event(input, EV_MSC, MSC_SERIAL, 0xf0);
221                 input_sync(input);
222         }
223
224 #ifdef CONFIG_HID_WACOM_POWER_SUPPLY
225         /* Store current battery capacity */
226         rw = (data[7] >> 2 & 0x07);
227         if (rw != wdata->battery_capacity)
228                 wdata->battery_capacity = rw;
229 #endif
230         return 1;
231 }
232
233 static int wacom_probe(struct hid_device *hdev,
234                 const struct hid_device_id *id)
235 {
236         struct hid_input *hidinput;
237         struct input_dev *input;
238         struct wacom_data *wdata;
239         char rep_data[2];
240         int ret;
241         int limit;
242
243         wdata = kzalloc(sizeof(*wdata), GFP_KERNEL);
244         if (wdata == NULL) {
245                 dev_err(&hdev->dev, "can't alloc wacom descriptor\n");
246                 return -ENOMEM;
247         }
248
249         hid_set_drvdata(hdev, wdata);
250
251         /* Parse the HID report now */
252         ret = hid_parse(hdev);
253         if (ret) {
254                 dev_err(&hdev->dev, "parse failed\n");
255                 goto err_free;
256         }
257
258         ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
259         if (ret) {
260                 dev_err(&hdev->dev, "hw start failed\n");
261                 goto err_free;
262         }
263
264         /*
265          * Note that if the raw queries fail, it's not a hard failure and it
266          * is safe to continue
267          */
268
269         /* Set Wacom mode2 */
270         rep_data[0] = 0x03; rep_data[1] = 0x00;
271         limit = 3;
272         do {
273                 ret = hdev->hid_output_raw_report(hdev, rep_data, 2,
274                                 HID_FEATURE_REPORT);
275         } while (ret < 0 && limit-- > 0);
276         if (ret < 0)
277                 dev_warn(&hdev->dev, "failed to poke device #1, %d\n", ret);
278
279         /* 0x06 - high reporting speed, 0x05 - low speed */
280         rep_data[0] = 0x06; rep_data[1] = 0x00;
281         limit = 3;
282         do {
283                 ret = hdev->hid_output_raw_report(hdev, rep_data, 2,
284                                 HID_FEATURE_REPORT);
285         } while (ret < 0 && limit-- > 0);
286         if (ret < 0)
287                 dev_warn(&hdev->dev, "failed to poke device #2, %d\n", ret);
288
289 #ifdef CONFIG_HID_WACOM_POWER_SUPPLY
290         wdata->battery.properties = wacom_battery_props;
291         wdata->battery.num_properties = ARRAY_SIZE(wacom_battery_props);
292         wdata->battery.get_property = wacom_battery_get_property;
293         wdata->battery.name = "wacom_battery";
294         wdata->battery.type = POWER_SUPPLY_TYPE_BATTERY;
295         wdata->battery.use_for_apm = 0;
296
297         ret = power_supply_register(&hdev->dev, &wdata->battery);
298         if (ret) {
299                 dev_warn(&hdev->dev,
300                         "can't create sysfs battery attribute, err: %d\n", ret);
301                 /*
302                  * battery attribute is not critical for the tablet, but if it
303                  * failed then there is no need to create ac attribute
304                  */
305                 goto move_on;
306         }
307
308         wdata->ac.properties = wacom_ac_props;
309         wdata->ac.num_properties = ARRAY_SIZE(wacom_ac_props);
310         wdata->ac.get_property = wacom_ac_get_property;
311         wdata->ac.name = "wacom_ac";
312         wdata->ac.type = POWER_SUPPLY_TYPE_MAINS;
313         wdata->ac.use_for_apm = 0;
314
315         ret = power_supply_register(&hdev->dev, &wdata->ac);
316         if (ret) {
317                 dev_warn(&hdev->dev,
318                         "can't create ac battery attribute, err: %d\n", ret);
319                 /*
320                  * ac attribute is not critical for the tablet, but if it
321                  * failed then we don't want to battery attribute to exist
322                  */
323                 power_supply_unregister(&wdata->battery);
324         }
325
326 move_on:
327 #endif
328         hidinput = list_entry(hdev->inputs.next, struct hid_input, list);
329         input = hidinput->input;
330
331         /* Basics */
332         input->evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_REL);
333         input->absbit[0] |= BIT(ABS_X) | BIT(ABS_Y) |
334                 BIT(ABS_PRESSURE) | BIT(ABS_DISTANCE);
335         input->relbit[0] |= BIT(REL_WHEEL);
336         set_bit(BTN_TOOL_PEN, input->keybit);
337         set_bit(BTN_TOUCH, input->keybit);
338         set_bit(BTN_STYLUS, input->keybit);
339         set_bit(BTN_STYLUS2, input->keybit);
340         set_bit(BTN_LEFT, input->keybit);
341         set_bit(BTN_RIGHT, input->keybit);
342         set_bit(BTN_MIDDLE, input->keybit);
343
344         /* Pad */
345         input->evbit[0] |= BIT(EV_MSC);
346         input->mscbit[0] |= BIT(MSC_SERIAL);
347         set_bit(BTN_0, input->keybit);
348         set_bit(BTN_1, input->keybit);
349         set_bit(BTN_TOOL_FINGER, input->keybit);
350
351         /* Distance, rubber and mouse */
352         input->absbit[0] |= BIT(ABS_DISTANCE);
353         set_bit(BTN_TOOL_RUBBER, input->keybit);
354         set_bit(BTN_TOOL_MOUSE, input->keybit);
355
356         input->absmax[ABS_PRESSURE] = 511;
357         input->absmax[ABS_DISTANCE] = 32;
358
359         input->absmax[ABS_X] = 16704;
360         input->absmax[ABS_Y] = 12064;
361         input->absfuzz[ABS_X] = 4;
362         input->absfuzz[ABS_Y] = 4;
363
364         return 0;
365 err_free:
366         kfree(wdata);
367         return ret;
368 }
369
370 static void wacom_remove(struct hid_device *hdev)
371 {
372 #ifdef CONFIG_HID_WACOM_POWER_SUPPLY
373         struct wacom_data *wdata = hid_get_drvdata(hdev);
374 #endif
375         hid_hw_stop(hdev);
376
377 #ifdef CONFIG_HID_WACOM_POWER_SUPPLY
378         power_supply_unregister(&wdata->battery);
379         power_supply_unregister(&wdata->ac);
380 #endif
381         kfree(hid_get_drvdata(hdev));
382 }
383
384 static const struct hid_device_id wacom_devices[] = {
385         { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH) },
386
387         { }
388 };
389 MODULE_DEVICE_TABLE(hid, wacom_devices);
390
391 static struct hid_driver wacom_driver = {
392         .name = "wacom",
393         .id_table = wacom_devices,
394         .probe = wacom_probe,
395         .remove = wacom_remove,
396         .raw_event = wacom_raw_event,
397 };
398
399 static int __init wacom_init(void)
400 {
401         int ret;
402
403         ret = hid_register_driver(&wacom_driver);
404         if (ret)
405                 printk(KERN_ERR "can't register wacom driver\n");
406         printk(KERN_ERR "wacom driver registered\n");
407         return ret;
408 }
409
410 static void __exit wacom_exit(void)
411 {
412         hid_unregister_driver(&wacom_driver);
413 }
414
415 module_init(wacom_init);
416 module_exit(wacom_exit);
417 MODULE_LICENSE("GPL");
418