aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hid
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/hid')
-rw-r--r--drivers/hid/hid-core.c2
-rw-r--r--drivers/hid/hid-ids.h1
-rw-r--r--drivers/hid/hid-input.c113
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
1162static const struct hid_device_id *hid_match_id(struct hid_device *hdev, 1162const 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
37static const unsigned char hid_keyboard[256] = { 39static 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
288static 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
295static 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
282static int hidinput_get_battery_property(struct power_supply *psy, 307static 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
317static void hidinput_setup_battery(struct hid_device *dev, s32 min, s32 max) 355static 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
406out:
407 return true;
344} 408}
345 409
346static void hidinput_cleanup_battery(struct hid_device *dev) 410static 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 */
356static void hidinput_setup_battery(struct hid_device *dev, s32 min, s32 max) 420static 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
360static void hidinput_cleanup_battery(struct hid_device *dev) 426static 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/*