diff options
author | Arnd Bergmann <arnd@arndb.de> | 2012-10-04 22:57:00 +0200 |
---|---|---|
committer | Arnd Bergmann <arnd@arndb.de> | 2012-10-04 22:57:51 +0200 |
commit | c37d6154c0b9163c27e53cc1d0be3867b4abd760 (patch) | |
tree | 7a24522c56d1cb284dff1d3c225bbdaba0901bb5 /drivers/hid/hid-lg4ff.c | |
parent | e7a570ff7dff9af6e54ff5e580a61ec7652137a0 (diff) | |
parent | 8a1ab3155c2ac7fbe5f2038d6e26efeb607a1498 (diff) |
Merge branch 'disintegrate-asm-generic' of git://git.infradead.org/users/dhowells/linux-headers into asm-generic
Patches from David Howells <dhowells@redhat.com>:
This is to complete part of the UAPI disintegration for which the
preparatory patches were pulled recently.
Note that there are some fixup patches which are at the base of the
branch aimed at you, plus all arches get the asm-generic branch merged in too.
* 'disintegrate-asm-generic' of git://git.infradead.org/users/dhowells/linux-headers:
UAPI: (Scripted) Disintegrate include/asm-generic
UAPI: Fix conditional header installation handling (notably kvm_para.h on m68k)
c6x: remove c6x signal.h
UAPI: Split compound conditionals containing __KERNEL__ in Arm64
UAPI: Fix the guards on various asm/unistd.h files
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Diffstat (limited to 'drivers/hid/hid-lg4ff.c')
-rw-r--r-- | drivers/hid/hid-lg4ff.c | 198 |
1 files changed, 138 insertions, 60 deletions
diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c index f3390ee6105..d7947c701f3 100644 --- a/drivers/hid/hid-lg4ff.c +++ b/drivers/hid/hid-lg4ff.c @@ -43,6 +43,11 @@ #define G27_REV_MAJ 0x12 #define G27_REV_MIN 0x38 +#define DFP_X_MIN 0 +#define DFP_X_MAX 16383 +#define DFP_PEDAL_MIN 0 +#define DFP_PEDAL_MAX 255 + #define to_hid_device(pdev) container_of(pdev, struct hid_device, dev) static 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 static DEVICE_ATTR(range, S_IRWXU | S_IRWXG | S_IRWXO, lg4ff_range_show, lg4ff_range_store); struct lg4ff_device_entry { + __u32 product_id; __u16 range; __u16 min_range; __u16 max_range; @@ -129,26 +135,77 @@ static const struct lg4ff_usb_revision lg4ff_revs[] = { {G27_REV_MAJ, G27_REV_MIN, &native_g27}, /* G27 */ }; +/* Recalculates X axis value accordingly to currently selected range */ +static __s32 lg4ff_adjust_dfp_x_axis(__s32 value, __u16 range) +{ + __u16 max_range; + __s32 new_value; + + if (range == 900) + return value; + else if (range == 200) + return value; + else if (range < 200) + max_range = 200; + else + max_range = 900; + + new_value = 8192 + mult_frac(value - 8192, max_range, range); + if (new_value < 0) + return 0; + else if (new_value > 16383) + return 16383; + else + return new_value; +} + +int lg4ff_adjust_input_event(struct hid_device *hid, struct hid_field *field, + struct hid_usage *usage, __s32 value, struct lg_drv_data *drv_data) +{ + struct lg4ff_device_entry *entry = drv_data->device_props; + __s32 new_value = 0; + + if (!entry) { + hid_err(hid, "Device properties not found"); + return 0; + } + + switch (entry->product_id) { + case USB_DEVICE_ID_LOGITECH_DFP_WHEEL: + switch (usage->code) { + case ABS_X: + new_value = lg4ff_adjust_dfp_x_axis(value, entry->range); + input_event(field->hidinput->input, usage->type, usage->code, new_value); + return 1; + default: + return 0; + } + default: + return 0; + } +} + static int hid_lg4ff_play(struct input_dev *dev, void *data, struct ff_effect *effect) { struct hid_device *hid = input_get_drvdata(dev); struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; struct hid_report *report = list_entry(report_list->next, struct hid_report, list); + __s32 *value = report->field[0]->value; int x; -#define CLAMP(x) if (x < 0) x = 0; if (x > 0xff) x = 0xff +#define CLAMP(x) do { if (x < 0) x = 0; else if (x > 0xff) x = 0xff; } while (0) switch (effect->type) { case FF_CONSTANT: x = effect->u.ramp.start_level + 0x80; /* 0x80 is no force */ CLAMP(x); - report->field[0]->value[0] = 0x11; /* Slot 1 */ - report->field[0]->value[1] = 0x08; - report->field[0]->value[2] = x; - report->field[0]->value[3] = 0x80; - report->field[0]->value[4] = 0x00; - report->field[0]->value[5] = 0x00; - report->field[0]->value[6] = 0x00; + value[0] = 0x11; /* Slot 1 */ + value[1] = 0x08; + value[2] = x; + value[3] = 0x80; + value[4] = 0x00; + value[5] = 0x00; + value[6] = 0x00; usbhid_submit_report(hid, report, USB_DIR_OUT); break; @@ -163,14 +220,15 @@ static void hid_lg4ff_set_autocenter_default(struct input_dev *dev, u16 magnitud struct hid_device *hid = input_get_drvdata(dev); struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; struct hid_report *report = list_entry(report_list->next, struct hid_report, list); + __s32 *value = report->field[0]->value; - report->field[0]->value[0] = 0xfe; - report->field[0]->value[1] = 0x0d; - report->field[0]->value[2] = magnitude >> 13; - report->field[0]->value[3] = magnitude >> 13; - report->field[0]->value[4] = magnitude >> 8; - report->field[0]->value[5] = 0x00; - report->field[0]->value[6] = 0x00; + value[0] = 0xfe; + value[1] = 0x0d; + value[2] = magnitude >> 13; + value[3] = magnitude >> 13; + value[4] = magnitude >> 8; + value[5] = 0x00; + value[6] = 0x00; usbhid_submit_report(hid, report, USB_DIR_OUT); } @@ -181,16 +239,16 @@ static void hid_lg4ff_set_autocenter_ffex(struct input_dev *dev, u16 magnitude) struct hid_device *hid = input_get_drvdata(dev); struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; struct hid_report *report = list_entry(report_list->next, struct hid_report, list); + __s32 *value = report->field[0]->value; magnitude = magnitude * 90 / 65535; - - report->field[0]->value[0] = 0xfe; - report->field[0]->value[1] = 0x03; - report->field[0]->value[2] = magnitude >> 14; - report->field[0]->value[3] = magnitude >> 14; - report->field[0]->value[4] = magnitude; - report->field[0]->value[5] = 0x00; - report->field[0]->value[6] = 0x00; + value[0] = 0xfe; + value[1] = 0x03; + value[2] = magnitude >> 14; + value[3] = magnitude >> 14; + value[4] = magnitude; + value[5] = 0x00; + value[6] = 0x00; usbhid_submit_report(hid, report, USB_DIR_OUT); } @@ -200,15 +258,17 @@ static void hid_lg4ff_set_range_g25(struct hid_device *hid, u16 range) { struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; struct hid_report *report = list_entry(report_list->next, struct hid_report, list); + __s32 *value = report->field[0]->value; + dbg_hid("G25/G27/DFGT: setting range to %u\n", range); - report->field[0]->value[0] = 0xf8; - report->field[0]->value[1] = 0x81; - report->field[0]->value[2] = range & 0x00ff; - report->field[0]->value[3] = (range & 0xff00) >> 8; - report->field[0]->value[4] = 0x00; - report->field[0]->value[5] = 0x00; - report->field[0]->value[6] = 0x00; + value[0] = 0xf8; + value[1] = 0x81; + value[2] = range & 0x00ff; + value[3] = (range & 0xff00) >> 8; + value[4] = 0x00; + value[5] = 0x00; + value[6] = 0x00; usbhid_submit_report(hid, report, USB_DIR_OUT); } @@ -219,16 +279,18 @@ static void hid_lg4ff_set_range_dfp(struct hid_device *hid, __u16 range) struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; struct hid_report *report = list_entry(report_list->next, struct hid_report, list); int start_left, start_right, full_range; + __s32 *value = report->field[0]->value; + dbg_hid("Driving Force Pro: setting range to %u\n", range); /* Prepare "coarse" limit command */ - report->field[0]->value[0] = 0xf8; - report->field[0]->value[1] = 0x00; /* Set later */ - report->field[0]->value[2] = 0x00; - report->field[0]->value[3] = 0x00; - report->field[0]->value[4] = 0x00; - report->field[0]->value[5] = 0x00; - report->field[0]->value[6] = 0x00; + value[0] = 0xf8; + value[1] = 0x00; /* Set later */ + value[2] = 0x00; + value[3] = 0x00; + value[4] = 0x00; + value[5] = 0x00; + value[6] = 0x00; if (range > 200) { report->field[0]->value[1] = 0x03; @@ -240,13 +302,13 @@ static void hid_lg4ff_set_range_dfp(struct hid_device *hid, __u16 range) usbhid_submit_report(hid, report, USB_DIR_OUT); /* Prepare "fine" limit command */ - report->field[0]->value[0] = 0x81; - report->field[0]->value[1] = 0x0b; - report->field[0]->value[2] = 0x00; - report->field[0]->value[3] = 0x00; - report->field[0]->value[4] = 0x00; - report->field[0]->value[5] = 0x00; - report->field[0]->value[6] = 0x00; + value[0] = 0x81; + value[1] = 0x0b; + value[2] = 0x00; + value[3] = 0x00; + value[4] = 0x00; + value[5] = 0x00; + value[6] = 0x00; if (range == 200 || range == 900) { /* Do not apply any fine limit */ 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) start_left = (((full_range - range + 1) * 2047) / full_range); start_right = 0xfff - start_left; - report->field[0]->value[2] = start_left >> 4; - report->field[0]->value[3] = start_right >> 4; - report->field[0]->value[4] = 0xff; - report->field[0]->value[5] = (start_right & 0xe) << 4 | (start_left & 0xe); - report->field[0]->value[6] = 0xff; + value[2] = start_left >> 4; + value[3] = start_right >> 4; + value[4] = 0xff; + value[5] = (start_right & 0xe) << 4 | (start_left & 0xe); + value[6] = 0xff; usbhid_submit_report(hid, report, USB_DIR_OUT); } @@ -344,14 +406,15 @@ static void lg4ff_set_leds(struct hid_device *hid, __u8 leds) { struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; struct hid_report *report = list_entry(report_list->next, struct hid_report, list); - - report->field[0]->value[0] = 0xf8; - report->field[0]->value[1] = 0x12; - report->field[0]->value[2] = leds; - report->field[0]->value[3] = 0x00; - report->field[0]->value[4] = 0x00; - report->field[0]->value[5] = 0x00; - report->field[0]->value[6] = 0x00; + __s32 *value = report->field[0]->value; + + value[0] = 0xf8; + value[1] = 0x12; + value[2] = leds; + value[3] = 0x00; + value[4] = 0x00; + value[5] = 0x00; + value[6] = 0x00; usbhid_submit_report(hid, report, USB_DIR_OUT); } @@ -360,7 +423,7 @@ static void lg4ff_led_set_brightness(struct led_classdev *led_cdev, { struct device *dev = led_cdev->dev->parent; struct hid_device *hid = container_of(dev, struct hid_device, dev); - struct lg_drv_data *drv_data = (struct lg_drv_data *)hid_get_drvdata(hid); + struct lg_drv_data *drv_data = hid_get_drvdata(hid); struct lg4ff_device_entry *entry; int i, state = 0; @@ -395,7 +458,7 @@ static enum led_brightness lg4ff_led_get_brightness(struct led_classdev *led_cde { struct device *dev = led_cdev->dev->parent; struct hid_device *hid = container_of(dev, struct hid_device, dev); - struct lg_drv_data *drv_data = (struct lg_drv_data *)hid_get_drvdata(hid); + struct lg_drv_data *drv_data = hid_get_drvdata(hid); struct lg4ff_device_entry *entry; int i, value = 0; @@ -501,7 +564,7 @@ int lg4ff_init(struct hid_device *hid) /* Check if autocentering is available and * set the centering force to zero by default */ if (test_bit(FF_AUTOCENTER, dev->ffbit)) { - if(rev_maj == FFEX_REV_MAJ && rev_min == FFEX_REV_MIN) /* Formula Force EX expects different autocentering command */ + if (rev_maj == FFEX_REV_MAJ && rev_min == FFEX_REV_MIN) /* Formula Force EX expects different autocentering command */ dev->ff->set_autocenter = hid_lg4ff_set_autocenter_ffex; else dev->ff->set_autocenter = hid_lg4ff_set_autocenter_default; @@ -524,6 +587,7 @@ int lg4ff_init(struct hid_device *hid) } drv_data->device_props = entry; + entry->product_id = lg4ff_devices[i].product_id; entry->min_range = lg4ff_devices[i].min_range; entry->max_range = lg4ff_devices[i].max_range; entry->set_range = lg4ff_devices[i].set_range; @@ -534,6 +598,18 @@ int lg4ff_init(struct hid_device *hid) return error; dbg_hid("sysfs interface created\n"); + /* Set default axes parameters */ + switch (lg4ff_devices[i].product_id) { + case USB_DEVICE_ID_LOGITECH_DFP_WHEEL: + dbg_hid("Setting axes parameters for Driving Force Pro\n"); + input_set_abs_params(dev, ABS_X, DFP_X_MIN, DFP_X_MAX, 0, 0); + input_set_abs_params(dev, ABS_Y, DFP_PEDAL_MIN, DFP_PEDAL_MAX, 0, 0); + input_set_abs_params(dev, ABS_RZ, DFP_PEDAL_MIN, DFP_PEDAL_MAX, 0, 0); + break; + default: + break; + } + /* Set the maximum range to start with */ entry->range = entry->max_range; if (entry->set_range != NULL) @@ -594,6 +670,8 @@ out: return 0; } + + int lg4ff_deinit(struct hid_device *hid) { struct lg4ff_device_entry *entry; |