aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hid/hid-lg4ff.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/hid/hid-lg4ff.c')
-rw-r--r--drivers/hid/hid-lg4ff.c198
1 files changed, 138 insertions, 60 deletions
diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c
index f3390ee6105c..d7947c701f30 100644
--- a/drivers/hid/hid-lg4ff.c
+++ b/drivers/hid/hid-lg4ff.c
@@ -43,6 +43,11 @@
43#define G27_REV_MAJ 0x12 43#define G27_REV_MAJ 0x12
44#define G27_REV_MIN 0x38 44#define G27_REV_MIN 0x38
45 45
46#define DFP_X_MIN 0
47#define DFP_X_MAX 16383
48#define DFP_PEDAL_MIN 0
49#define DFP_PEDAL_MAX 255
50
46#define to_hid_device(pdev) container_of(pdev, struct hid_device, dev) 51#define to_hid_device(pdev) container_of(pdev, struct hid_device, dev)
47 52
48static void hid_lg4ff_set_range_dfp(struct hid_device *hid, u16 range); 53static void hid_lg4ff_set_range_dfp(struct hid_device *hid, u16 range);
@@ -53,6 +58,7 @@ static ssize_t lg4ff_range_store(struct device *dev, struct device_attribute *at
53static DEVICE_ATTR(range, S_IRWXU | S_IRWXG | S_IRWXO, lg4ff_range_show, lg4ff_range_store); 58static DEVICE_ATTR(range, S_IRWXU | S_IRWXG | S_IRWXO, lg4ff_range_show, lg4ff_range_store);
54 59
55struct lg4ff_device_entry { 60struct lg4ff_device_entry {
61 __u32 product_id;
56 __u16 range; 62 __u16 range;
57 __u16 min_range; 63 __u16 min_range;
58 __u16 max_range; 64 __u16 max_range;
@@ -129,26 +135,77 @@ static const struct lg4ff_usb_revision lg4ff_revs[] = {
129 {G27_REV_MAJ, G27_REV_MIN, &native_g27}, /* G27 */ 135 {G27_REV_MAJ, G27_REV_MIN, &native_g27}, /* G27 */
130}; 136};
131 137
138/* Recalculates X axis value accordingly to currently selected range */
139static __s32 lg4ff_adjust_dfp_x_axis(__s32 value, __u16 range)
140{
141 __u16 max_range;
142 __s32 new_value;
143
144 if (range == 900)
145 return value;
146 else if (range == 200)
147 return value;
148 else if (range < 200)
149 max_range = 200;
150 else
151 max_range = 900;
152
153 new_value = 8192 + mult_frac(value - 8192, max_range, range);
154 if (new_value < 0)
155 return 0;
156 else if (new_value > 16383)
157 return 16383;
158 else
159 return new_value;
160}
161
162int lg4ff_adjust_input_event(struct hid_device *hid, struct hid_field *field,
163 struct hid_usage *usage, __s32 value, struct lg_drv_data *drv_data)
164{
165 struct lg4ff_device_entry *entry = drv_data->device_props;
166 __s32 new_value = 0;
167
168 if (!entry) {
169 hid_err(hid, "Device properties not found");
170 return 0;
171 }
172
173 switch (entry->product_id) {
174 case USB_DEVICE_ID_LOGITECH_DFP_WHEEL:
175 switch (usage->code) {
176 case ABS_X:
177 new_value = lg4ff_adjust_dfp_x_axis(value, entry->range);
178 input_event(field->hidinput->input, usage->type, usage->code, new_value);
179 return 1;
180 default:
181 return 0;
182 }
183 default:
184 return 0;
185 }
186}
187
132static int hid_lg4ff_play(struct input_dev *dev, void *data, struct ff_effect *effect) 188static int hid_lg4ff_play(struct input_dev *dev, void *data, struct ff_effect *effect)
133{ 189{
134 struct hid_device *hid = input_get_drvdata(dev); 190 struct hid_device *hid = input_get_drvdata(dev);
135 struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; 191 struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
136 struct hid_report *report = list_entry(report_list->next, struct hid_report, list); 192 struct hid_report *report = list_entry(report_list->next, struct hid_report, list);
193 __s32 *value = report->field[0]->value;
137 int x; 194 int x;
138 195
139#define CLAMP(x) if (x < 0) x = 0; if (x > 0xff) x = 0xff 196#define CLAMP(x) do { if (x < 0) x = 0; else if (x > 0xff) x = 0xff; } while (0)
140 197
141 switch (effect->type) { 198 switch (effect->type) {
142 case FF_CONSTANT: 199 case FF_CONSTANT:
143 x = effect->u.ramp.start_level + 0x80; /* 0x80 is no force */ 200 x = effect->u.ramp.start_level + 0x80; /* 0x80 is no force */
144 CLAMP(x); 201 CLAMP(x);
145 report->field[0]->value[0] = 0x11; /* Slot 1 */ 202 value[0] = 0x11; /* Slot 1 */
146 report->field[0]->value[1] = 0x08; 203 value[1] = 0x08;
147 report->field[0]->value[2] = x; 204 value[2] = x;
148 report->field[0]->value[3] = 0x80; 205 value[3] = 0x80;
149 report->field[0]->value[4] = 0x00; 206 value[4] = 0x00;
150 report->field[0]->value[5] = 0x00; 207 value[5] = 0x00;
151 report->field[0]->value[6] = 0x00; 208 value[6] = 0x00;
152 209
153 usbhid_submit_report(hid, report, USB_DIR_OUT); 210 usbhid_submit_report(hid, report, USB_DIR_OUT);
154 break; 211 break;
@@ -163,14 +220,15 @@ static void hid_lg4ff_set_autocenter_default(struct input_dev *dev, u16 magnitud
163 struct hid_device *hid = input_get_drvdata(dev); 220 struct hid_device *hid = input_get_drvdata(dev);
164 struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; 221 struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
165 struct hid_report *report = list_entry(report_list->next, struct hid_report, list); 222 struct hid_report *report = list_entry(report_list->next, struct hid_report, list);
223 __s32 *value = report->field[0]->value;
166 224
167 report->field[0]->value[0] = 0xfe; 225 value[0] = 0xfe;
168 report->field[0]->value[1] = 0x0d; 226 value[1] = 0x0d;
169 report->field[0]->value[2] = magnitude >> 13; 227 value[2] = magnitude >> 13;
170 report->field[0]->value[3] = magnitude >> 13; 228 value[3] = magnitude >> 13;
171 report->field[0]->value[4] = magnitude >> 8; 229 value[4] = magnitude >> 8;
172 report->field[0]->value[5] = 0x00; 230 value[5] = 0x00;
173 report->field[0]->value[6] = 0x00; 231 value[6] = 0x00;
174 232
175 usbhid_submit_report(hid, report, USB_DIR_OUT); 233 usbhid_submit_report(hid, report, USB_DIR_OUT);
176} 234}
@@ -181,16 +239,16 @@ static void hid_lg4ff_set_autocenter_ffex(struct input_dev *dev, u16 magnitude)
181 struct hid_device *hid = input_get_drvdata(dev); 239 struct hid_device *hid = input_get_drvdata(dev);
182 struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; 240 struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
183 struct hid_report *report = list_entry(report_list->next, struct hid_report, list); 241 struct hid_report *report = list_entry(report_list->next, struct hid_report, list);
242 __s32 *value = report->field[0]->value;
184 magnitude = magnitude * 90 / 65535; 243 magnitude = magnitude * 90 / 65535;
185
186 244
187 report->field[0]->value[0] = 0xfe; 245 value[0] = 0xfe;
188 report->field[0]->value[1] = 0x03; 246 value[1] = 0x03;
189 report->field[0]->value[2] = magnitude >> 14; 247 value[2] = magnitude >> 14;
190 report->field[0]->value[3] = magnitude >> 14; 248 value[3] = magnitude >> 14;
191 report->field[0]->value[4] = magnitude; 249 value[4] = magnitude;
192 report->field[0]->value[5] = 0x00; 250 value[5] = 0x00;
193 report->field[0]->value[6] = 0x00; 251 value[6] = 0x00;
194 252
195 usbhid_submit_report(hid, report, USB_DIR_OUT); 253 usbhid_submit_report(hid, report, USB_DIR_OUT);
196} 254}
@@ -200,15 +258,17 @@ static void hid_lg4ff_set_range_g25(struct hid_device *hid, u16 range)
200{ 258{
201 struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; 259 struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
202 struct hid_report *report = list_entry(report_list->next, struct hid_report, list); 260 struct hid_report *report = list_entry(report_list->next, struct hid_report, list);
261 __s32 *value = report->field[0]->value;
262
203 dbg_hid("G25/G27/DFGT: setting range to %u\n", range); 263 dbg_hid("G25/G27/DFGT: setting range to %u\n", range);
204 264
205 report->field[0]->value[0] = 0xf8; 265 value[0] = 0xf8;
206 report->field[0]->value[1] = 0x81; 266 value[1] = 0x81;
207 report->field[0]->value[2] = range & 0x00ff; 267 value[2] = range & 0x00ff;
208 report->field[0]->value[3] = (range & 0xff00) >> 8; 268 value[3] = (range & 0xff00) >> 8;
209 report->field[0]->value[4] = 0x00; 269 value[4] = 0x00;
210 report->field[0]->value[5] = 0x00; 270 value[5] = 0x00;
211 report->field[0]->value[6] = 0x00; 271 value[6] = 0x00;
212 272
213 usbhid_submit_report(hid, report, USB_DIR_OUT); 273 usbhid_submit_report(hid, report, USB_DIR_OUT);
214} 274}
@@ -219,16 +279,18 @@ static void hid_lg4ff_set_range_dfp(struct hid_device *hid, __u16 range)
219 struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; 279 struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
220 struct hid_report *report = list_entry(report_list->next, struct hid_report, list); 280 struct hid_report *report = list_entry(report_list->next, struct hid_report, list);
221 int start_left, start_right, full_range; 281 int start_left, start_right, full_range;
282 __s32 *value = report->field[0]->value;
283
222 dbg_hid("Driving Force Pro: setting range to %u\n", range); 284 dbg_hid("Driving Force Pro: setting range to %u\n", range);
223 285
224 /* Prepare "coarse" limit command */ 286 /* Prepare "coarse" limit command */
225 report->field[0]->value[0] = 0xf8; 287 value[0] = 0xf8;
226 report->field[0]->value[1] = 0x00; /* Set later */ 288 value[1] = 0x00; /* Set later */
227 report->field[0]->value[2] = 0x00; 289 value[2] = 0x00;
228 report->field[0]->value[3] = 0x00; 290 value[3] = 0x00;
229 report->field[0]->value[4] = 0x00; 291 value[4] = 0x00;
230 report->field[0]->value[5] = 0x00; 292 value[5] = 0x00;
231 report->field[0]->value[6] = 0x00; 293 value[6] = 0x00;
232 294
233 if (range > 200) { 295 if (range > 200) {
234 report->field[0]->value[1] = 0x03; 296 report->field[0]->value[1] = 0x03;
@@ -240,13 +302,13 @@ static void hid_lg4ff_set_range_dfp(struct hid_device *hid, __u16 range)
240 usbhid_submit_report(hid, report, USB_DIR_OUT); 302 usbhid_submit_report(hid, report, USB_DIR_OUT);
241 303
242 /* Prepare "fine" limit command */ 304 /* Prepare "fine" limit command */
243 report->field[0]->value[0] = 0x81; 305 value[0] = 0x81;
244 report->field[0]->value[1] = 0x0b; 306 value[1] = 0x0b;
245 report->field[0]->value[2] = 0x00; 307 value[2] = 0x00;
246 report->field[0]->value[3] = 0x00; 308 value[3] = 0x00;
247 report->field[0]->value[4] = 0x00; 309 value[4] = 0x00;
248 report->field[0]->value[5] = 0x00; 310 value[5] = 0x00;
249 report->field[0]->value[6] = 0x00; 311 value[6] = 0x00;
250 312
251 if (range == 200 || range == 900) { /* Do not apply any fine limit */ 313 if (range == 200 || range == 900) { /* Do not apply any fine limit */
252 usbhid_submit_report(hid, report, USB_DIR_OUT); 314 usbhid_submit_report(hid, report, USB_DIR_OUT);
@@ -257,11 +319,11 @@ static void hid_lg4ff_set_range_dfp(struct hid_device *hid, __u16 range)
257 start_left = (((full_range - range + 1) * 2047) / full_range); 319 start_left = (((full_range - range + 1) * 2047) / full_range);
258 start_right = 0xfff - start_left; 320 start_right = 0xfff - start_left;
259 321
260 report->field[0]->value[2] = start_left >> 4; 322 value[2] = start_left >> 4;
261 report->field[0]->value[3] = start_right >> 4; 323 value[3] = start_right >> 4;
262 report->field[0]->value[4] = 0xff; 324 value[4] = 0xff;
263 report->field[0]->value[5] = (start_right & 0xe) << 4 | (start_left & 0xe); 325 value[5] = (start_right & 0xe) << 4 | (start_left & 0xe);
264 report->field[0]->value[6] = 0xff; 326 value[6] = 0xff;
265 327
266 usbhid_submit_report(hid, report, USB_DIR_OUT); 328 usbhid_submit_report(hid, report, USB_DIR_OUT);
267} 329}
@@ -344,14 +406,15 @@ static void lg4ff_set_leds(struct hid_device *hid, __u8 leds)
344{ 406{
345 struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; 407 struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
346 struct hid_report *report = list_entry(report_list->next, struct hid_report, list); 408 struct hid_report *report = list_entry(report_list->next, struct hid_report, list);
347 409 __s32 *value = report->field[0]->value;
348 report->field[0]->value[0] = 0xf8; 410
349 report->field[0]->value[1] = 0x12; 411 value[0] = 0xf8;
350 report->field[0]->value[2] = leds; 412 value[1] = 0x12;
351 report->field[0]->value[3] = 0x00; 413 value[2] = leds;
352 report->field[0]->value[4] = 0x00; 414 value[3] = 0x00;
353 report->field[0]->value[5] = 0x00; 415 value[4] = 0x00;
354 report->field[0]->value[6] = 0x00; 416 value[5] = 0x00;
417 value[6] = 0x00;
355 usbhid_submit_report(hid, report, USB_DIR_OUT); 418 usbhid_submit_report(hid, report, USB_DIR_OUT);
356} 419}
357 420
@@ -360,7 +423,7 @@ static void lg4ff_led_set_brightness(struct led_classdev *led_cdev,
360{ 423{
361 struct device *dev = led_cdev->dev->parent; 424 struct device *dev = led_cdev->dev->parent;
362 struct hid_device *hid = container_of(dev, struct hid_device, dev); 425 struct hid_device *hid = container_of(dev, struct hid_device, dev);
363 struct lg_drv_data *drv_data = (struct lg_drv_data *)hid_get_drvdata(hid); 426 struct lg_drv_data *drv_data = hid_get_drvdata(hid);
364 struct lg4ff_device_entry *entry; 427 struct lg4ff_device_entry *entry;
365 int i, state = 0; 428 int i, state = 0;
366 429
@@ -395,7 +458,7 @@ static enum led_brightness lg4ff_led_get_brightness(struct led_classdev *led_cde
395{ 458{
396 struct device *dev = led_cdev->dev->parent; 459 struct device *dev = led_cdev->dev->parent;
397 struct hid_device *hid = container_of(dev, struct hid_device, dev); 460 struct hid_device *hid = container_of(dev, struct hid_device, dev);
398 struct lg_drv_data *drv_data = (struct lg_drv_data *)hid_get_drvdata(hid); 461 struct lg_drv_data *drv_data = hid_get_drvdata(hid);
399 struct lg4ff_device_entry *entry; 462 struct lg4ff_device_entry *entry;
400 int i, value = 0; 463 int i, value = 0;
401 464
@@ -501,7 +564,7 @@ int lg4ff_init(struct hid_device *hid)
501 /* Check if autocentering is available and 564 /* Check if autocentering is available and
502 * set the centering force to zero by default */ 565 * set the centering force to zero by default */
503 if (test_bit(FF_AUTOCENTER, dev->ffbit)) { 566 if (test_bit(FF_AUTOCENTER, dev->ffbit)) {
504 if(rev_maj == FFEX_REV_MAJ && rev_min == FFEX_REV_MIN) /* Formula Force EX expects different autocentering command */ 567 if (rev_maj == FFEX_REV_MAJ && rev_min == FFEX_REV_MIN) /* Formula Force EX expects different autocentering command */
505 dev->ff->set_autocenter = hid_lg4ff_set_autocenter_ffex; 568 dev->ff->set_autocenter = hid_lg4ff_set_autocenter_ffex;
506 else 569 else
507 dev->ff->set_autocenter = hid_lg4ff_set_autocenter_default; 570 dev->ff->set_autocenter = hid_lg4ff_set_autocenter_default;
@@ -524,6 +587,7 @@ int lg4ff_init(struct hid_device *hid)
524 } 587 }
525 drv_data->device_props = entry; 588 drv_data->device_props = entry;
526 589
590 entry->product_id = lg4ff_devices[i].product_id;
527 entry->min_range = lg4ff_devices[i].min_range; 591 entry->min_range = lg4ff_devices[i].min_range;
528 entry->max_range = lg4ff_devices[i].max_range; 592 entry->max_range = lg4ff_devices[i].max_range;
529 entry->set_range = lg4ff_devices[i].set_range; 593 entry->set_range = lg4ff_devices[i].set_range;
@@ -534,6 +598,18 @@ int lg4ff_init(struct hid_device *hid)
534 return error; 598 return error;
535 dbg_hid("sysfs interface created\n"); 599 dbg_hid("sysfs interface created\n");
536 600
601 /* Set default axes parameters */
602 switch (lg4ff_devices[i].product_id) {
603 case USB_DEVICE_ID_LOGITECH_DFP_WHEEL:
604 dbg_hid("Setting axes parameters for Driving Force Pro\n");
605 input_set_abs_params(dev, ABS_X, DFP_X_MIN, DFP_X_MAX, 0, 0);
606 input_set_abs_params(dev, ABS_Y, DFP_PEDAL_MIN, DFP_PEDAL_MAX, 0, 0);
607 input_set_abs_params(dev, ABS_RZ, DFP_PEDAL_MIN, DFP_PEDAL_MAX, 0, 0);
608 break;
609 default:
610 break;
611 }
612
537 /* Set the maximum range to start with */ 613 /* Set the maximum range to start with */
538 entry->range = entry->max_range; 614 entry->range = entry->max_range;
539 if (entry->set_range != NULL) 615 if (entry->set_range != NULL)
@@ -594,6 +670,8 @@ out:
594 return 0; 670 return 0;
595} 671}
596 672
673
674
597int lg4ff_deinit(struct hid_device *hid) 675int lg4ff_deinit(struct hid_device *hid)
598{ 676{
599 struct lg4ff_device_entry *entry; 677 struct lg4ff_device_entry *entry;