Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.34-rc5 140 lines 3.8 kB view raw
1/* 2 * HID driver for some samsung "special" devices 3 * 4 * Copyright (c) 1999 Andreas Gal 5 * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz> 6 * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc 7 * Copyright (c) 2006-2007 Jiri Kosina 8 * Copyright (c) 2007 Paul Walmsley 9 * Copyright (c) 2008 Jiri Slaby 10 */ 11 12/* 13 * This program is free software; you can redistribute it and/or modify it 14 * under the terms of the GNU General Public License as published by the Free 15 * Software Foundation; either version 2 of the License, or (at your option) 16 * any later version. 17 */ 18 19#include <linux/device.h> 20#include <linux/hid.h> 21#include <linux/module.h> 22 23#include "hid-ids.h" 24 25/* 26 * Samsung IrDA remote controller (reports as Cypress USB Mouse). 27 * 28 * There are several variants for 0419:0001: 29 * 30 * 1. 184 byte report descriptor 31 * Vendor specific report #4 has a size of 48 bit, 32 * and therefore is not accepted when inspecting the descriptors. 33 * As a workaround we reinterpret the report as: 34 * Variable type, count 6, size 8 bit, log. maximum 255 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. 42 * 43 * 4. 171 byte report descriptor 44 * Report #3 has an array field with logical range 0..1 instead of 1..3. 45 */ 46static inline void samsung_dev_trace(struct hid_device *hdev, 47 unsigned int rsize) 48{ 49 dev_info(&hdev->dev, "fixing up Samsung IrDA %d byte report " 50 "descriptor\n", rsize); 51} 52 53static void samsung_report_fixup(struct hid_device *hdev, __u8 *rdesc, 54 unsigned int rsize) 55{ 56 if (rsize == 184 && rdesc[175] == 0x25 && rdesc[176] == 0x40 && 57 rdesc[177] == 0x75 && rdesc[178] == 0x30 && 58 rdesc[179] == 0x95 && rdesc[180] == 0x01 && 59 rdesc[182] == 0x40) { 60 samsung_dev_trace(hdev, 184); 61 rdesc[176] = 0xff; 62 rdesc[178] = 0x08; 63 rdesc[180] = 0x06; 64 rdesc[182] = 0x42; 65 } else 66 if (rsize == 203 && rdesc[192] == 0x15 && rdesc[193] == 0x0 && 67 rdesc[194] == 0x25 && rdesc[195] == 0x12) { 68 samsung_dev_trace(hdev, 203); 69 rdesc[193] = 0x1; 70 rdesc[195] = 0xf; 71 } else 72 if (rsize == 135 && rdesc[124] == 0x15 && rdesc[125] == 0x0 && 73 rdesc[126] == 0x25 && rdesc[127] == 0x11) { 74 samsung_dev_trace(hdev, 135); 75 rdesc[125] = 0x1; 76 rdesc[127] = 0xe; 77 } else 78 if (rsize == 171 && rdesc[160] == 0x15 && rdesc[161] == 0x0 && 79 rdesc[162] == 0x25 && rdesc[163] == 0x01) { 80 samsung_dev_trace(hdev, 171); 81 rdesc[161] = 0x1; 82 rdesc[163] = 0x3; 83 } 84} 85 86static int samsung_probe(struct hid_device *hdev, 87 const struct hid_device_id *id) 88{ 89 int ret; 90 unsigned int cmask = HID_CONNECT_DEFAULT; 91 92 ret = hid_parse(hdev); 93 if (ret) { 94 dev_err(&hdev->dev, "parse failed\n"); 95 goto err_free; 96 } 97 98 if (hdev->rsize == 184) { 99 /* disable hidinput, force hiddev */ 100 cmask = (cmask & ~HID_CONNECT_HIDINPUT) | 101 HID_CONNECT_HIDDEV_FORCE; 102 } 103 104 ret = hid_hw_start(hdev, cmask); 105 if (ret) { 106 dev_err(&hdev->dev, "hw start failed\n"); 107 goto err_free; 108 } 109 110 return 0; 111err_free: 112 return ret; 113} 114 115static const struct hid_device_id samsung_devices[] = { 116 { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) }, 117 { } 118}; 119MODULE_DEVICE_TABLE(hid, samsung_devices); 120 121static struct hid_driver samsung_driver = { 122 .name = "samsung", 123 .id_table = samsung_devices, 124 .report_fixup = samsung_report_fixup, 125 .probe = samsung_probe, 126}; 127 128static int __init samsung_init(void) 129{ 130 return hid_register_driver(&samsung_driver); 131} 132 133static void __exit samsung_exit(void) 134{ 135 hid_unregister_driver(&samsung_driver); 136} 137 138module_init(samsung_init); 139module_exit(samsung_exit); 140MODULE_LICENSE("GPL");