aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hid/hid-input.c
diff options
context:
space:
mode:
authorNikolai Kondrashov <spbnick@gmail.com>2010-09-15 06:51:14 -0400
committerJiri Kosina <jkosina@suse.cz>2010-10-15 10:40:29 -0400
commit4ea6e4ffb4acdaaf9ba7687dbd84ae36e26cef9e (patch)
tree9636ec55c7f58ea5140daf40159f383faf7a81f8 /drivers/hid/hid-input.c
parentb6dc79929fa18a97bbc08400db72405ad835622f (diff)
HID: add absolute axis resolution calculation
Add absolute axis resolution calculation to the core HID layer, according to HID specification v1.11 6.2.2.7 Global Items. Only exponent 1 length units for X/Y/Z/RX/RY/RZ axis are supported for now. Signed-off-by: Nikolai Kondrashov <spbnick@gmail.com> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'drivers/hid/hid-input.c')
-rw-r--r--drivers/hid/hid-input.c80
1 files changed, 80 insertions, 0 deletions
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index 6c03dcc5760a..8e733b6eae27 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -149,6 +149,83 @@ static int hidinput_setkeycode(struct input_dev *dev,
149} 149}
150 150
151 151
152/**
153 * hidinput_calc_abs_res - calculate an absolute axis resolution
154 * @field: the HID report field to calculate resolution for
155 * @code: axis code
156 *
157 * The formula is:
158 * (logical_maximum - logical_minimum)
159 * resolution = ----------------------------------------------------------
160 * (physical_maximum - physical_minimum) * 10 ^ unit_exponent
161 *
162 * as seen in the HID specification v1.11 6.2.2.7 Global Items.
163 *
164 * Only exponent 1 length units are processed. Centimeters are converted to
165 * inches. Degrees are converted to radians.
166 */
167static __s32 hidinput_calc_abs_res(const struct hid_field *field, __u16 code)
168{
169 __s32 unit_exponent = field->unit_exponent;
170 __s32 logical_extents = field->logical_maximum -
171 field->logical_minimum;
172 __s32 physical_extents = field->physical_maximum -
173 field->physical_minimum;
174 __s32 prev;
175
176 /* Check if the extents are sane */
177 if (logical_extents <= 0 || physical_extents <= 0)
178 return 0;
179
180 /*
181 * Verify and convert units.
182 * See HID specification v1.11 6.2.2.7 Global Items for unit decoding
183 */
184 if (code == ABS_X || code == ABS_Y || code == ABS_Z) {
185 if (field->unit == 0x11) { /* If centimeters */
186 /* Convert to inches */
187 prev = logical_extents;
188 logical_extents *= 254;
189 if (logical_extents < prev)
190 return 0;
191 unit_exponent += 2;
192 } else if (field->unit != 0x13) { /* If not inches */
193 return 0;
194 }
195 } else if (code == ABS_RX || code == ABS_RY || code == ABS_RZ) {
196 if (field->unit == 0x14) { /* If degrees */
197 /* Convert to radians */
198 prev = logical_extents;
199 logical_extents *= 573;
200 if (logical_extents < prev)
201 return 0;
202 unit_exponent += 1;
203 } else if (field->unit != 0x12) { /* If not radians */
204 return 0;
205 }
206 } else {
207 return 0;
208 }
209
210 /* Apply negative unit exponent */
211 for (; unit_exponent < 0; unit_exponent++) {
212 prev = logical_extents;
213 logical_extents *= 10;
214 if (logical_extents < prev)
215 return 0;
216 }
217 /* Apply positive unit exponent */
218 for (; unit_exponent > 0; unit_exponent--) {
219 prev = physical_extents;
220 physical_extents *= 10;
221 if (physical_extents < prev)
222 return 0;
223 }
224
225 /* Calculate resolution */
226 return logical_extents / physical_extents;
227}
228
152static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_field *field, 229static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_field *field,
153 struct hid_usage *usage) 230 struct hid_usage *usage)
154{ 231{
@@ -537,6 +614,9 @@ mapped:
537 input_set_abs_params(input, usage->code, a, b, (b - a) >> 8, (b - a) >> 4); 614 input_set_abs_params(input, usage->code, a, b, (b - a) >> 8, (b - a) >> 4);
538 else input_set_abs_params(input, usage->code, a, b, 0, 0); 615 else input_set_abs_params(input, usage->code, a, b, 0, 0);
539 616
617 input_abs_set_res(input, usage->code,
618 hidinput_calc_abs_res(field, usage->code));
619
540 /* use a larger default input buffer for MT devices */ 620 /* use a larger default input buffer for MT devices */
541 if (usage->code == ABS_MT_POSITION_X && input->hint_events_per_packet == 0) 621 if (usage->code == ABS_MT_POSITION_X && input->hint_events_per_packet == 0)
542 input_set_events_per_packet(input, 60); 622 input_set_events_per_packet(input, 60);