Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 68659
b: refs/heads/master
c: b27c959
h: refs/heads/master
i:
  68657: 19bb733
  68655: 15f87a2
v: v3
  • Loading branch information
Dmitry Torokhov authored and Jiri Kosina committed Oct 14, 2007
1 parent be106f4 commit 485d2ed
Show file tree
Hide file tree
Showing 4 changed files with 125 additions and 45 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 933e3187d0042d9381d932757dc1f931d984e56d
refs/heads/master: b27c9590ca0f44681fe2504a7ec427ff1bb77e82
5 changes: 3 additions & 2 deletions trunk/drivers/hid/usbhid/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,12 @@ config PANTHERLORD_FF
to enable force feedback support for it.

config THRUSTMASTER_FF
bool "ThrustMaster FireStorm Dual Power 2 support (EXPERIMENTAL)"
bool "ThrustMaster devices support (EXPERIMENTAL)"
depends on HID_FF && EXPERIMENTAL
select INPUT_FF_MEMLESS if USB_HID
help
Say Y here if you have a THRUSTMASTER FireStore Dual Power 2,
Say Y here if you have a THRUSTMASTER FireStore Dual Power 2 or
a THRUSTMASTER Ferrari GT Rumble Force or Force Feedback Wheel,
and want to enable force feedback support for it.
Note: if you say N here, this device will still be supported, but without
force feedback.
Expand Down
2 changes: 2 additions & 0 deletions trunk/drivers/hid/usbhid/hid-ff.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ static struct hid_ff_initializer inits[] = {
#ifdef CONFIG_THRUSTMASTER_FF
{ 0x44f, 0xb300, hid_tmff_init },
{ 0x44f, 0xb304, hid_tmff_init },
{ 0x44f, 0xb651, hid_tmff_init }, /* FGT Rumble Force Wheel */
{ 0x44f, 0xb654, hid_tmff_init }, /* FGT Force Feedback Wheel */
#endif
#ifdef CONFIG_ZEROPLUS_FF
{ 0xc12, 0x0005, hid_zpff_init },
Expand Down
161 changes: 119 additions & 42 deletions trunk/drivers/hid/usbhid/hid-tmff.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,39 @@
#include "usbhid.h"

/* Usages for thrustmaster devices I know about */
#define THRUSTMASTER_USAGE_RUMBLE_LR (HID_UP_GENDESK | 0xbb)
#define THRUSTMASTER_USAGE_FF (HID_UP_GENDESK | 0xbb)

struct dev_type {
u16 idVendor;
u16 idProduct;
const signed short *ff;
};

static const signed short ff_rumble[] = {
FF_RUMBLE,
-1
};

static const signed short ff_joystick[] = {
FF_CONSTANT,
-1
};

static const struct dev_type devices[] = {
{ 0x44f, 0xb300, ff_rumble },
{ 0x44f, 0xb304, ff_rumble },
{ 0x44f, 0xb651, ff_rumble }, /* FGT Rumble Force Wheel */
{ 0x44f, 0xb654, ff_joystick }, /* FGT Force Feedback Wheel */
};

struct tmff_device {
struct hid_report *report;
struct hid_field *rumble;
struct hid_field *ff_field;
};

/* Changes values from 0 to 0xffff into values from minimum to maximum */
static inline int hid_tmff_scale(unsigned int in, int minimum, int maximum)
static inline int hid_tmff_scale_u16(unsigned int in,
int minimum, int maximum)
{
int ret;

Expand All @@ -57,22 +80,57 @@ static inline int hid_tmff_scale(unsigned int in, int minimum, int maximum)
return ret;
}

/* Changes values from -0x80 to 0x7f into values from minimum to maximum */
static inline int hid_tmff_scale_s8(int in,
int minimum, int maximum)
{
int ret;

ret = (((in + 0x80) * (maximum - minimum)) / 0xff) + minimum;
if (ret < minimum)
return minimum;
if (ret > maximum)
return maximum;
return ret;
}

static int hid_tmff_play(struct input_dev *dev, void *data, struct ff_effect *effect)
{
struct hid_device *hid = input_get_drvdata(dev);
struct tmff_device *tmff = data;
struct hid_field *ff_field = tmff->ff_field;
int x, y;
int left, right; /* Rumbling */

left = hid_tmff_scale(effect->u.rumble.weak_magnitude,
tmff->rumble->logical_minimum, tmff->rumble->logical_maximum);
right = hid_tmff_scale(effect->u.rumble.strong_magnitude,
tmff->rumble->logical_minimum, tmff->rumble->logical_maximum);

tmff->rumble->value[0] = left;
tmff->rumble->value[1] = right;
dbg_hid("(left,right)=(%08x, %08x)\n", left, right);
usbhid_submit_report(hid, tmff->report, USB_DIR_OUT);

switch (effect->type) {
case FF_CONSTANT:
x = hid_tmff_scale_s8(effect->u.ramp.start_level,
ff_field->logical_minimum,
ff_field->logical_maximum);
y = hid_tmff_scale_s8(effect->u.ramp.end_level,
ff_field->logical_minimum,
ff_field->logical_maximum);

dbg_hid("(x, y)=(%04x, %04x)\n", x, y);
ff_field->value[0] = x;
ff_field->value[1] = y;
usbhid_submit_report(hid, tmff->report, USB_DIR_OUT);
break;

case FF_RUMBLE:
left = hid_tmff_scale_u16(effect->u.rumble.weak_magnitude,
ff_field->logical_minimum,
ff_field->logical_maximum);
right = hid_tmff_scale_u16(effect->u.rumble.strong_magnitude,
ff_field->logical_minimum,
ff_field->logical_maximum);

dbg_hid("(left,right)=(%08x, %08x)\n", left, right);
ff_field->value[0] = left;
ff_field->value[1] = right;
usbhid_submit_report(hid, tmff->report, USB_DIR_OUT);
break;
}
return 0;
}

Expand All @@ -82,14 +140,16 @@ int hid_tmff_init(struct hid_device *hid)
struct list_head *pos;
struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list);
struct input_dev *input_dev = hidinput->input;
const signed short *ff_bits = ff_joystick;
int error;
int i;

