aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/hid/hid-input.c108
-rw-r--r--include/linux/hid.h3
2 files changed, 108 insertions, 3 deletions
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index d6fab5798487..59a5608b8dc0 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -712,7 +712,15 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
712 map_abs_clear(usage->hid & 0xf); 712 map_abs_clear(usage->hid & 0xf);
713 break; 713 break;
714 714
715 case HID_GD_SLIDER: case HID_GD_DIAL: case HID_GD_WHEEL: 715 case HID_GD_WHEEL:
716 if (field->flags & HID_MAIN_ITEM_RELATIVE) {
717 set_bit(REL_WHEEL, input->relbit);
718 map_rel(REL_WHEEL_HI_RES);
719 } else {
720 map_abs(usage->hid & 0xf);
721 }
722 break;
723 case HID_GD_SLIDER: case HID_GD_DIAL:
716 if (field->flags & HID_MAIN_ITEM_RELATIVE) 724 if (field->flags & HID_MAIN_ITEM_RELATIVE)
717 map_rel(usage->hid & 0xf); 725 map_rel(usage->hid & 0xf);
718 else 726 else
@@ -1012,7 +1020,10 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
1012 case 0x22f: map_key_clear(KEY_ZOOMRESET); break; 1020 case 0x22f: map_key_clear(KEY_ZOOMRESET); break;
1013 case 0x233: map_key_clear(KEY_SCROLLUP); break; 1021 case 0x233: map_key_clear(KEY_SCROLLUP); break;
1014 case 0x234: map_key_clear(KEY_SCROLLDOWN); break; 1022 case 0x234: map_key_clear(KEY_SCROLLDOWN); break;
1015 case 0x238: map_rel(REL_HWHEEL); break; 1023 case 0x238: /* AC Pan */
1024 set_bit(REL_HWHEEL, input->relbit);
1025 map_rel(REL_HWHEEL_HI_RES);
1026 break;
1016 case 0x23d: map_key_clear(KEY_EDIT); break; 1027 case 0x23d: map_key_clear(KEY_EDIT); break;
1017 case 0x25f: map_key_clear(KEY_CANCEL); break; 1028 case 0x25f: map_key_clear(KEY_CANCEL); break;
1018 case 0x269: map_key_clear(KEY_INSERT); break; 1029 case 0x269: map_key_clear(KEY_INSERT); break;
@@ -1200,6 +1211,38 @@ ignore:
1200 1211
1201} 1212}
1202 1213
1214static void hidinput_handle_scroll(struct hid_usage *usage,
1215 struct input_dev *input,
1216 __s32 value)
1217{
1218 int code;
1219 int hi_res, lo_res;
1220
1221 if (value == 0)
1222 return;
1223
1224 if (usage->code == REL_WHEEL_HI_RES)
1225 code = REL_WHEEL;
1226 else
1227 code = REL_HWHEEL;
1228
1229 /*
1230 * Windows reports one wheel click as value 120. Where a high-res
1231 * scroll wheel is present, a fraction of 120 is reported instead.
1232 * Our REL_WHEEL_HI_RES axis does the same because all HW must
1233 * adhere to the 120 expectation.
1234 */
1235 hi_res = value * 120/usage->resolution_multiplier;
1236
1237 usage->wheel_accumulated += hi_res;
1238 lo_res = usage->wheel_accumulated/120;
1239 if (lo_res)
1240 usage->wheel_accumulated -= lo_res * 120;
1241
1242 input_event(input, EV_REL, code, lo_res);
1243 input_event(input, EV_REL, usage->code, hi_res);
1244}
1245
1203void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value) 1246void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value)
1204{ 1247{
1205 struct input_dev *input; 1248 struct input_dev *input;
@@ -1262,6 +1305,12 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
1262 if ((usage->type == EV_KEY) && (usage->code == 0)) /* Key 0 is "unassigned", not KEY_UNKNOWN */ 1305 if ((usage->type == EV_KEY) && (usage->code == 0)) /* Key 0 is "unassigned", not KEY_UNKNOWN */
1263 return; 1306 return;
1264 1307
1308 if ((usage->type == EV_REL) && (usage->code == REL_WHEEL_HI_RES ||
1309 usage->code == REL_HWHEEL_HI_RES)) {
1310 hidinput_handle_scroll(usage, input, value);
1311 return;
1312 }
1313
1265 if ((usage->type == EV_ABS) && (field->flags & HID_MAIN_ITEM_RELATIVE) && 1314 if ((usage->type == EV_ABS) && (field->flags & HID_MAIN_ITEM_RELATIVE) &&
1266 (usage->code == ABS_VOLUME)) { 1315 (usage->code == ABS_VOLUME)) {
1267 int count = abs(value); 1316 int count = abs(value);
@@ -1489,6 +1538,58 @@ static void hidinput_close(struct input_dev *dev)
1489 hid_hw_close(hid); 1538 hid_hw_close(hid);
1490} 1539}
1491 1540
1541static void hidinput_change_resolution_multipliers(struct hid_device *hid)
1542{
1543 struct hid_report_enum *rep_enum;
1544 struct hid_report *rep;
1545 struct hid_usage *usage;
1546 int i, j;
1547
1548 rep_enum = &hid->report_enum[HID_FEATURE_REPORT];
1549 list_for_each_entry(rep, &rep_enum->report_list, list) {
1550 bool update_needed = false;
1551
1552 if (rep->maxfield == 0)
1553 continue;
1554
1555 /*
1556 * If we have more than one feature within this report we
1557 * need to fill in the bits from the others before we can
1558 * overwrite the ones for the Resolution Multiplier.
1559 */
1560 if (rep->maxfield > 1) {
1561 hid_hw_request(hid, rep, HID_REQ_GET_REPORT);
1562 hid_hw_wait(hid);
1563 }
1564
1565 for (i = 0; i < rep->maxfield; i++) {
1566 __s32 logical_max = rep->field[i]->logical_maximum;
1567
1568 /* There is no good reason for a Resolution
1569 * Multiplier to have a count other than 1.
1570 * Ignore that case.
1571 */
1572 if (rep->field[i]->report_count != 1)
1573 continue;
1574
1575 for (j = 0; j < rep->field[i]->maxusage; j++) {
1576 usage = &rep->field[i]->usage[j];
1577
1578 if (usage->hid != HID_GD_RESOLUTION_MULTIPLIER)
1579 continue;
1580
1581 *rep->field[i]->value = logical_max;
1582 update_needed = true;
1583 }
1584 }
1585 if (update_needed)
1586 hid_hw_request(hid, rep, HID_REQ_SET_REPORT);
1587 }
1588
1589 /* refresh our structs */
1590 hid_setup_resolution_multiplier(hid);
1591}
1592
1492static void report_features(struct hid_device *hid) 1593static void report_features(struct hid_device *hid)
1493{ 1594{
1494 struct hid_driver *drv = hid->driver; 1595 struct hid_driver *drv = hid->driver;
@@ -1782,6 +1883,8 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
1782 } 1883 }
1783 } 1884 }
1784 1885
1886 hidinput_change_resolution_multipliers(hid);
1887
1785 list_for_each_entry_safe(hidinput, next, &hid->inputs, list) { 1888 list_for_each_entry_safe(hidinput, next, &hid->inputs, list) {
1786 if (drv->input_configured && 1889 if (drv->input_configured &&
1787 drv->input_configured(hid, hidinput)) 1890 drv->input_configured(hid, hidinput))
@@ -1840,4 +1943,3 @@ void hidinput_disconnect(struct hid_device *hid)
1840 cancel_work_sync(&hid->led_work); 1943 cancel_work_sync(&hid->led_work);
1841} 1944}
1842EXPORT_SYMBOL_GPL(hidinput_disconnect); 1945EXPORT_SYMBOL_GPL(hidinput_disconnect);
1843
diff --git a/include/linux/hid.h b/include/linux/hid.h
index fd8d860365a4..93db548f8761 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -233,6 +233,7 @@ struct hid_item {
233#define HID_DC_BATTERYSTRENGTH 0x00060020 233#define HID_DC_BATTERYSTRENGTH 0x00060020
234 234
235#define HID_CP_CONSUMER_CONTROL 0x000c0001 235#define HID_CP_CONSUMER_CONTROL 0x000c0001
236#define HID_CP_AC_PAN 0x000c0238
236 237
237#define HID_DG_DIGITIZER 0x000d0001 238#define HID_DG_DIGITIZER 0x000d0001
238#define HID_DG_PEN 0x000d0002 239#define HID_DG_PEN 0x000d0002
@@ -441,11 +442,13 @@ struct hid_usage {
441 __s8 resolution_multiplier;/* Effective Resolution Multiplier 442 __s8 resolution_multiplier;/* Effective Resolution Multiplier
442 (HUT v1.12, 4.3.1), default: 1 */ 443 (HUT v1.12, 4.3.1), default: 1 */
443 /* hidinput data */ 444 /* hidinput data */
445 __s8 wheel_factor; /* 120/resolution_multiplier */
444 __u16 code; /* input driver code */ 446 __u16 code; /* input driver code */
445 __u8 type; /* input driver type */ 447 __u8 type; /* input driver type */
446 __s8 hat_min; /* hat switch fun */ 448 __s8 hat_min; /* hat switch fun */
447 __s8 hat_max; /* ditto */ 449 __s8 hat_max; /* ditto */
448 __s8 hat_dir; /* ditto */ 450 __s8 hat_dir; /* ditto */
451 __s16 wheel_accumulated; /* hi-res wheel */
449}; 452};
450 453
451struct hid_input; 454struct hid_input;