diff options
Diffstat (limited to 'drivers/hid/hid-wacom.c')
-rw-r--r-- | drivers/hid/hid-wacom.c | 302 |
1 files changed, 216 insertions, 86 deletions
diff --git a/drivers/hid/hid-wacom.c b/drivers/hid/hid-wacom.c index 067e2963314c..fe23a1eb586b 100644 --- a/drivers/hid/hid-wacom.c +++ b/drivers/hid/hid-wacom.c | |||
@@ -24,15 +24,16 @@ | |||
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 | #ifdef CONFIG_HID_WACOM_POWER_SUPPLY | ||
29 | #include <linux/power_supply.h> | 29 | #include <linux/power_supply.h> |
30 | #endif | ||
31 | 30 | ||
32 | #include "hid-ids.h" | 31 | #include "hid-ids.h" |
33 | 32 | ||
34 | #define PAD_DEVICE_ID 0x0F | 33 | #define PAD_DEVICE_ID 0x0F |
35 | 34 | ||
35 | #define WAC_CMD_LED_CONTROL 0x20 | ||
36 | |||
36 | struct wacom_data { | 37 | struct wacom_data { |
37 | __u16 tool; | 38 | __u16 tool; |
38 | __u16 butstate; | 39 | __u16 butstate; |
@@ -41,16 +42,20 @@ struct wacom_data { | |||
41 | __u32 id; | 42 | __u32 id; |
42 | __u32 serial; | 43 | __u32 serial; |
43 | unsigned char high_speed; | 44 | unsigned char high_speed; |
44 | #ifdef CONFIG_HID_WACOM_POWER_SUPPLY | 45 | __u8 battery_capacity; |
45 | int battery_capacity; | 46 | __u8 power_raw; |
47 | __u8 ps_connected; | ||
46 | struct power_supply battery; | 48 | struct power_supply battery; |
47 | struct power_supply ac; | 49 | struct power_supply ac; |
48 | #endif | 50 | __u8 led_selector; |
51 | struct led_classdev *leds[4]; | ||
49 | }; | 52 | }; |
50 | 53 | ||
51 | #ifdef CONFIG_HID_WACOM_POWER_SUPPLY | 54 | /*percent of battery capacity for Graphire |
52 | /*percent of battery capacity, 0 means AC online*/ | 55 | 8th value means AC online and show 100% capacity */ |
53 | static unsigned short batcap[8] = { 1, 15, 25, 35, 50, 70, 100, 0 }; | 56 | static unsigned short batcap_gr[8] = { 1, 15, 25, 35, 50, 70, 100, 100 }; |
57 | /*percent of battery capacity for Intuos4 WL, AC has a separate bit*/ | ||
58 | static unsigned short batcap_i4[8] = { 1, 15, 30, 45, 60, 70, 85, 100 }; | ||
54 | 59 | ||
55 | static enum power_supply_property wacom_battery_props[] = { | 60 | static enum power_supply_property wacom_battery_props[] = { |
56 | POWER_SUPPLY_PROP_PRESENT, | 61 | POWER_SUPPLY_PROP_PRESENT, |
@@ -64,13 +69,123 @@ 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) |
70 | { | 186 | { |
71 | struct wacom_data *wdata = container_of(psy, | 187 | struct wacom_data *wdata = container_of(psy, |
72 | struct wacom_data, battery); | 188 | struct wacom_data, battery); |
73 | int power_state = batcap[wdata->battery_capacity]; | ||
74 | int ret = 0; | 189 | int ret = 0; |
75 | 190 | ||
76 | switch (psp) { | 191 | switch (psp) { |
@@ -81,11 +196,7 @@ static int wacom_battery_get_property(struct power_supply *psy, | |||
81 | val->intval = POWER_SUPPLY_SCOPE_DEVICE; | 196 | val->intval = POWER_SUPPLY_SCOPE_DEVICE; |
82 | break; | 197 | break; |
83 | case POWER_SUPPLY_PROP_CAPACITY: | 198 | case POWER_SUPPLY_PROP_CAPACITY: |
84 | /* show 100% battery capacity when charging */ | 199 | val->intval = wdata->battery_capacity; |
85 | if (power_state == 0) | ||
86 | val->intval = 100; | ||
87 | else | ||
88 | val->intval = power_state; | ||
89 | break; | 200 | break; |
90 | default: | 201 | default: |
91 | ret = -EINVAL; | 202 | ret = -EINVAL; |
@@ -99,17 +210,13 @@ static int wacom_ac_get_property(struct power_supply *psy, | |||
99 | union power_supply_propval *val) | 210 | union power_supply_propval *val) |
100 | { | 211 | { |
101 | struct wacom_data *wdata = container_of(psy, struct wacom_data, ac); | 212 | struct wacom_data *wdata = container_of(psy, struct wacom_data, ac); |
102 | int power_state = batcap[wdata->battery_capacity]; | ||
103 | int ret = 0; | 213 | int ret = 0; |
104 | 214 | ||
105 | switch (psp) { | 215 | switch (psp) { |
106 | case POWER_SUPPLY_PROP_PRESENT: | 216 | case POWER_SUPPLY_PROP_PRESENT: |
107 | /* fall through */ | 217 | /* fall through */ |
108 | case POWER_SUPPLY_PROP_ONLINE: | 218 | case POWER_SUPPLY_PROP_ONLINE: |
109 | if (power_state == 0) | 219 | val->intval = wdata->ps_connected; |
110 | val->intval = 1; | ||
111 | else | ||
112 | val->intval = 0; | ||
113 | break; | 220 | break; |
114 | case POWER_SUPPLY_PROP_SCOPE: | 221 | case POWER_SUPPLY_PROP_SCOPE: |
115 | val->intval = POWER_SUPPLY_SCOPE_DEVICE; | 222 | val->intval = POWER_SUPPLY_SCOPE_DEVICE; |
@@ -120,41 +227,16 @@ static int wacom_ac_get_property(struct power_supply *psy, | |||
120 | } | 227 | } |
121 | return ret; | 228 | return ret; |
122 | } | 229 | } |
123 | #endif | ||
124 | |||
125 | static void wacom_set_features(struct hid_device *hdev) | ||
126 | { | ||
127 | int ret; | ||
128 | __u8 rep_data[2]; | ||
129 | |||
130 | /*set high speed, tablet mode*/ | ||
131 | rep_data[0] = 0x03; | ||
132 | rep_data[1] = 0x20; | ||
133 | ret = hdev->hid_output_raw_report(hdev, rep_data, 2, | ||
134 | HID_FEATURE_REPORT); | ||
135 | return; | ||
136 | } | ||
137 | 230 | ||
138 | static void wacom_poke(struct hid_device *hdev, u8 speed) | 231 | static void wacom_set_features(struct hid_device *hdev, u8 speed) |
139 | { | 232 | { |
140 | struct wacom_data *wdata = hid_get_drvdata(hdev); | 233 | struct wacom_data *wdata = hid_get_drvdata(hdev); |
141 | int limit, ret; | 234 | int limit, ret; |
142 | char rep_data[2]; | 235 | __u8 rep_data[2]; |
143 | |||
144 | rep_data[0] = 0x03 ; rep_data[1] = 0x00; | ||
145 | limit = 3; | ||
146 | do { | ||
147 | ret = hdev->hid_output_raw_report(hdev, rep_data, 2, | ||
148 | HID_FEATURE_REPORT); | ||
149 | } while (ret < 0 && limit-- > 0); | ||
150 | |||
151 | if (ret >= 0) { | ||
152 | if (speed == 0) | ||
153 | rep_data[0] = 0x05; | ||
154 | else | ||
155 | rep_data[0] = 0x06; | ||
156 | 236 | ||
157 | rep_data[1] = 0x00; | 237 | switch (hdev->product) { |
238 | case USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH: | ||
239 | rep_data[0] = 0x03 ; rep_data[1] = 0x00; | ||
158 | limit = 3; | 240 | limit = 3; |
159 | do { | 241 | do { |
160 | ret = hdev->hid_output_raw_report(hdev, rep_data, 2, | 242 | ret = hdev->hid_output_raw_report(hdev, rep_data, 2, |
@@ -162,17 +244,47 @@ static void wacom_poke(struct hid_device *hdev, u8 speed) | |||
162 | } while (ret < 0 && limit-- > 0); | 244 | } while (ret < 0 && limit-- > 0); |
163 | 245 | ||
164 | if (ret >= 0) { | 246 | if (ret >= 0) { |
165 | wdata->high_speed = speed; | 247 | if (speed == 0) |
166 | return; | 248 | rep_data[0] = 0x05; |
249 | else | ||
250 | rep_data[0] = 0x06; | ||
251 | |||
252 | rep_data[1] = 0x00; | ||
253 | limit = 3; | ||
254 | do { | ||
255 | ret = hdev->hid_output_raw_report(hdev, | ||
256 | rep_data, 2, HID_FEATURE_REPORT); | ||
257 | } while (ret < 0 && limit-- > 0); | ||
258 | |||
259 | if (ret >= 0) { | ||
260 | wdata->high_speed = speed; | ||
261 | return; | ||
262 | } | ||
167 | } | 263 | } |
264 | |||
265 | /* | ||
266 | * Note that if the raw queries fail, it's not a hard failure | ||
267 | * and it is safe to continue | ||
268 | */ | ||
269 | hid_warn(hdev, "failed to poke device, command %d, err %d\n", | ||
270 | rep_data[0], ret); | ||
271 | break; | ||
272 | case USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH: | ||
273 | if (speed == 1) | ||
274 | wdata->features &= ~0x20; | ||
275 | else | ||
276 | wdata->features |= 0x20; | ||
277 | |||
278 | rep_data[0] = 0x03; | ||
279 | rep_data[1] = wdata->features; | ||
280 | |||
281 | ret = hdev->hid_output_raw_report(hdev, rep_data, 2, | ||
282 | HID_FEATURE_REPORT); | ||
283 | if (ret >= 0) | ||
284 | wdata->high_speed = speed; | ||
285 | break; | ||
168 | } | 286 | } |
169 | 287 | ||
170 | /* | ||
171 | * Note that if the raw queries fail, it's not a hard failure and it | ||
172 | * is safe to continue | ||
173 | */ | ||
174 | hid_warn(hdev, "failed to poke device, command %d, err %d\n", | ||
175 | rep_data[0], ret); | ||
176 | return; | 288 | return; |
177 | } | 289 | } |
178 | 290 | ||
@@ -196,7 +308,7 @@ static ssize_t wacom_store_speed(struct device *dev, | |||
196 | return -EINVAL; | 308 | return -EINVAL; |
197 | 309 | ||
198 | if (new_speed == 0 || new_speed == 1) { | 310 | if (new_speed == 0 || new_speed == 1) { |
199 | wacom_poke(hdev, new_speed); | 311 | wacom_set_features(hdev, new_speed); |
200 | return strnlen(buf, PAGE_SIZE); | 312 | return strnlen(buf, PAGE_SIZE); |
201 | } else | 313 | } else |
202 | return -EINVAL; | 314 | return -EINVAL; |
@@ -310,12 +422,16 @@ static int wacom_gr_parse_report(struct hid_device *hdev, | |||
310 | input_sync(input); | 422 | input_sync(input); |
311 | } | 423 | } |
312 | 424 | ||
313 | #ifdef CONFIG_HID_WACOM_POWER_SUPPLY | 425 | /* Store current battery capacity and power supply state*/ |
314 | /* Store current battery capacity */ | ||
315 | rw = (data[7] >> 2 & 0x07); | 426 | rw = (data[7] >> 2 & 0x07); |
316 | if (rw != wdata->battery_capacity) | 427 | if (rw != wdata->power_raw) { |
317 | wdata->battery_capacity = rw; | 428 | wdata->power_raw = rw; |
318 | #endif | 429 | wdata->battery_capacity = batcap_gr[rw]; |
430 | if (rw == 7) | ||
431 | wdata->ps_connected = 1; | ||
432 | else | ||
433 | wdata->ps_connected = 0; | ||
434 | } | ||
319 | return 1; | 435 | return 1; |
320 | } | 436 | } |
321 | 437 | ||
@@ -369,6 +485,7 @@ static void wacom_i4_parse_pen_report(struct wacom_data *wdata, | |||
369 | { | 485 | { |
370 | __u16 x, y, pressure; | 486 | __u16 x, y, pressure; |
371 | __u8 distance; | 487 | __u8 distance; |
488 | __u8 tilt_x, tilt_y; | ||
372 | 489 | ||
373 | switch (data[1]) { | 490 | switch (data[1]) { |
374 | case 0x80: /* Out of proximity report */ | 491 | case 0x80: /* Out of proximity report */ |
@@ -405,6 +522,8 @@ static void wacom_i4_parse_pen_report(struct wacom_data *wdata, | |||
405 | pressure = (data[6] << 3) | ((data[7] & 0xC0) >> 5) | 522 | pressure = (data[6] << 3) | ((data[7] & 0xC0) >> 5) |
406 | | (data[1] & 0x01); | 523 | | (data[1] & 0x01); |
407 | distance = (data[9] >> 2) & 0x3f; | 524 | distance = (data[9] >> 2) & 0x3f; |
525 | tilt_x = ((data[7] << 1) & 0x7e) | (data[8] >> 7); | ||
526 | tilt_y = data[8] & 0x7f; | ||
408 | 527 | ||
409 | input_report_key(input, BTN_TOUCH, pressure > 1); | 528 | input_report_key(input, BTN_TOUCH, pressure > 1); |
410 | 529 | ||
@@ -415,6 +534,8 @@ static void wacom_i4_parse_pen_report(struct wacom_data *wdata, | |||
415 | input_report_abs(input, ABS_Y, y); | 534 | input_report_abs(input, ABS_Y, y); |
416 | input_report_abs(input, ABS_PRESSURE, pressure); | 535 | input_report_abs(input, ABS_PRESSURE, pressure); |
417 | input_report_abs(input, ABS_DISTANCE, distance); | 536 | input_report_abs(input, ABS_DISTANCE, distance); |
537 | input_report_abs(input, ABS_TILT_X, tilt_x); | ||
538 | input_report_abs(input, ABS_TILT_Y, tilt_y); | ||
418 | input_report_abs(input, ABS_MISC, wdata->id); | 539 | input_report_abs(input, ABS_MISC, wdata->id); |
419 | input_event(input, EV_MSC, MSC_SERIAL, wdata->serial); | 540 | input_event(input, EV_MSC, MSC_SERIAL, wdata->serial); |
420 | input_report_key(input, wdata->tool, 1); | 541 | input_report_key(input, wdata->tool, 1); |
@@ -455,6 +576,7 @@ static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report, | |||
455 | struct input_dev *input; | 576 | struct input_dev *input; |
456 | unsigned char *data = (unsigned char *) raw_data; | 577 | unsigned char *data = (unsigned char *) raw_data; |
457 | int i; | 578 | int i; |
579 | __u8 power_raw; | ||
458 | 580 | ||
459 | if (!(hdev->claimed & HID_CLAIMED_INPUT)) | 581 | if (!(hdev->claimed & HID_CLAIMED_INPUT)) |
460 | return 0; | 582 | return 0; |
@@ -462,13 +584,15 @@ static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report, | |||
462 | hidinput = list_entry(hdev->inputs.next, struct hid_input, list); | 584 | hidinput = list_entry(hdev->inputs.next, struct hid_input, list); |
463 | input = hidinput->input; | 585 | input = hidinput->input; |
464 | 586 | ||
465 | /* Check if this is a tablet report */ | ||
466 | if (data[0] != 0x03) | ||
467 | return 0; | ||
468 | |||
469 | switch (hdev->product) { | 587 | switch (hdev->product) { |
470 | case USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH: | 588 | case USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH: |
471 | return wacom_gr_parse_report(hdev, wdata, input, data); | 589 | if (data[0] == 0x03) { |
590 | return wacom_gr_parse_report(hdev, wdata, input, data); | ||
591 | } else { | ||
592 | hid_err(hdev, "Unknown report: %d,%d size:%d\n", | ||
593 | data[0], data[1], size); | ||
594 | return 0; | ||
595 | } | ||
472 | break; | 596 | break; |
473 | case USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH: | 597 | case USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH: |
474 | i = 1; | 598 | i = 1; |
@@ -482,6 +606,13 @@ static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report, | |||
482 | wacom_i4_parse_report(hdev, wdata, input, data + i); | 606 | wacom_i4_parse_report(hdev, wdata, input, data + i); |
483 | i += 10; | 607 | i += 10; |
484 | wacom_i4_parse_report(hdev, wdata, input, data + i); | 608 | wacom_i4_parse_report(hdev, wdata, input, data + i); |
609 | power_raw = data[i+10]; | ||
610 | if (power_raw != wdata->power_raw) { | ||
611 | wdata->power_raw = power_raw; | ||
612 | wdata->battery_capacity = batcap_i4[power_raw & 0x07]; | ||
613 | wdata->ps_connected = power_raw & 0x08; | ||
614 | } | ||
615 | |||
485 | break; | 616 | break; |
486 | default: | 617 | default: |
487 | hid_err(hdev, "Unknown report: %d,%d size:%d\n", | 618 | hid_err(hdev, "Unknown report: %d,%d size:%d\n", |
@@ -546,6 +677,8 @@ static int wacom_input_mapped(struct hid_device *hdev, struct hid_input *hi, | |||
546 | input_set_abs_params(input, ABS_Y, 0, 25400, 4, 0); | 677 | input_set_abs_params(input, ABS_Y, 0, 25400, 4, 0); |
547 | input_set_abs_params(input, ABS_PRESSURE, 0, 2047, 0, 0); | 678 | input_set_abs_params(input, ABS_PRESSURE, 0, 2047, 0, 0); |
548 | input_set_abs_params(input, ABS_DISTANCE, 0, 63, 0, 0); | 679 | input_set_abs_params(input, ABS_DISTANCE, 0, 63, 0, 0); |
680 | input_set_abs_params(input, ABS_TILT_X, 0, 127, 0, 0); | ||
681 | input_set_abs_params(input, ABS_TILT_Y, 0, 127, 0, 0); | ||
549 | break; | 682 | break; |
550 | } | 683 | } |
551 | 684 | ||
@@ -584,19 +717,19 @@ static int wacom_probe(struct hid_device *hdev, | |||
584 | hid_warn(hdev, | 717 | hid_warn(hdev, |
585 | "can't create sysfs speed attribute err: %d\n", ret); | 718 | "can't create sysfs speed attribute err: %d\n", ret); |
586 | 719 | ||
587 | switch (hdev->product) { | 720 | wdata->features = 0; |
588 | case USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH: | 721 | wacom_set_features(hdev, 1); |
589 | /* Set Wacom mode 2 with high reporting speed */ | 722 | |
590 | wacom_poke(hdev, 1); | 723 | if (hdev->product == USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH) { |
591 | break; | ||
592 | case USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH: | ||
593 | sprintf(hdev->name, "%s", "Wacom Intuos4 WL"); | 724 | sprintf(hdev->name, "%s", "Wacom Intuos4 WL"); |
594 | wdata->features = 0; | 725 | ret = wacom_initialize_leds(hdev); |
595 | wacom_set_features(hdev); | 726 | if (ret) { |
596 | break; | 727 | hid_warn(hdev, |
728 | "can't create led attribute, err: %d\n", ret); | ||
729 | goto destroy_leds; | ||
730 | } | ||
597 | } | 731 | } |
598 | 732 | ||
599 | #ifdef CONFIG_HID_WACOM_POWER_SUPPLY | ||
600 | wdata->battery.properties = wacom_battery_props; | 733 | wdata->battery.properties = wacom_battery_props; |
601 | wdata->battery.num_properties = ARRAY_SIZE(wacom_battery_props); | 734 | wdata->battery.num_properties = ARRAY_SIZE(wacom_battery_props); |
602 | wdata->battery.get_property = wacom_battery_get_property; | 735 | wdata->battery.get_property = wacom_battery_get_property; |
@@ -629,16 +762,15 @@ static int wacom_probe(struct hid_device *hdev, | |||
629 | } | 762 | } |
630 | 763 | ||
631 | power_supply_powers(&wdata->ac, &hdev->dev); | 764 | power_supply_powers(&wdata->ac, &hdev->dev); |
632 | #endif | ||
633 | return 0; | 765 | return 0; |
634 | 766 | ||
635 | #ifdef CONFIG_HID_WACOM_POWER_SUPPLY | ||
636 | err_ac: | 767 | err_ac: |
637 | power_supply_unregister(&wdata->battery); | 768 | power_supply_unregister(&wdata->battery); |
638 | err_battery: | 769 | err_battery: |
639 | device_remove_file(&hdev->dev, &dev_attr_speed); | 770 | device_remove_file(&hdev->dev, &dev_attr_speed); |
640 | hid_hw_stop(hdev); | 771 | hid_hw_stop(hdev); |
641 | #endif | 772 | destroy_leds: |
773 | wacom_destroy_leds(hdev); | ||
642 | err_free: | 774 | err_free: |
643 | kfree(wdata); | 775 | kfree(wdata); |
644 | return ret; | 776 | return ret; |
@@ -646,16 +778,14 @@ err_free: | |||
646 | 778 | ||
647 | static void wacom_remove(struct hid_device *hdev) | 779 | static void wacom_remove(struct hid_device *hdev) |
648 | { | 780 | { |
649 | #ifdef CONFIG_HID_WACOM_POWER_SUPPLY | ||
650 | struct wacom_data *wdata = hid_get_drvdata(hdev); | 781 | struct wacom_data *wdata = hid_get_drvdata(hdev); |
651 | #endif | 782 | |
783 | wacom_destroy_leds(hdev); | ||
652 | device_remove_file(&hdev->dev, &dev_attr_speed); | 784 | device_remove_file(&hdev->dev, &dev_attr_speed); |
653 | hid_hw_stop(hdev); | 785 | hid_hw_stop(hdev); |
654 | 786 | ||
655 | #ifdef CONFIG_HID_WACOM_POWER_SUPPLY | ||
656 | power_supply_unregister(&wdata->battery); | 787 | power_supply_unregister(&wdata->battery); |
657 | power_supply_unregister(&wdata->ac); | 788 | power_supply_unregister(&wdata->ac); |
658 | #endif | ||
659 | kfree(hid_get_drvdata(hdev)); | 789 | kfree(hid_get_drvdata(hdev)); |
660 | } | 790 | } |
661 | 791 | ||
@@ -693,5 +823,5 @@ static void __exit wacom_exit(void) | |||
693 | 823 | ||
694 | module_init(wacom_init); | 824 | module_init(wacom_init); |
695 | module_exit(wacom_exit); | 825 | module_exit(wacom_exit); |
826 | MODULE_DESCRIPTION("Driver for Wacom Graphire Bluetooth and Wacom Intuos4 WL"); | ||
696 | MODULE_LICENSE("GPL"); | 827 | MODULE_LICENSE("GPL"); |
697 | |||