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 | |
| 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
| -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 | ||||
| -rw-r--r-- | include/linux/hid.h | 5 |
4 files changed, 91 insertions, 30 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 | /* |
diff --git a/include/linux/hid.h b/include/linux/hid.h index 8ac51d6e81e0..3a95da60fd3e 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h | |||
| @@ -495,7 +495,8 @@ struct hid_device { /* device report descriptor */ | |||
| 495 | struct power_supply battery; | 495 | struct power_supply battery; |
| 496 | __s32 battery_min; | 496 | __s32 battery_min; |
| 497 | __s32 battery_max; | 497 | __s32 battery_max; |
| 498 | __s32 battery_val; | 498 | __s32 battery_report_type; |
| 499 | __s32 battery_report_id; | ||
| 499 | #endif | 500 | #endif |
| 500 | 501 | ||
| 501 | unsigned int status; /* see STAT flags above */ | 502 | unsigned int status; /* see STAT flags above */ |
| @@ -737,6 +738,8 @@ int hid_parse_report(struct hid_device *hid, __u8 *start, unsigned size); | |||
| 737 | int hid_check_keys_pressed(struct hid_device *hid); | 738 | int hid_check_keys_pressed(struct hid_device *hid); |
| 738 | int hid_connect(struct hid_device *hid, unsigned int connect_mask); | 739 | int hid_connect(struct hid_device *hid, unsigned int connect_mask); |
| 739 | void hid_disconnect(struct hid_device *hid); | 740 | void hid_disconnect(struct hid_device *hid); |
| 741 | const struct hid_device_id *hid_match_id(struct hid_device *hdev, | ||
| 742 | const struct hid_device_id *id); | ||
| 740 | 743 | ||
| 741 | /** | 744 | /** |
| 742 | * hid_map_usage - map usage input bits | 745 | * hid_map_usage - map usage input bits |
