Blame view

drivers/hid/hid-cypress.c 3.85 KB
0f2213208   Jiri Slaby   HID: move cypress...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
  /*
   *  HID driver for some cypress "special" devices
   *
   *  Copyright (c) 1999 Andreas Gal
   *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
   *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
   *  Copyright (c) 2006-2007 Jiri Kosina
   *  Copyright (c) 2007 Paul Walmsley
   *  Copyright (c) 2008 Jiri Slaby
   */
  
  /*
   * This program is free software; you can redistribute it and/or modify it
   * under the terms of the GNU General Public License as published by the Free
   * Software Foundation; either version 2 of the License, or (at your option)
   * any later version.
   */
  
  #include <linux/device.h>
  #include <linux/hid.h>
  #include <linux/input.h>
  #include <linux/module.h>
  
  #include "hid-ids.h"
  
  #define CP_RDESC_SWAPPED_MIN_MAX	0x01
  #define CP_2WHEEL_MOUSE_HACK		0x02
  #define CP_2WHEEL_MOUSE_HACK_ON		0x04
  
  /*
   * Some USB barcode readers from cypress have usage min and usage max in
   * the wrong order
   */
73e4008dd   Nikolai Kondrashov   HID: allow resizi...
34
35
  static __u8 *cp_report_fixup(struct hid_device *hdev, __u8 *rdesc,
  		unsigned int *rsize)
0f2213208   Jiri Slaby   HID: move cypress...
36
37
38
39
40
  {
  	unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
  	unsigned int i;
  
  	if (!(quirks & CP_RDESC_SWAPPED_MIN_MAX))
73e4008dd   Nikolai Kondrashov   HID: allow resizi...
41
  		return rdesc;
0f2213208   Jiri Slaby   HID: move cypress...
42

73e4008dd   Nikolai Kondrashov   HID: allow resizi...
43
  	for (i = 0; i < *rsize - 4; i++)
0f2213208   Jiri Slaby   HID: move cypress...
44
45
46
47
48
49
50
51
52
  		if (rdesc[i] == 0x29 && rdesc[i + 2] == 0x19) {
  			__u8 tmp;
  
  			rdesc[i] = 0x19;
  			rdesc[i + 2] = 0x29;
  			tmp = rdesc[i + 3];
  			rdesc[i + 3] = rdesc[i + 1];
  			rdesc[i + 1] = tmp;
  		}
73e4008dd   Nikolai Kondrashov   HID: allow resizi...
53
  	return rdesc;
0f2213208   Jiri Slaby   HID: move cypress...
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
  }
  
  static int cp_input_mapped(struct hid_device *hdev, struct hid_input *hi,
  		struct hid_field *field, struct hid_usage *usage,
  		unsigned long **bit, int *max)
  {
  	unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
  
  	if (!(quirks & CP_2WHEEL_MOUSE_HACK))
  		return 0;
  
  	if (usage->type == EV_REL && usage->code == REL_WHEEL)
  		set_bit(REL_HWHEEL, *bit);
  	if (usage->hid == 0x00090005)
  		return -1;
  
  	return 0;
  }
  
  static int cp_event(struct hid_device *hdev, struct hid_field *field,
  		struct hid_usage *usage, __s32 value)
  {
  	unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
  
  	if (!(hdev->claimed & HID_CLAIMED_INPUT) || !field->hidinput ||
  			!usage->type || !(quirks & CP_2WHEEL_MOUSE_HACK))
  		return 0;
  
  	if (usage->hid == 0x00090005) {
  		if (value)
  			quirks |=  CP_2WHEEL_MOUSE_HACK_ON;
  		else
  			quirks &= ~CP_2WHEEL_MOUSE_HACK_ON;
  		hid_set_drvdata(hdev, (void *)quirks);
  		return 1;
  	}
  
  	if (usage->code == REL_WHEEL && (quirks & CP_2WHEEL_MOUSE_HACK_ON)) {
  		struct input_dev *input = field->hidinput->input;
  
  		input_event(input, usage->type, REL_HWHEEL, value);
  		return 1;
  	}
  
  	return 0;
  }
  
  static int cp_probe(struct hid_device *hdev, const struct hid_device_id *id)
  {
  	unsigned long quirks = id->driver_data;
  	int ret;
  
  	hid_set_drvdata(hdev, (void *)quirks);
  
  	ret = hid_parse(hdev);
  	if (ret) {
4291ee305   Joe Perches   HID: Add and use ...
110
111
  		hid_err(hdev, "parse failed
  ");
0f2213208   Jiri Slaby   HID: move cypress...
112
113
  		goto err_free;
  	}
93c10132a   Jiri Slaby   HID: move connect...
114
  	ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
0f2213208   Jiri Slaby   HID: move cypress...
115
  	if (ret) {
4291ee305   Joe Perches   HID: Add and use ...
116
117
  		hid_err(hdev, "hw start failed
  ");
0f2213208   Jiri Slaby   HID: move cypress...
118
119
120
121
122
123
124
125
126
127
128
129
130
  		goto err_free;
  	}
  
  	return 0;
  err_free:
  	return ret;
  }
  
  static const struct hid_device_id cp_devices[] = {
  	{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1),
  		.driver_data = CP_RDESC_SWAPPED_MIN_MAX },
  	{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2),
  		.driver_data = CP_RDESC_SWAPPED_MIN_MAX },
e8d0eab4d   Jiri Kosina   HID: add support ...
131
132
  	{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_3),
  		.driver_data = CP_RDESC_SWAPPED_MIN_MAX },
0f2213208   Jiri Slaby   HID: move cypress...
133
134
135
136
137
138
139
140
141
142
143
144
145
146
  	{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE),
  		.driver_data = CP_2WHEEL_MOUSE_HACK },
  	{ }
  };
  MODULE_DEVICE_TABLE(hid, cp_devices);
  
  static struct hid_driver cp_driver = {
  	.name = "cypress",
  	.id_table = cp_devices,
  	.report_fixup = cp_report_fixup,
  	.input_mapped = cp_input_mapped,
  	.event = cp_event,
  	.probe = cp_probe,
  };
a24f423bd   Peter Huewe   HID: adding __ini...
147
  static int __init cp_init(void)
0f2213208   Jiri Slaby   HID: move cypress...
148
149
150
  {
  	return hid_register_driver(&cp_driver);
  }
a24f423bd   Peter Huewe   HID: adding __ini...
151
  static void __exit cp_exit(void)
0f2213208   Jiri Slaby   HID: move cypress...
152
153
154
155
156
157
158
  {
  	hid_unregister_driver(&cp_driver);
  }
  
  module_init(cp_init);
  module_exit(cp_exit);
  MODULE_LICENSE("GPL");