summaryrefslogtreecommitdiffstats
path: root/drivers/hid/hid-input.c
diff options
context:
space:
mode:
authorKonrad Rzeszutek Wilk <konrad.wilk@oracle.com>2013-05-15 10:26:50 -0400
committerKonrad Rzeszutek Wilk <konrad.wilk@oracle.com>2013-05-15 10:26:50 -0400
commit12e04ffcd93b25dfd726d46338c2ee7d23de556e (patch)
treef91479a62805619168994fd3ee55e3ffa23fc24e /drivers/hid/hid-input.c
parent9eff37a8713939f218ab8bf0dc93f1d67af7b8b4 (diff)
parentf722406faae2d073cc1d01063d1123c35425939e (diff)
Merge tag 'v3.10-rc1' into stable/for-linus-3.10
Linux 3.10-rc1 * tag 'v3.10-rc1': (12273 commits) Linux 3.10-rc1 [SCSI] qla2xxx: Update firmware link in Kconfig file. [SCSI] iscsi class, qla4xxx: fix sess/conn refcounting when find fns are used [SCSI] sas: unify the pointlessly separated enums sas_dev_type and sas_device_type [SCSI] pm80xx: thermal, sas controller config and error handling update [SCSI] pm80xx: NCQ error handling changes [SCSI] pm80xx: WWN Modification for PM8081/88/89 controllers [SCSI] pm80xx: Changed module name and debug messages update [SCSI] pm80xx: Firmware flash memory free fix, with addition of new memory region for it [SCSI] pm80xx: SPC new firmware changes for device id 0x8081 alone [SCSI] pm80xx: Added SPCv/ve specific hardware functionalities and relevant changes in common files [SCSI] pm80xx: MSI-X implementation for using 64 interrupts [SCSI] pm80xx: Updated common functions common for SPC and SPCv/ve [SCSI] pm80xx: Multiple inbound/outbound queue configuration [SCSI] pm80xx: Added SPCv/ve specific ids, variables and modify for SPC [SCSI] lpfc: fix up Kconfig dependencies [SCSI] Handle MLQUEUE busy response in scsi_send_eh_cmnd dm cache: set config value dm cache: move config fns dm thin: generate event when metadata threshold passed ...
Diffstat (limited to 'drivers/hid/hid-input.c')
-rw-r--r--drivers/hid/hid-input.c77
1 files changed, 77 insertions, 0 deletions
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index 21b196c394b..945b8158ec4 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)
return hidinput;
}
+static bool hidinput_has_been_populated(struct hid_input *hidinput)
+{
+ int i;
+ unsigned long r = 0;
+
+ for (i = 0; i < BITS_TO_LONGS(EV_CNT); i++)
+ r |= hidinput->input->evbit[i];
+
+ for (i = 0; i < BITS_TO_LONGS(KEY_CNT); i++)
+ r |= hidinput->input->keybit[i];
+
+ for (i = 0; i < BITS_TO_LONGS(REL_CNT); i++)
+ r |= hidinput->input->relbit[i];
+
+ for (i = 0; i < BITS_TO_LONGS(ABS_CNT); i++)
+ r |= hidinput->input->absbit[i];
+
+ for (i = 0; i < BITS_TO_LONGS(MSC_CNT); i++)
+ r |= hidinput->input->mscbit[i];
+
+ for (i = 0; i < BITS_TO_LONGS(LED_CNT); i++)
+ r |= hidinput->input->ledbit[i];
+
+ for (i = 0; i < BITS_TO_LONGS(SND_CNT); i++)
+ r |= hidinput->input->sndbit[i];
+
+ for (i = 0; i < BITS_TO_LONGS(FF_CNT); i++)
+ r |= hidinput->input->ffbit[i];
+
+ for (i = 0; i < BITS_TO_LONGS(SW_CNT); i++)
+ r |= hidinput->input->swbit[i];
+
+ return !!r;
+}
+
+static void hidinput_cleanup_hidinput(struct hid_device *hid,
+ struct hid_input *hidinput)
+{
+ struct hid_report *report;
+ int i, k;
+
+ list_del(&hidinput->list);
+ input_free_device(hidinput->input);
+
+ for (k = HID_INPUT_REPORT; k <= HID_OUTPUT_REPORT; k++) {
+ if (k == HID_OUTPUT_REPORT &&
+ hid->quirks & HID_QUIRK_SKIP_OUTPUT_REPORTS)
+ continue;
+
+ list_for_each_entry(report, &hid->report_enum[k].report_list,
+ list) {
+
+ for (i = 0; i < report->maxfield; i++)
+ if (report->field[i]->hidinput == hidinput)
+ report->field[i]->hidinput = NULL;
+ }
+ }
+
+ kfree(hidinput);
+}
+
/*
* Register the input device; print a message.
* Configure the input layer interface
@@ -1249,6 +1310,10 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
hidinput_configure_usage(hidinput, report->field[i],
report->field[i]->usage + j);
+ if ((hid->quirks & HID_QUIRK_NO_EMPTY_INPUT) &&
+ !hidinput_has_been_populated(hidinput))
+ continue;
+
if (hid->quirks & HID_QUIRK_MULTI_INPUT) {
/* This will leave hidinput NULL, so that it
* allocates another one if we have more inputs on
@@ -1265,6 +1330,18 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
}
}
+ if (hidinput && (hid->quirks & HID_QUIRK_NO_EMPTY_INPUT) &&
+ !hidinput_has_been_populated(hidinput)) {
+ /* no need to register an input device not populated */
+ hidinput_cleanup_hidinput(hid, hidinput);
+ hidinput = NULL;
+ }
+
+ if (list_empty(&hid->inputs)) {
+ hid_err(hid, "No inputs registered, leaving\n");
+ goto out_unwind;
+ }
+
if (hidinput) {
if (drv->input_configured)
drv->input_configured(hid, hidinput);