diff options
author | Robert Schedel <r.schedel@yahoo.de> | 2009-06-23 05:26:48 -0400 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2009-07-22 19:27:59 -0400 |
commit | 0810b51170570ed21cae56b8131db6a5e3efa584 (patch) | |
tree | aca5fd5ad71897582c01527ddf57db0aa498d4e1 /drivers/hid | |
parent | 3c3301083e3bea4d14c597106c7b20b4b85fc03d (diff) |
HID: Support new variants of Samsung USB IR receiver (0419:0001)
This patch extends the existing Samsung IrDA (0419:0001) quirk file with newly
reported variants:
* New device variants with 203 byte and 135 byte report descriptors were
reported to be recognized incorrectly. This patch adds an autodetection for
those two, using report descriptor size to enable new quirks.
* Any other unknown 0419:0001 variants will now be treated without any quirk
flags (i.e. IGNORE_HIDINPUT/HIDDEV_FORCE will not be set by default anymore).
More details:
1. Descriptor size 184 bytes ("Satelco bundled remote")
Already supported since kernel 2.6.25 (my old patch).
2. Descriptor size 203 bytes ("Optronix remote")
This receiver mostly works with the regular HID input driver. Only when some
keys are released, another spurious key press event is interpreted due to
incorrect array ranges. According to HID 1.11, section 6.2.2.5, arrays should
return a 0 value when no control is asserted, and ranges should go from 1 to
the number of elements. The patch clips the value with a logical range from
1..15 (instead of originally 0..18).
Ticket with more information available at
https://bugs.launchpad.net/bugs/326986
3. Descriptor size 135 bytes ("Gotview remote")
This receiver has a similar issue than the previous one, i.e. it mostly works
with regular HID input, except some key press events get stuck on key release.
The patch clips the array value from 1..14 (instead of originally 0..17).
Ticket with more information available at
http://bugs.archlinux.org/task/15216
4. Other unknown variants (found one report with 218 bytes,
but no further information about issues)
For such unknown variants we should refrain from changing any device flags.
Currently, HIDINPUT is suppressed and HIDDEV is enforced (because in 2.6.25 the
quirk table did not yet allow differentiating variants and we
did not expect variants either). Now we should be as strict as
possible and enable it only for the first variant above.
Signed-off-by: Robert Schedel <r.schedel@yahoo.de>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'drivers/hid')
-rw-r--r-- | drivers/hid/hid-samsung.c | 39 |
1 files changed, 34 insertions, 5 deletions
diff --git a/drivers/hid/hid-samsung.c b/drivers/hid/hid-samsung.c index 07083aa6c19a..ba91d9485ad0 100644 --- a/drivers/hid/hid-samsung.c +++ b/drivers/hid/hid-samsung.c | |||
@@ -25,25 +25,48 @@ | |||
25 | /* | 25 | /* |
26 | * Samsung IrDA remote controller (reports as Cypress USB Mouse). | 26 | * Samsung IrDA remote controller (reports as Cypress USB Mouse). |
27 | * | 27 | * |
28 | * There are several variants for 0419:0001: | ||
29 | * | ||
30 | * 1. 184 byte report descriptor | ||
28 | * Vendor specific report #4 has a size of 48 bit, | 31 | * Vendor specific report #4 has a size of 48 bit, |
29 | * and therefore is not accepted when inspecting the descriptors. | 32 | * and therefore is not accepted when inspecting the descriptors. |
30 | * As a workaround we reinterpret the report as: | 33 | * As a workaround we reinterpret the report as: |
31 | * Variable type, count 6, size 8 bit, log. maximum 255 | 34 | * Variable type, count 6, size 8 bit, log. maximum 255 |
32 | * The burden to reconstruct the data is moved into user space. | 35 | * The burden to reconstruct the data is moved into user space. |
36 | * | ||
37 | * 2. 203 byte report descriptor | ||
38 | * Report #4 has an array field with logical range 0..18 instead of 1..15. | ||
39 | * | ||
40 | * 3. 135 byte report descriptor | ||
41 | * Report #4 has an array field with logical range 0..17 instead of 1..14. | ||
33 | */ | 42 | */ |
34 | static void samsung_report_fixup(struct hid_device *hdev, __u8 *rdesc, | 43 | static void samsung_report_fixup(struct hid_device *hdev, __u8 *rdesc, |
35 | unsigned int rsize) | 44 | unsigned int rsize) |
36 | { | 45 | { |
37 | if (rsize >= 182 && rdesc[175] == 0x25 && rdesc[176] == 0x40 && | 46 | if (rsize == 184 && rdesc[175] == 0x25 && rdesc[176] == 0x40 && |
38 | rdesc[177] == 0x75 && rdesc[178] == 0x30 && | 47 | rdesc[177] == 0x75 && rdesc[178] == 0x30 && |
39 | rdesc[179] == 0x95 && rdesc[180] == 0x01 && | 48 | rdesc[179] == 0x95 && rdesc[180] == 0x01 && |
40 | rdesc[182] == 0x40) { | 49 | rdesc[182] == 0x40) { |
41 | dev_info(&hdev->dev, "fixing up Samsung IrDA report " | 50 | dev_info(&hdev->dev, "fixing up Samsung IrDA %d byte report " |
42 | "descriptor\n"); | 51 | "descriptor\n", 184); |
43 | rdesc[176] = 0xff; | 52 | rdesc[176] = 0xff; |
44 | rdesc[178] = 0x08; | 53 | rdesc[178] = 0x08; |
45 | rdesc[180] = 0x06; | 54 | rdesc[180] = 0x06; |
46 | rdesc[182] = 0x42; | 55 | rdesc[182] = 0x42; |
56 | } else | ||
57 | if (rsize == 203 && rdesc[192] == 0x15 && rdesc[193] == 0x0 && | ||
58 | rdesc[194] == 0x25 && rdesc[195] == 0x12) { | ||
59 | dev_info(&hdev->dev, "fixing up Samsung IrDA %d byte report " | ||
60 | "descriptor\n", 203); | ||
61 | rdesc[193] = 0x1; | ||
62 | rdesc[195] = 0xf; | ||
63 | } else | ||
64 | if (rsize == 135 && rdesc[124] == 0x15 && rdesc[125] == 0x0 && | ||
65 | rdesc[126] == 0x25 && rdesc[127] == 0x11) { | ||
66 | dev_info(&hdev->dev, "fixing up Samsung IrDA %d byte report " | ||
67 | "descriptor\n", 135); | ||
68 | rdesc[125] = 0x1; | ||
69 | rdesc[127] = 0xe; | ||
47 | } | 70 | } |
48 | } | 71 | } |
49 | 72 | ||
@@ -51,6 +74,7 @@ static int samsung_probe(struct hid_device *hdev, | |||
51 | const struct hid_device_id *id) | 74 | const struct hid_device_id *id) |
52 | { | 75 | { |
53 | int ret; | 76 | int ret; |
77 | unsigned int cmask = HID_CONNECT_DEFAULT; | ||
54 | 78 | ||
55 | ret = hid_parse(hdev); | 79 | ret = hid_parse(hdev); |
56 | if (ret) { | 80 | if (ret) { |
@@ -58,8 +82,13 @@ static int samsung_probe(struct hid_device *hdev, | |||
58 | goto err_free; | 82 | goto err_free; |
59 | } | 83 | } |
60 | 84 | ||
61 | ret = hid_hw_start(hdev, (HID_CONNECT_DEFAULT & ~HID_CONNECT_HIDINPUT) | | 85 | if (hdev->rsize == 184) { |
62 | HID_CONNECT_HIDDEV_FORCE); | 86 | /* disable hidinput, force hiddev */ |
87 | cmask = (cmask & ~HID_CONNECT_HIDINPUT) | | ||
88 | HID_CONNECT_HIDDEV_FORCE; | ||
89 | } | ||
90 | |||
91 | ret = hid_hw_start(hdev, cmask); | ||
63 | if (ret) { | 92 | if (ret) { |
64 | dev_err(&hdev->dev, "hw start failed\n"); | 93 | dev_err(&hdev->dev, "hw start failed\n"); |
65 | goto err_free; | 94 | goto err_free; |