diff options
| author | Andrew Duggan <aduggan@synaptics.com> | 2014-12-19 17:45:41 -0500 |
|---|---|---|
| committer | Jiri Kosina <jkosina@suse.cz> | 2014-12-22 08:22:57 -0500 |
| commit | 2f43de605e700f5aa5cad15e19f8ffe54b1d4c86 (patch) | |
| tree | 0a9a2c7675ac7f63c6935cd2d7b2036cd2325243 /drivers | |
| parent | e39f2d5956999c05c85814787a113ffadbcd4b26 (diff) | |
HID: rmi: Support non rmi devices by passing events to hid-input
Allowing hid-rmi to bind to non rmi devices allows us to support composite USB
devices which contain several HID devices one of which is a HID touchpad.
Since all of the devices have the same VID and PID we can add the device
to the hid_have_special_driver list and have hid-rmi handle all of the devices.
Then hid-rmi's probe can look for the rmi specific HID report IDs and decide if
it should handle the device as a rmi device or simply report that the events
needs additional processing.
Signed-off-by: Andrew Duggan <aduggan@synaptics.com>
Reviewed-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/hid/hid-rmi.c | 93 |
1 files changed, 76 insertions, 17 deletions
diff --git a/drivers/hid/hid-rmi.c b/drivers/hid/hid-rmi.c index b51200fe2f33..018f80f5fec6 100644 --- a/drivers/hid/hid-rmi.c +++ b/drivers/hid/hid-rmi.c | |||
| @@ -33,6 +33,9 @@ | |||
| 33 | #define RMI_READ_DATA_PENDING BIT(1) | 33 | #define RMI_READ_DATA_PENDING BIT(1) |
| 34 | #define RMI_STARTED BIT(2) | 34 | #define RMI_STARTED BIT(2) |
| 35 | 35 | ||
| 36 | /* device flags */ | ||
| 37 | #define RMI_DEVICE BIT(0) | ||
| 38 | |||
| 36 | enum rmi_mode_type { | 39 | enum rmi_mode_type { |
| 37 | RMI_MODE_OFF = 0, | 40 | RMI_MODE_OFF = 0, |
| 38 | RMI_MODE_ATTN_REPORTS = 1, | 41 | RMI_MODE_ATTN_REPORTS = 1, |
| @@ -118,6 +121,8 @@ struct rmi_data { | |||
| 118 | 121 | ||
| 119 | struct work_struct reset_work; | 122 | struct work_struct reset_work; |
| 120 | struct hid_device *hdev; | 123 | struct hid_device *hdev; |
| 124 | |||
| 125 | unsigned long device_flags; | ||
| 121 | }; | 126 | }; |
| 122 | 127 | ||
| 123 | #define RMI_PAGE(addr) (((addr) >> 8) & 0xff) | 128 | #define RMI_PAGE(addr) (((addr) >> 8) & 0xff) |
| @@ -452,9 +457,23 @@ static int rmi_raw_event(struct hid_device *hdev, | |||
| 452 | return rmi_read_data_event(hdev, data, size); | 457 | return rmi_read_data_event(hdev, data, size); |
| 453 | case RMI_ATTN_REPORT_ID: | 458 | case RMI_ATTN_REPORT_ID: |
| 454 | return rmi_input_event(hdev, data, size); | 459 | return rmi_input_event(hdev, data, size); |
| 455 | case RMI_MOUSE_REPORT_ID: | 460 | default: |
| 461 | return 1; | ||
| 462 | } | ||
| 463 | |||
| 464 | return 0; | ||
| 465 | } | ||
| 466 | |||
| 467 | static int rmi_event(struct hid_device *hdev, struct hid_field *field, | ||
| 468 | struct hid_usage *usage, __s32 value) | ||
| 469 | { | ||
| 470 | struct rmi_data *data = hid_get_drvdata(hdev); | ||
| 471 | |||
| 472 | if ((data->device_flags & RMI_DEVICE) && | ||
| 473 | (field->application == HID_GD_POINTER || | ||
| 474 | field->application == HID_GD_MOUSE)) { | ||
| 456 | rmi_schedule_reset(hdev); | 475 | rmi_schedule_reset(hdev); |
| 457 | break; | 476 | return 1; |
| 458 | } | 477 | } |
| 459 | 478 | ||
| 460 | return 0; | 479 | return 0; |
| @@ -856,6 +875,9 @@ static void rmi_input_configured(struct hid_device *hdev, struct hid_input *hi) | |||
| 856 | if (ret) | 875 | if (ret) |
| 857 | return; | 876 | return; |
| 858 | 877 | ||
| 878 | if (!(data->device_flags & RMI_DEVICE)) | ||
| 879 | return; | ||
| 880 | |||
| 859 | /* Allow incoming hid reports */ | 881 | /* Allow incoming hid reports */ |
| 860 | hid_device_io_start(hdev); | 882 | hid_device_io_start(hdev); |
| 861 | 883 | ||
| @@ -914,8 +936,33 @@ static int rmi_input_mapping(struct hid_device *hdev, | |||
| 914 | struct hid_input *hi, struct hid_field *field, | 936 | struct hid_input *hi, struct hid_field *field, |
| 915 | struct hid_usage *usage, unsigned long **bit, int *max) | 937 | struct hid_usage *usage, unsigned long **bit, int *max) |
| 916 | { | 938 | { |
| 917 | /* we want to make HID ignore the advertised HID collection */ | 939 | struct rmi_data *data = hid_get_drvdata(hdev); |
| 918 | return -1; | 940 | |
| 941 | /* | ||
| 942 | * we want to make HID ignore the advertised HID collection | ||
| 943 | * for RMI deivces | ||
| 944 | */ | ||
| 945 | if (data->device_flags & RMI_DEVICE) | ||
| 946 | return -1; | ||
| 947 | |||
| 948 | return 0; | ||
| 949 | } | ||
| 950 | |||
| 951 | static int rmi_check_valid_report_id(struct hid_device *hdev, unsigned type, | ||
| 952 | unsigned id, struct hid_report **report) | ||
| 953 | { | ||
| 954 | int i; | ||
| 955 | |||
| 956 | *report = hdev->report_enum[type].report_id_hash[id]; | ||
| 957 | if (*report) { | ||
| 958 | for (i = 0; i < (*report)->maxfield; i++) { | ||
| 959 | unsigned app = (*report)->field[i]->application; | ||
| 960 | if ((app & HID_USAGE_PAGE) >= HID_UP_MSVENDOR) | ||
| 961 | return 1; | ||
| 962 | } | ||
| 963 | } | ||
| 964 | |||
| 965 | return 0; | ||
| 919 | } | 966 | } |
| 920 | 967 | ||
| 921 | static int rmi_probe(struct hid_device *hdev, const struct hid_device_id *id) | 968 | static int rmi_probe(struct hid_device *hdev, const struct hid_device_id *id) |
| @@ -925,6 +972,7 @@ static int rmi_probe(struct hid_device *hdev, const struct hid_device_id *id) | |||
| 925 | size_t alloc_size; | 972 | size_t alloc_size; |
| 926 | struct hid_report *input_report; | 973 | struct hid_report *input_report; |
| 927 | struct hid_report *output_report; | 974 | struct hid_report *output_report; |
| 975 | struct hid_report *feature_report; | ||
| 928 | 976 | ||
| 929 | data = devm_kzalloc(&hdev->dev, sizeof(struct rmi_data), GFP_KERNEL); | 977 | data = devm_kzalloc(&hdev->dev, sizeof(struct rmi_data), GFP_KERNEL); |
| 930 | if (!data) | 978 | if (!data) |
| @@ -943,27 +991,35 @@ static int rmi_probe(struct hid_device *hdev, const struct hid_device_id *id) | |||
| 943 | return ret; | 991 | return ret; |
| 944 | } | 992 | } |
| 945 | 993 | ||
| 946 | input_report = hdev->report_enum[HID_INPUT_REPORT] | 994 | /* |
| 947 | .report_id_hash[RMI_ATTN_REPORT_ID]; | 995 | * Check for the RMI specific report ids. If they are misisng |
| 948 | if (!input_report) { | 996 | * simply return and let the events be processed by hid-input |
| 949 | hid_err(hdev, "device does not have expected input report\n"); | 997 | */ |
| 950 | ret = -ENODEV; | 998 | if (!rmi_check_valid_report_id(hdev, HID_FEATURE_REPORT, |
| 951 | return ret; | 999 | RMI_SET_RMI_MODE_REPORT_ID, &feature_report)) { |
| 1000 | hid_dbg(hdev, "device does not have set mode feature report\n"); | ||
| 1001 | goto start; | ||
| 1002 | } | ||
| 1003 | |||
| 1004 | if (!rmi_check_valid_report_id(hdev, HID_INPUT_REPORT, | ||
| 1005 | RMI_ATTN_REPORT_ID, &input_report)) { | ||
| 1006 | hid_dbg(hdev, "device does not have attention input report\n"); | ||
| 1007 | goto start; | ||
| 952 | } | 1008 | } |
| 953 | 1009 | ||
| 954 | data->input_report_size = (input_report->size >> 3) + 1 /* report id */; | 1010 | data->input_report_size = (input_report->size >> 3) + 1 /* report id */; |
| 955 | 1011 | ||
| 956 | output_report = hdev->report_enum[HID_OUTPUT_REPORT] | 1012 | if (!rmi_check_valid_report_id(hdev, HID_OUTPUT_REPORT, |
| 957 | .report_id_hash[RMI_WRITE_REPORT_ID]; | 1013 | RMI_WRITE_REPORT_ID, &output_report)) { |
| 958 | if (!output_report) { | 1014 | hid_dbg(hdev, |
| 959 | hid_err(hdev, "device does not have expected output report\n"); | 1015 | "device does not have rmi write output report\n"); |
| 960 | ret = -ENODEV; | 1016 | goto start; |
| 961 | return ret; | ||
| 962 | } | 1017 | } |
| 963 | 1018 | ||
| 964 | data->output_report_size = (output_report->size >> 3) | 1019 | data->output_report_size = (output_report->size >> 3) |
| 965 | + 1 /* report id */; | 1020 | + 1 /* report id */; |
| 966 | 1021 | ||
| 1022 | data->device_flags |= RMI_DEVICE; | ||
| 967 | alloc_size = data->output_report_size + data->input_report_size; | 1023 | alloc_size = data->output_report_size + data->input_report_size; |
| 968 | 1024 | ||
| 969 | data->writeReport = devm_kzalloc(&hdev->dev, alloc_size, GFP_KERNEL); | 1025 | data->writeReport = devm_kzalloc(&hdev->dev, alloc_size, GFP_KERNEL); |
| @@ -978,13 +1034,15 @@ static int rmi_probe(struct hid_device *hdev, const struct hid_device_id *id) | |||
| 978 | 1034 | ||
| 979 | mutex_init(&data->page_mutex); | 1035 | mutex_init(&data->page_mutex); |
| 980 | 1036 | ||
| 1037 | start: | ||
| 981 | ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); | 1038 | ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); |
| 982 | if (ret) { | 1039 | if (ret) { |
| 983 | hid_err(hdev, "hw start failed\n"); | 1040 | hid_err(hdev, "hw start failed\n"); |
| 984 | return ret; | 1041 | return ret; |
| 985 | } | 1042 | } |
| 986 | 1043 | ||
| 987 | if (!test_bit(RMI_STARTED, &data->flags)) | 1044 | if ((data->device_flags & RMI_DEVICE) && |
| 1045 | !test_bit(RMI_STARTED, &data->flags)) | ||
| 988 | /* | 1046 | /* |
| 989 | * The device maybe in the bootloader if rmi_input_configured | 1047 | * The device maybe in the bootloader if rmi_input_configured |
| 990 | * failed to find F11 in the PDT. Print an error, but don't | 1048 | * failed to find F11 in the PDT. Print an error, but don't |
| @@ -1017,6 +1075,7 @@ static struct hid_driver rmi_driver = { | |||
| 1017 | .id_table = rmi_id, | 1075 | .id_table = rmi_id, |
| 1018 | .probe = rmi_probe, | 1076 | .probe = rmi_probe, |
| 1019 | .remove = rmi_remove, | 1077 | .remove = rmi_remove, |
| 1078 | .event = rmi_event, | ||
| 1020 | .raw_event = rmi_raw_event, | 1079 | .raw_event = rmi_raw_event, |
| 1021 | .input_mapping = rmi_input_mapping, | 1080 | .input_mapping = rmi_input_mapping, |
| 1022 | .input_configured = rmi_input_configured, | 1081 | .input_configured = rmi_input_configured, |
