aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/hid/hid-lg4ff.c89
1 files changed, 89 insertions, 0 deletions
diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c
index 1fcb2da32785..8eb938d7aa02 100644
--- a/drivers/hid/hid-lg4ff.c
+++ b/drivers/hid/hid-lg4ff.c
@@ -31,6 +31,17 @@
31#include "hid-lg.h" 31#include "hid-lg.h"
32#include "hid-ids.h" 32#include "hid-ids.h"
33 33
34#define DFGT_REV_MAJ 0x13
35#define DFGT_REV_MIN 0x22
36#define DFP_REV_MAJ 0x11
37#define DFP_REV_MIN 0x06
38#define FFEX_REV_MAJ 0x21
39#define FFEX_REV_MIN 0x00
40#define G25_REV_MAJ 0x12
41#define G25_REV_MIN 0x22
42#define G27_REV_MAJ 0x12
43#define G27_REV_MIN 0x38
44
34static const signed short lg4ff_wheel_effects[] = { 45static const signed short lg4ff_wheel_effects[] = {
35 FF_CONSTANT, 46 FF_CONSTANT,
36 FF_AUTOCENTER, 47 FF_AUTOCENTER,
@@ -55,6 +66,46 @@ static const struct lg4ff_wheel lg4ff_devices[] = {
55 {USB_DEVICE_ID_LOGITECH_WII_WHEEL, lg4ff_wheel_effects, 40, 270} 66 {USB_DEVICE_ID_LOGITECH_WII_WHEEL, lg4ff_wheel_effects, 40, 270}
56}; 67};
57 68
69struct lg4ff_native_cmd {
70 const __u8 cmd_num; /* Number of commands to send */
71 const __u8 cmd[];
72};
73
74struct lg4ff_usb_revision {
75 const __u16 rev_maj;
76 const __u16 rev_min;
77 const struct lg4ff_native_cmd *command;
78};
79
80static const struct lg4ff_native_cmd native_dfp = {
81 1,
82 {0xf8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00}
83};
84
85static const struct lg4ff_native_cmd native_dfgt = {
86 2,
87 {0xf8, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, /* 1st command */
88 0xf8, 0x09, 0x03, 0x01, 0x00, 0x00, 0x00} /* 2nd command */
89};
90
91static const struct lg4ff_native_cmd native_g25 = {
92 1,
93 {0xf8, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00}
94};
95
96static const struct lg4ff_native_cmd native_g27 = {
97 2,
98 {0xf8, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, /* 1st command */
99 0xf8, 0x09, 0x04, 0x01, 0x00, 0x00, 0x00} /* 2nd command */
100};
101
102static const struct lg4ff_usb_revision lg4ff_revs[] = {
103 {DFGT_REV_MAJ, DFGT_REV_MIN, &native_dfgt}, /* Driving Force GT */
104 {DFP_REV_MAJ, DFP_REV_MIN, &native_dfp}, /* Driving Force Pro */
105 {G25_REV_MAJ, G25_REV_MIN, &native_g25}, /* G25 */
106 {G27_REV_MAJ, G27_REV_MIN, &native_g27}, /* G27 */
107};
108
58static int hid_lg4ff_play(struct input_dev *dev, void *data, 109static int hid_lg4ff_play(struct input_dev *dev, void *data,
59 struct ff_effect *effect) 110 struct ff_effect *effect)
60{ 111{
@@ -100,6 +151,20 @@ static void hid_lg4ff_set_autocenter(struct input_dev *dev, u16 magnitude)
100 usbhid_submit_report(hid, report, USB_DIR_OUT); 151 usbhid_submit_report(hid, report, USB_DIR_OUT);
101} 152}
102 153
154static void hid_lg4ff_switch_native(struct hid_device *hid, const struct lg4ff_native_cmd *cmd)
155{
156 struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
157 struct hid_report *report = list_entry(report_list->next, struct hid_report, list);
158 __u8 i, j;
159
160 j = 0;
161 while (j < 7*cmd->cmd_num) {
162 for (i = 0; i < 7; i++)
163 report->field[0]->value[i] = cmd->cmd[j++];
164
165 usbhid_submit_report(hid, report, USB_DIR_OUT);
166 }
167}
103 168
104int lg4ff_init(struct hid_device *hid) 169int lg4ff_init(struct hid_device *hid)
105{ 170{
@@ -108,7 +173,9 @@ int lg4ff_init(struct hid_device *hid)
108 struct input_dev *dev = hidinput->input; 173 struct input_dev *dev = hidinput->input;
109 struct hid_report *report; 174 struct hid_report *report;
110 struct hid_field *field; 175 struct hid_field *field;
176 struct usb_device_descriptor *udesc = 0;
111 int error, i, j; 177 int error, i, j;
178 __u16 bcdDevice, rev_maj, rev_min;
112 179
113 /* Find the report to use */ 180 /* Find the report to use */
114 if (list_empty(report_list)) { 181 if (list_empty(report_list)) {
@@ -143,6 +210,28 @@ int lg4ff_init(struct hid_device *hid)
143 return -1; 210 return -1;
144 } 211 }
145 212
213 /* Attempt to switch wheel to native mode when applicable */
214 udesc = &(hid_to_usb_dev(hid)->descriptor);
215 if (!udesc) {
216 hid_err(hid, "NULL USB device descriptor\n");
217 return -1;
218 }
219 bcdDevice = le16_to_cpu(udesc->bcdDevice);
220 rev_maj = bcdDevice >> 8;
221 rev_min = bcdDevice & 0xff;
222
223 if (lg4ff_devices[i].product_id == USB_DEVICE_ID_LOGITECH_WHEEL) {
224 dbg_hid("Generic wheel detected, can it do native?\n");
225 dbg_hid("USB revision: %2x.%02x\n", rev_maj, rev_min);
226
227 for (j = 0; j < ARRAY_SIZE(lg4ff_revs); j++) {
228 if (lg4ff_revs[j].rev_maj == rev_maj && lg4ff_revs[j].rev_min == rev_min) {
229 hid_lg4ff_switch_native(hid, lg4ff_revs[j].command);
230 hid_info(hid, "Switched to native mode\n");
231 }
232 }
233 }
234
146 /* Set supported force feedback capabilities */ 235 /* Set supported force feedback capabilities */
147 for (j = 0; lg4ff_devices[i].ff_effects[j] >= 0; j++) 236 for (j = 0; lg4ff_devices[i].ff_effects[j] >= 0; j++)
148 set_bit(lg4ff_devices[i].ff_effects[j], dev->ffbit); 237 set_bit(lg4ff_devices[i].ff_effects[j], dev->ffbit);