tmff = kzalloc(sizeof(struct tmff_device), GFP_KERNEL);
if (!tmff)
return -ENOMEM;

/* Find the report to use */
__list_for_each(pos, &hid->report_enum[HID_OUTPUT_REPORT].report_list) {
list_for_each(pos, &hid->report_enum[HID_OUTPUT_REPORT].report_list) {
struct hid_report *report = (struct hid_report *)pos;
int fieldnum;

Expand All @@ -100,48 +160,65 @@ int hid_tmff_init(struct hid_device *hid)
continue;

switch (field->usage[0].hid) {
case THRUSTMASTER_USAGE_RUMBLE_LR:
if (field->report_count < 2) {
warn("ignoring THRUSTMASTER_USAGE_RUMBLE_LR with report_count < 2");
continue;
}
case THRUSTMASTER_USAGE_FF:
if (field->report_count < 2) {
warn("ignoring FF field with report_count < 2");
continue;
}

if (field->logical_maximum == field->logical_minimum) {
warn("ignoring THRUSTMASTER_USAGE_RUMBLE_LR with logical_maximum == logical_minimum");
continue;
}
if (field->logical_maximum == field->logical_minimum) {
warn("ignoring FF field with logical_maximum == logical_minimum");
continue;
}

if (tmff->report && tmff->report != report) {
warn("ignoring THRUSTMASTER_USAGE_RUMBLE_LR in other report");
continue;
}
if (tmff->report && tmff->report != report) {
warn("ignoring FF field in other report");
continue;
}

if (tmff->rumble && tmff->rumble != field) {
warn("ignoring duplicate THRUSTMASTER_USAGE_RUMBLE_LR");
continue;
if (tmff->ff_field && tmff->ff_field != field) {
warn("ignoring duplicate FF field");
continue;
}

tmff->report = report;
tmff->ff_field = field;

for (i = 0; i < ARRAY_SIZE(devices); i++) {
if (input_dev->id.vendor == devices[i].idVendor &&
input_dev->id.product == devices[i].idProduct) {
ff_bits = devices[i].ff;
break;
}
}

tmff->report = report;
tmff->rumble = field;
for (i = 0; ff_bits[i] >= 0; i++)
set_bit(ff_bits[i], input_dev->ffbit);

set_bit(FF_RUMBLE, input_dev->ffbit);
break;
break;

default:
warn("ignoring unknown output usage %08x", field->usage[0].hid);
continue;
default:
warn("ignoring unknown output usage %08x", field->usage[0].hid);
continue;
}
}
}

error = input_ff_create_memless(input_dev, tmff, hid_tmff_play);
if (error) {
kfree(tmff);
return error;
if (!tmff->report) {
err("cant find FF field in output reports\n");
error = -ENODEV;
goto fail;
}

info("Force feedback for ThrustMaster rumble pad devices by Zinx Verituse <zinx@epicsol.org>");
error = input_ff_create_memless(input_dev, tmff, hid_tmff_play);
if (error)
goto fail;

info("Force feedback for ThrustMaster devices by Zinx Verituse <zinx@epicsol.org>");
return 0;

fail:
kfree(tmff);
return error;
}

0 comments on commit 485d2ed

Please sign in to comment.