aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hid/hid-lg4ff.c
diff options
context:
space:
mode:
authorMichal Malý <madcatxster@gmail.com>2011-08-04 10:18:11 -0400
committerJiri Kosina <jkosina@suse.cz>2011-08-04 10:45:55 -0400
commit96440c8a00e22e541135dee2eba9f3e7d8195f65 (patch)
tree66a2da8c5c6e5122306eaad5f2a8426394db50f1 /drivers/hid/hid-lg4ff.c
parent7362cd2286d2364cca6738b583668f64254fe04b (diff)
HID: lg4ff - Add support for native mode switching
This patch allows the lg4ff driver to switch wheels to the native mode. Since this is specific to Logitech wheels only, it's handled in hid-lg4ff rather than hid-lg. Signed-off-by: Michal Malý <madcatxster@gmail.com> Signed-off-by: Simon Wood <simon@mungewell.org> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'drivers/hid/hid-lg4ff.c')
-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);