diff options
author | Jiri Kosina <jkosina@suse.cz> | 2012-01-09 05:24:59 -0500 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2012-01-09 05:24:59 -0500 |
commit | 420174afdc7023c000e5b5b1b6fe9e028470c713 (patch) | |
tree | a50385761d11bef88689c53317d52f431bab3f9a /drivers/hid | |
parent | e0273728564a395a13cfed70e34da4f2613d2d44 (diff) | |
parent | 652aa6a9ac4a5f8d3e1fa3f6466646519e83c01e (diff) |
Merge branch 'hid-battery' of git://git.kernel.org/pub/scm/linux/kernel/git/jeremy/xen into for-linus
Diffstat (limited to 'drivers/hid')
-rw-r--r-- | drivers/hid/hid-core.c | 2 | ||||
-rw-r--r-- | drivers/hid/hid-ids.h | 1 | ||||
-rw-r--r-- | drivers/hid/hid-input.c | 113 |
3 files changed, 87 insertions, 29 deletions
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index b88ae113d367..af08ce7207d9 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c | |||
@@ -1159,7 +1159,7 @@ static bool hid_match_one_id(struct hid_device *hdev, | |||
1159 | (id->product == HID_ANY_ID || id->product == hdev->product); | 1159 | (id->product == HID_ANY_ID || id->product == hdev->product); |
1160 | } | 1160 | } |
1161 | 1161 | ||
1162 | static const struct hid_device_id *hid_match_id(struct hid_device *hdev, | 1162 | const struct hid_device_id *hid_match_id(struct hid_device *hdev, |
1163 | const struct hid_device_id *id) | 1163 | const struct hid_device_id *id) |
1164 | { | 1164 | { |
1165 | for (; id->bus; id++) | 1165 | for (; id->bus; id++) |
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 448e9d89f8d0..b8574cddd953 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h | |||
@@ -125,6 +125,7 @@ | |||
125 | #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI 0x0239 | 125 | #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI 0x0239 |
126 | #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO 0x023a | 126 | #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO 0x023a |
127 | #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS 0x023b | 127 | #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS 0x023b |
128 | #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI 0x0255 | ||
128 | #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO 0x0256 | 129 | #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO 0x0256 |
129 | #define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY 0x030a | 130 | #define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY 0x030a |
130 | #define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY 0x030b | 131 | #define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY 0x030b |
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index c6ee632bfd68..9333d692a786 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c | |||
@@ -32,6 +32,8 @@ | |||
32 | #include <linux/hid.h> | 32 | #include <linux/hid.h> |
33 | #include <linux/hid-debug.h> | 33 | #include <linux/hid-debug.h> |
34 | 34 | ||
35 | #include "hid-ids.h" | ||
36 | |||
35 | #define unk KEY_UNKNOWN | 37 | #define unk KEY_UNKNOWN |
36 | 38 | ||
37 | static const unsigned char hid_keyboard[256] = { | 39 | static const unsigned char hid_keyboard[256] = { |
@@ -277,14 +279,38 @@ static enum power_supply_property hidinput_battery_props[] = { | |||
277 | POWER_SUPPLY_PROP_ONLINE, | 279 | POWER_SUPPLY_PROP_ONLINE, |
278 | POWER_SUPPLY_PROP_CAPACITY, | 280 | POWER_SUPPLY_PROP_CAPACITY, |
279 | POWER_SUPPLY_PROP_MODEL_NAME, | 281 | POWER_SUPPLY_PROP_MODEL_NAME, |
282 | POWER_SUPPLY_PROP_STATUS | ||
280 | }; | 283 | }; |
281 | 284 | ||
285 | #define HID_BATTERY_QUIRK_PERCENT (1 << 0) /* always reports percent */ | ||
286 | #define HID_BATTERY_QUIRK_FEATURE (1 << 1) /* ask for feature report */ | ||
287 | |||
288 | static const struct hid_device_id hid_battery_quirks[] = { | ||
289 | { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, | ||
290 | USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI), | ||
291 | HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE }, | ||
292 | {} | ||
293 | }; | ||
294 | |||
295 | static unsigned find_battery_quirk(struct hid_device *hdev) | ||
296 | { | ||
297 | unsigned quirks = 0; | ||
298 | const struct hid_device_id *match; | ||
299 | |||
300 | match = hid_match_id(hdev, hid_battery_quirks); | ||
301 | if (match != NULL) | ||
302 | quirks = match->driver_data; | ||
303 | |||
304 | return quirks; | ||
305 | } | ||
306 | |||
282 | static int hidinput_get_battery_property(struct power_supply *psy, | 307 | static int hidinput_get_battery_property(struct power_supply *psy, |
283 | enum power_supply_property prop, | 308 | enum power_supply_property prop, |
284 | union power_supply_propval *val) | 309 | union power_supply_propval *val) |
285 | { | 310 | { |
286 | struct hid_device *dev = container_of(psy, struct hid_device, battery); | 311 | struct hid_device *dev = container_of(psy, struct hid_device, battery); |
287 | int ret = 0; | 312 | int ret = 0; |
313 | __u8 buf[2] = {}; | ||
288 | 314 | ||
289 | switch (prop) { | 315 | switch (prop) { |
290 | case POWER_SUPPLY_PROP_PRESENT: | 316 | case POWER_SUPPLY_PROP_PRESENT: |
@@ -293,19 +319,31 @@ static int hidinput_get_battery_property(struct power_supply *psy, | |||
293 | break; | 319 | break; |
294 | 320 | ||
295 | case POWER_SUPPLY_PROP_CAPACITY: | 321 | case POWER_SUPPLY_PROP_CAPACITY: |
322 | ret = dev->hid_get_raw_report(dev, dev->battery_report_id, | ||
323 | buf, sizeof(buf), | ||
324 | dev->battery_report_type); | ||
325 | |||
326 | if (ret != 2) { | ||
327 | if (ret >= 0) | ||
328 | ret = -EINVAL; | ||
329 | break; | ||
330 | } | ||
331 | |||
296 | if (dev->battery_min < dev->battery_max && | 332 | if (dev->battery_min < dev->battery_max && |
297 | dev->battery_val >= dev->battery_min && | 333 | buf[1] >= dev->battery_min && |
298 | dev->battery_val <= dev->battery_max) | 334 | buf[1] <= dev->battery_max) |
299 | val->intval = (100 * (dev->battery_val - dev->battery_min)) / | 335 | val->intval = (100 * (buf[1] - dev->battery_min)) / |
300 | (dev->battery_max - dev->battery_min); | 336 | (dev->battery_max - dev->battery_min); |
301 | else | ||
302 | ret = -EINVAL; | ||
303 | break; | 337 | break; |
304 | 338 | ||
305 | case POWER_SUPPLY_PROP_MODEL_NAME: | 339 | case POWER_SUPPLY_PROP_MODEL_NAME: |
306 | val->strval = dev->name; | 340 | val->strval = dev->name; |
307 | break; | 341 | break; |
308 | 342 | ||
343 | case POWER_SUPPLY_PROP_STATUS: | ||
344 | val->intval = POWER_SUPPLY_STATUS_DISCHARGING; | ||
345 | break; | ||
346 | |||
309 | default: | 347 | default: |
310 | ret = -EINVAL; | 348 | ret = -EINVAL; |
311 | break; | 349 | break; |
@@ -314,17 +352,22 @@ static int hidinput_get_battery_property(struct power_supply *psy, | |||
314 | return ret; | 352 | return ret; |
315 | } | 353 | } |
316 | 354 | ||
317 | static void hidinput_setup_battery(struct hid_device *dev, s32 min, s32 max) | 355 | static bool hidinput_setup_battery(struct hid_device *dev, unsigned report_type, struct hid_field *field) |
318 | { | 356 | { |
319 | struct power_supply *battery = &dev->battery; | 357 | struct power_supply *battery = &dev->battery; |
320 | int ret; | 358 | int ret; |
359 | unsigned quirks; | ||
360 | s32 min, max; | ||
361 | |||
362 | if (field->usage->hid != HID_DC_BATTERYSTRENGTH) | ||
363 | return false; /* no match */ | ||
321 | 364 | ||
322 | if (battery->name != NULL) | 365 | if (battery->name != NULL) |
323 | return; /* already initialized? */ | 366 | goto out; /* already initialized? */ |
324 | 367 | ||
325 | battery->name = kasprintf(GFP_KERNEL, "hid-%s-battery", dev->uniq); | 368 | battery->name = kasprintf(GFP_KERNEL, "hid-%s-battery", dev->uniq); |
326 | if (battery->name == NULL) | 369 | if (battery->name == NULL) |
327 | return; | 370 | goto out; |
328 | 371 | ||
329 | battery->type = POWER_SUPPLY_TYPE_BATTERY; | 372 | battery->type = POWER_SUPPLY_TYPE_BATTERY; |
330 | battery->properties = hidinput_battery_props; | 373 | battery->properties = hidinput_battery_props; |
@@ -332,8 +375,26 @@ static void hidinput_setup_battery(struct hid_device *dev, s32 min, s32 max) | |||
332 | battery->use_for_apm = 0; | 375 | battery->use_for_apm = 0; |
333 | battery->get_property = hidinput_get_battery_property; | 376 | battery->get_property = hidinput_get_battery_property; |
334 | 377 | ||
378 | quirks = find_battery_quirk(dev); | ||
379 | |||
380 | hid_dbg(dev, "device %x:%x:%x %d quirks %d\n", | ||
381 | dev->bus, dev->vendor, dev->product, dev->version, quirks); | ||
382 | |||
383 | min = field->logical_minimum; | ||
384 | max = field->logical_maximum; | ||
385 | |||
386 | if (quirks & HID_BATTERY_QUIRK_PERCENT) { | ||
387 | min = 0; | ||
388 | max = 100; | ||
389 | } | ||
390 | |||
391 | if (quirks & HID_BATTERY_QUIRK_FEATURE) | ||
392 | report_type = HID_FEATURE_REPORT; | ||
393 | |||
335 | dev->battery_min = min; | 394 | dev->battery_min = min; |
336 | dev->battery_max = max; | 395 | dev->battery_max = max; |
396 | dev->battery_report_type = report_type; | ||
397 | dev->battery_report_id = field->report->id; | ||
337 | 398 | ||
338 | ret = power_supply_register(&dev->dev, battery); | 399 | ret = power_supply_register(&dev->dev, battery); |
339 | if (ret != 0) { | 400 | if (ret != 0) { |
@@ -341,6 +402,9 @@ static void hidinput_setup_battery(struct hid_device *dev, s32 min, s32 max) | |||
341 | kfree(battery->name); | 402 | kfree(battery->name); |
342 | battery->name = NULL; | 403 | battery->name = NULL; |
343 | } | 404 | } |
405 | |||
406 | out: | ||
407 | return true; | ||
344 | } | 408 | } |
345 | 409 | ||
346 | static void hidinput_cleanup_battery(struct hid_device *dev) | 410 | static void hidinput_cleanup_battery(struct hid_device *dev) |
@@ -353,8 +417,10 @@ static void hidinput_cleanup_battery(struct hid_device *dev) | |||
353 | dev->battery.name = NULL; | 417 | dev->battery.name = NULL; |
354 | } | 418 | } |
355 | #else /* !CONFIG_HID_BATTERY_STRENGTH */ | 419 | #else /* !CONFIG_HID_BATTERY_STRENGTH */ |
356 | static void hidinput_setup_battery(struct hid_device *dev, s32 min, s32 max) | 420 | static bool hidinput_setup_battery(struct hid_device *dev, unsigned report_type, |
421 | struct hid_field *field) | ||
357 | { | 422 | { |
423 | return false; | ||
358 | } | 424 | } |
359 | 425 | ||
360 | static void hidinput_cleanup_battery(struct hid_device *dev) | 426 | static void hidinput_cleanup_battery(struct hid_device *dev) |
@@ -721,12 +787,9 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel | |||
721 | break; | 787 | break; |
722 | 788 | ||
723 | case HID_UP_GENDEVCTRLS: | 789 | case HID_UP_GENDEVCTRLS: |
724 | if ((usage->hid & HID_USAGE) == 0x20) { /* Battery Strength */ | 790 | if (hidinput_setup_battery(device, HID_INPUT_REPORT, field)) |
725 | hidinput_setup_battery(device, | ||
726 | field->logical_minimum, | ||
727 | field->logical_maximum); | ||
728 | goto ignore; | 791 | goto ignore; |
729 | } else | 792 | else |
730 | goto unknown; | 793 | goto unknown; |
731 | break; | 794 | break; |
732 | 795 | ||
@@ -861,14 +924,6 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct | |||
861 | 924 | ||
862 | input = field->hidinput->input; | 925 | input = field->hidinput->input; |
863 | 926 | ||
864 | #ifdef CONFIG_HID_BATTERY_STRENGTH | ||
865 | if (usage->hid == HID_DC_BATTERYSTRENGTH) { | ||
866 | hid->battery_val = value; | ||
867 | hid_dbg(hid, "battery value is %d (range %d-%d)\n", | ||
868 | value, hid->battery_min, hid->battery_max); | ||
869 | return; | ||
870 | } | ||
871 | #endif | ||
872 | if (!usage->type) | 927 | if (!usage->type) |
873 | return; | 928 | return; |
874 | 929 | ||
@@ -1039,15 +1094,17 @@ static void report_features(struct hid_device *hid) | |||
1039 | struct hid_report *rep; | 1094 | struct hid_report *rep; |
1040 | int i, j; | 1095 | int i, j; |
1041 | 1096 | ||
1042 | if (!drv->feature_mapping) | ||
1043 | return; | ||
1044 | |||
1045 | rep_enum = &hid->report_enum[HID_FEATURE_REPORT]; | 1097 | rep_enum = &hid->report_enum[HID_FEATURE_REPORT]; |
1046 | list_for_each_entry(rep, &rep_enum->report_list, list) | 1098 | list_for_each_entry(rep, &rep_enum->report_list, list) |
1047 | for (i = 0; i < rep->maxfield; i++) | 1099 | for (i = 0; i < rep->maxfield; i++) |
1048 | for (j = 0; j < rep->field[i]->maxusage; j++) | 1100 | for (j = 0; j < rep->field[i]->maxusage; j++) { |
1049 | drv->feature_mapping(hid, rep->field[i], | 1101 | /* Verify if Battery Strength feature is available */ |
1050 | rep->field[i]->usage + j); | 1102 | hidinput_setup_battery(hid, HID_FEATURE_REPORT, rep->field[i]); |
1103 | |||
1104 | if (drv->feature_mapping) | ||
1105 | drv->feature_mapping(hid, rep->field[i], | ||
1106 | rep->field[i]->usage + j); | ||
1107 | } | ||
1051 | } | 1108 | } |
1052 | 1109 | ||
1053 | /* | 1110 | /* |