diff options
| -rw-r--r-- | drivers/hid/hid-input.c | 108 | ||||
| -rw-r--r-- | include/linux/hid.h | 3 |
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 | ||
| 1214 | static 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 | |||
| 1203 | void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value) | 1246 | void 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 | ||
| 1541 | static 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 | |||
| 1492 | static void report_features(struct hid_device *hid) | 1593 | static 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 | } |
| 1842 | EXPORT_SYMBOL_GPL(hidinput_disconnect); | 1945 | EXPORT_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 | ||
| 451 | struct hid_input; | 454 | struct hid_input; |
