aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hid/i2c-hid
diff options
context:
space:
mode:
authorArchana Patni <archana.patni@linux.intel.com>2014-05-08 09:26:19 -0400
committerJiri Kosina <jkosina@suse.cz>2014-05-13 05:19:22 -0400
commitf58b8487bcc898acad3eeea6f950e673d9b79dea (patch)
treedcb378c1bebd0d6abe7d754bb784262deb0a72c7 /drivers/hid/i2c-hid
parent7ceeff443be92913f7edd1134d677fa2a1824cd0 (diff)
HID: i2c-hid: hid report descriptor retrieval changes
Reading the partial HID Descriptor is causing a firmware lockup in some sensor hubs. Instead of a partial read, this patch implements the i2c hid fetch using a fixed descriptor size (30 bytes) followed by a verification of the BCDVersion (V01.00), and value stored in wHIDDescLength (30 Bytes) for V1.00 descriptors. As per i2c hid spec, this is the preferred model. From hid-over-i2c-protocol-spec-v1-0: There are a variety of ways a HOST may choose to retrieve the HID Descriptor from the DEVICE. The following is a preferred implementation but should not be considered the only implementation. A HOST may read the entire HID Descriptor in a single read by issuing a read for 30 Bytes to get the entire HID Descriptor from the DEVICE.However, the HOST is responsible for validating that 1. The BCDVersion is V01.00 (later revisions may have different descriptor lengths), and 2. The value stored in wHIDDescLength is 30 (Bytes) for V1.00 descriptors. Reported-by: Joe Tijerina <joe.tijerina@st.com> Signed-off-by: Archana Patni <archana.patni@intel.com> Signed-off-by: Subramony Sesha <subramony.sesha@intel.com> Reviewed-by: Mika Westerberg <mika.westerberg@linux.intel.com> Reviewed-by: Benjamin Tissoires <benjamin.tissoires@redhat.com> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'drivers/hid/i2c-hid')
-rw-r--r--drivers/hid/i2c-hid/i2c-hid.c45
1 files changed, 13 insertions, 32 deletions
diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c
index b50860db92f1..21aafc8f48c8 100644
--- a/drivers/hid/i2c-hid/i2c-hid.c
+++ b/drivers/hid/i2c-hid/i2c-hid.c
@@ -807,34 +807,18 @@ static int i2c_hid_fetch_hid_descriptor(struct i2c_hid *ihid)
807 unsigned int dsize; 807 unsigned int dsize;
808 int ret; 808 int ret;
809 809
810 /* Fetch the length of HID description, retrieve the 4 first bytes: 810 /* i2c hid fetch using a fixed descriptor size (30 bytes) */
811 * bytes 0-1 -> length 811 i2c_hid_dbg(ihid, "Fetching the HID descriptor\n");
812 * bytes 2-3 -> bcdVersion (has to be 1.00) */ 812 ret = i2c_hid_command(client, &hid_descr_cmd, ihid->hdesc_buffer,
813 ret = i2c_hid_command(client, &hid_descr_cmd, ihid->hdesc_buffer, 4); 813 sizeof(struct i2c_hid_desc));
814
815 i2c_hid_dbg(ihid, "%s, ihid->hdesc_buffer: %4ph\n", __func__,
816 ihid->hdesc_buffer);
817
818 if (ret) { 814 if (ret) {
819 dev_err(&client->dev, 815 dev_err(&client->dev, "hid_descr_cmd failed\n");
820 "unable to fetch the size of HID descriptor (ret=%d)\n",
821 ret);
822 return -ENODEV;
823 }
824
825 dsize = le16_to_cpu(hdesc->wHIDDescLength);
826 /*
827 * the size of the HID descriptor should at least contain
828 * its size and the bcdVersion (4 bytes), and should not be greater
829 * than sizeof(struct i2c_hid_desc) as we directly fill this struct
830 * through i2c_hid_command.
831 */
832 if (dsize < 4 || dsize > sizeof(struct i2c_hid_desc)) {
833 dev_err(&client->dev, "weird size of HID descriptor (%u)\n",
834 dsize);
835 return -ENODEV; 816 return -ENODEV;
836 } 817 }
837 818
819 /* Validate the length of HID descriptor, the 4 first bytes:
820 * bytes 0-1 -> length
821 * bytes 2-3 -> bcdVersion (has to be 1.00) */
838 /* check bcdVersion == 1.0 */ 822 /* check bcdVersion == 1.0 */
839 if (le16_to_cpu(hdesc->bcdVersion) != 0x0100) { 823 if (le16_to_cpu(hdesc->bcdVersion) != 0x0100) {
840 dev_err(&client->dev, 824 dev_err(&client->dev,
@@ -843,17 +827,14 @@ static int i2c_hid_fetch_hid_descriptor(struct i2c_hid *ihid)
843 return -ENODEV; 827 return -ENODEV;
844 } 828 }
845 829
846 i2c_hid_dbg(ihid, "Fetching the HID descriptor\n"); 830 /* Descriptor length should be 30 bytes as per the specification */
847 831 dsize = le16_to_cpu(hdesc->wHIDDescLength);
848 ret = i2c_hid_command(client, &hid_descr_cmd, ihid->hdesc_buffer, 832 if (dsize != sizeof(struct i2c_hid_desc)) {
849 dsize); 833 dev_err(&client->dev, "weird size of HID descriptor (%u)\n",
850 if (ret) { 834 dsize);
851 dev_err(&client->dev, "hid_descr_cmd Fail\n");
852 return -ENODEV; 835 return -ENODEV;
853 } 836 }
854
855 i2c_hid_dbg(ihid, "HID Descriptor: %*ph\n", dsize, ihid->hdesc_buffer); 837 i2c_hid_dbg(ihid, "HID Descriptor: %*ph\n", dsize, ihid->hdesc_buffer);
856
857 return 0; 838 return 0;
858} 839}
859 840