diff options
author | Benjamin Tissoires <benjamin.tissoires@redhat.com> | 2013-03-22 13:38:28 -0400 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2013-03-27 09:02:45 -0400 |
commit | 4f22decf9b6329acfe59091c5cba6b378b9b31db (patch) | |
tree | fddbec2a0158f8d93cfe6fc886d459b3c2f81664 | |
parent | b3fecf8cab6441527ab057c99d7e6a6d7f6713e5 (diff) |
HID: input: don't register unmapped input devices
There is no need to register an input device containing no events.
This allows drivers using the quirk MULTI_INPUT to register one input
per report effectively used.
For backward compatibility, we need to add a quirk to request
this behavior.
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
-rw-r--r-- | drivers/hid/hid-input.c | 77 | ||||
-rw-r--r-- | include/linux/hid.h | 1 |
2 files changed, 78 insertions, 0 deletions
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 21b196c394b1..945b8158ec4c 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c | |||
@@ -1198,6 +1198,67 @@ static struct hid_input *hidinput_allocate(struct hid_device *hid) | |||
1198 | return hidinput; | 1198 | return hidinput; |
1199 | } | 1199 | } |
1200 | 1200 | ||
1201 | static bool hidinput_has_been_populated(struct hid_input *hidinput) | ||
1202 | { | ||
1203 | int i; | ||
1204 | unsigned long r = 0; | ||
1205 | |||
1206 | for (i = 0; i < BITS_TO_LONGS(EV_CNT); i++) | ||
1207 | r |= hidinput->input->evbit[i]; | ||
1208 | |||
1209 | for (i = 0; i < BITS_TO_LONGS(KEY_CNT); i++) | ||
1210 | r |= hidinput->input->keybit[i]; | ||
1211 | |||
1212 | for (i = 0; i < BITS_TO_LONGS(REL_CNT); i++) | ||
1213 | r |= hidinput->input->relbit[i]; | ||
1214 | |||
1215 | for (i = 0; i < BITS_TO_LONGS(ABS_CNT); i++) | ||
1216 | r |= hidinput->input->absbit[i]; | ||
1217 | |||
1218 | for (i = 0; i < BITS_TO_LONGS(MSC_CNT); i++) | ||
1219 | r |= hidinput->input->mscbit[i]; | ||
1220 | |||
1221 | for (i = 0; i < BITS_TO_LONGS(LED_CNT); i++) | ||
1222 | r |= hidinput->input->ledbit[i]; | ||
1223 | |||
1224 | for (i = 0; i < BITS_TO_LONGS(SND_CNT); i++) | ||
1225 | r |= hidinput->input->sndbit[i]; | ||
1226 | |||
1227 | for (i = 0; i < BITS_TO_LONGS(FF_CNT); i++) | ||
1228 | r |= hidinput->input->ffbit[i]; | ||
1229 | |||
1230 | for (i = 0; i < BITS_TO_LONGS(SW_CNT); i++) | ||
1231 | r |= hidinput->input->swbit[i]; | ||
1232 | |||
1233 | return !!r; | ||
1234 | } | ||
1235 | |||
1236 | static void hidinput_cleanup_hidinput(struct hid_device *hid, | ||
1237 | struct hid_input *hidinput) | ||
1238 | { | ||
1239 | struct hid_report *report; | ||
1240 | int i, k; | ||
1241 | |||
1242 | list_del(&hidinput->list); | ||
1243 | input_free_device(hidinput->input); | ||
1244 | |||
1245 | for (k = HID_INPUT_REPORT; k <= HID_OUTPUT_REPORT; k++) { | ||
1246 | if (k == HID_OUTPUT_REPORT && | ||
1247 | hid->quirks & HID_QUIRK_SKIP_OUTPUT_REPORTS) | ||
1248 | continue; | ||
1249 | |||
1250 | list_for_each_entry(report, &hid->report_enum[k].report_list, | ||
1251 | list) { | ||
1252 | |||
1253 | for (i = 0; i < report->maxfield; i++) | ||
1254 | if (report->field[i]->hidinput == hidinput) | ||
1255 | report->field[i]->hidinput = NULL; | ||
1256 | } | ||
1257 | } | ||
1258 | |||
1259 | kfree(hidinput); | ||
1260 | } | ||
1261 | |||
1201 | /* | 1262 | /* |
1202 | * Register the input device; print a message. | 1263 | * Register the input device; print a message. |
1203 | * Configure the input layer interface | 1264 | * Configure the input layer interface |
@@ -1249,6 +1310,10 @@ int hidinput_connect(struct hid_device *hid, unsigned int force) | |||
1249 | hidinput_configure_usage(hidinput, report->field[i], | 1310 | hidinput_configure_usage(hidinput, report->field[i], |
1250 | report->field[i]->usage + j); | 1311 | report->field[i]->usage + j); |
1251 | 1312 | ||
1313 | if ((hid->quirks & HID_QUIRK_NO_EMPTY_INPUT) && | ||
1314 | !hidinput_has_been_populated(hidinput)) | ||
1315 | continue; | ||
1316 | |||
1252 | if (hid->quirks & HID_QUIRK_MULTI_INPUT) { | 1317 | if (hid->quirks & HID_QUIRK_MULTI_INPUT) { |
1253 | /* This will leave hidinput NULL, so that it | 1318 | /* This will leave hidinput NULL, so that it |
1254 | * allocates another one if we have more inputs on | 1319 | * allocates another one if we have more inputs on |
@@ -1265,6 +1330,18 @@ int hidinput_connect(struct hid_device *hid, unsigned int force) | |||
1265 | } | 1330 | } |
1266 | } | 1331 | } |
1267 | 1332 | ||
1333 | if (hidinput && (hid->quirks & HID_QUIRK_NO_EMPTY_INPUT) && | ||
1334 | !hidinput_has_been_populated(hidinput)) { | ||
1335 | /* no need to register an input device not populated */ | ||
1336 | hidinput_cleanup_hidinput(hid, hidinput); | ||
1337 | hidinput = NULL; | ||
1338 | } | ||
1339 | |||
1340 | if (list_empty(&hid->inputs)) { | ||
1341 | hid_err(hid, "No inputs registered, leaving\n"); | ||
1342 | goto out_unwind; | ||
1343 | } | ||
1344 | |||
1268 | if (hidinput) { | 1345 | if (hidinput) { |
1269 | if (drv->input_configured) | 1346 | if (drv->input_configured) |
1270 | drv->input_configured(hid, hidinput); | 1347 | drv->input_configured(hid, hidinput); |
diff --git a/include/linux/hid.h b/include/linux/hid.h index 863744c38ddc..fffa06bc4880 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h | |||
@@ -282,6 +282,7 @@ struct hid_item { | |||
282 | #define HID_QUIRK_BADPAD 0x00000020 | 282 | #define HID_QUIRK_BADPAD 0x00000020 |
283 | #define HID_QUIRK_MULTI_INPUT 0x00000040 | 283 | #define HID_QUIRK_MULTI_INPUT 0x00000040 |
284 | #define HID_QUIRK_HIDINPUT_FORCE 0x00000080 | 284 | #define HID_QUIRK_HIDINPUT_FORCE 0x00000080 |
285 | #define HID_QUIRK_NO_EMPTY_INPUT 0x00000100 | ||
285 | #define HID_QUIRK_SKIP_OUTPUT_REPORTS 0x00010000 | 286 | #define HID_QUIRK_SKIP_OUTPUT_REPORTS 0x00010000 |
286 | #define HID_QUIRK_FULLSPEED_INTERVAL 0x10000000 | 287 | #define HID_QUIRK_FULLSPEED_INTERVAL 0x10000000 |
287 | #define HID_QUIRK_NO_INIT_REPORTS 0x20000000 | 288 | #define HID_QUIRK_NO_INIT_REPORTS 0x20000000 |