Skip to content

Commit 29fae1c

Browse files
mungewellJiri Kosina
authored andcommitted
HID: logitech: Add support for G29
At present the G29 is mis-identified as a DFGT, this patch ensures that the wheel is correctly detected and allows setting the LEDs and turning range via the '/sys' interface. This wheel can also emulate other types of Logitech wheels. Signed-off-by: Simon Wood <[email protected]> Signed-off-by: Jiri Kosina <[email protected]>
1 parent bbec1bd commit 29fae1c

File tree

3 files changed

+63
-4
lines changed

3 files changed

+63
-4
lines changed

drivers/hid/hid-core.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1896,6 +1896,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
18961896
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD_CORD) },
18971897
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD) },
18981898
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2) },
1899+
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G29_WHEEL) },
18991900
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_F3D) },
19001901
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FFG ) },
19011902
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FORCE3D_PRO) },

drivers/hid/hid-lg.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -620,6 +620,7 @@ static int lg_input_mapped(struct hid_device *hdev, struct hid_input *hi,
620620
usage->code == ABS_Y || usage->code == ABS_Z ||
621621
usage->code == ABS_RZ)) {
622622
switch (hdev->product) {
623+
case USB_DEVICE_ID_LOGITECH_G29_WHEEL:
623624
case USB_DEVICE_ID_LOGITECH_WHEEL:
624625
case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL:
625626
case USB_DEVICE_ID_LOGITECH_DFP_WHEEL:
@@ -658,10 +659,18 @@ static int lg_event(struct hid_device *hdev, struct hid_field *field,
658659

659660
static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
660661
{
662+
struct usb_interface *iface = to_usb_interface(hdev->dev.parent);
663+
__u8 iface_num = iface->cur_altsetting->desc.bInterfaceNumber;
661664
unsigned int connect_mask = HID_CONNECT_DEFAULT;
662665
struct lg_drv_data *drv_data;
663666
int ret;
664667

668+
/* Only work with the 1st interface (G29 presents multiple) */
669+
if (iface_num != 0) {
670+
dbg_hid("%s: ignoring ifnum %d\n", __func__, iface_num);
671+
return -ENODEV;
672+
}
673+
665674
drv_data = kzalloc(sizeof(struct lg_drv_data), GFP_KERNEL);
666675
if (!drv_data) {
667676
hid_err(hdev, "Insufficient memory, cannot allocate driver data\n");

drivers/hid/hid-lg4ff.c

Lines changed: 53 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,14 +45,16 @@
4545
#define LG4FF_MODE_G25_IDX 3
4646
#define LG4FF_MODE_DFGT_IDX 4
4747
#define LG4FF_MODE_G27_IDX 5
48-
#define LG4FF_MODE_MAX_IDX 6
48+
#define LG4FF_MODE_G29_IDX 6
49+
#define LG4FF_MODE_MAX_IDX 7
4950

5051
#define LG4FF_MODE_NATIVE BIT(LG4FF_MODE_NATIVE_IDX)
5152
#define LG4FF_MODE_DFEX BIT(LG4FF_MODE_DFEX_IDX)
5253
#define LG4FF_MODE_DFP BIT(LG4FF_MODE_DFP_IDX)
5354
#define LG4FF_MODE_G25 BIT(LG4FF_MODE_G25_IDX)
5455
#define LG4FF_MODE_DFGT BIT(LG4FF_MODE_DFGT_IDX)
5556
#define LG4FF_MODE_G27 BIT(LG4FF_MODE_G27_IDX)
57+
#define LG4FF_MODE_G29 BIT(LG4FF_MODE_G29_IDX)
5658

5759
#define LG4FF_DFEX_TAG "DF-EX"
5860
#define LG4FF_DFEX_NAME "Driving Force / Formula EX"
@@ -62,6 +64,8 @@
6264
#define LG4FF_G25_NAME "G25 Racing Wheel"
6365
#define LG4FF_G27_TAG "G27"
6466
#define LG4FF_G27_NAME "G27 Racing Wheel"
67+
#define LG4FF_G29_TAG "G29"
68+
#define LG4FF_G29_NAME "G29 Racing Wheel"
6569
#define LG4FF_DFGT_TAG "DFGT"
6670
#define LG4FF_DFGT_NAME "Driving Force GT"
6771

@@ -140,6 +144,7 @@ static const struct lg4ff_wheel lg4ff_devices[] = {
140144
{USB_DEVICE_ID_LOGITECH_G25_WHEEL, lg4ff_wheel_effects, 40, 900, lg4ff_set_range_g25},
141145
{USB_DEVICE_ID_LOGITECH_DFGT_WHEEL, lg4ff_wheel_effects, 40, 900, lg4ff_set_range_g25},
142146
{USB_DEVICE_ID_LOGITECH_G27_WHEEL, lg4ff_wheel_effects, 40, 900, lg4ff_set_range_g25},
147+
{USB_DEVICE_ID_LOGITECH_G29_WHEEL, lg4ff_wheel_effects, 40, 900, lg4ff_set_range_g25},
143148
{USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2, lg4ff_wheel_effects, 40, 270, NULL},
144149
{USB_DEVICE_ID_LOGITECH_WII_WHEEL, lg4ff_wheel_effects, 40, 270, NULL}
145150
};
@@ -157,6 +162,9 @@ static const struct lg4ff_multimode_wheel lg4ff_multimode_wheels[] = {
157162
{USB_DEVICE_ID_LOGITECH_G27_WHEEL,
158163
LG4FF_MODE_NATIVE | LG4FF_MODE_G27 | LG4FF_MODE_G25 | LG4FF_MODE_DFP | LG4FF_MODE_DFEX,
159164
LG4FF_G27_TAG, LG4FF_G27_NAME},
165+
{USB_DEVICE_ID_LOGITECH_G29_WHEEL,
166+
LG4FF_MODE_NATIVE | LG4FF_MODE_G29 | LG4FF_MODE_G27 | LG4FF_MODE_G25 | LG4FF_MODE_DFGT | LG4FF_MODE_DFP | LG4FF_MODE_DFEX,
167+
LG4FF_G29_TAG, LG4FF_G29_NAME},
160168
};
161169

162170
static const struct lg4ff_alternate_mode lg4ff_alternate_modes[] = {
@@ -165,7 +173,8 @@ static const struct lg4ff_alternate_mode lg4ff_alternate_modes[] = {
165173
[LG4FF_MODE_DFP_IDX] = {USB_DEVICE_ID_LOGITECH_DFP_WHEEL, LG4FF_DFP_TAG, LG4FF_DFP_NAME},
166174
[LG4FF_MODE_G25_IDX] = {USB_DEVICE_ID_LOGITECH_G25_WHEEL, LG4FF_G25_TAG, LG4FF_G25_NAME},
167175
[LG4FF_MODE_DFGT_IDX] = {USB_DEVICE_ID_LOGITECH_DFGT_WHEEL, LG4FF_DFGT_TAG, LG4FF_DFGT_NAME},
168-
[LG4FF_MODE_G27_IDX] = {USB_DEVICE_ID_LOGITECH_G27_WHEEL, LG4FF_G27_TAG, LG4FF_G27_NAME}
176+
[LG4FF_MODE_G27_IDX] = {USB_DEVICE_ID_LOGITECH_G27_WHEEL, LG4FF_G27_TAG, LG4FF_G27_NAME},
177+
[LG4FF_MODE_G29_IDX] = {USB_DEVICE_ID_LOGITECH_G29_WHEEL, LG4FF_G29_TAG, LG4FF_G29_NAME},
169178
};
170179

171180
/* Multimode wheel identificators */
@@ -197,8 +206,24 @@ static const struct lg4ff_wheel_ident_info lg4ff_dfgt_ident_info = {
197206
USB_DEVICE_ID_LOGITECH_DFGT_WHEEL
198207
};
199208

209+
static const struct lg4ff_wheel_ident_info lg4ff_g29_ident_info = {
210+
LG4FF_MODE_G29 | LG4FF_MODE_G27 | LG4FF_MODE_G25 | LG4FF_MODE_DFGT | LG4FF_MODE_DFP | LG4FF_MODE_DFEX,
211+
0xfff8,
212+
0x1350,
213+
USB_DEVICE_ID_LOGITECH_G29_WHEEL
214+
};
215+
216+
static const struct lg4ff_wheel_ident_info lg4ff_g29_ident_info2 = {
217+
LG4FF_MODE_G29 | LG4FF_MODE_G27 | LG4FF_MODE_G25 | LG4FF_MODE_DFGT | LG4FF_MODE_DFP | LG4FF_MODE_DFEX,
218+
0xff00,
219+
0x8900,
220+
USB_DEVICE_ID_LOGITECH_G29_WHEEL
221+
};
222+
200223
/* Multimode wheel identification checklists */
201224
static const struct lg4ff_wheel_ident_info *lg4ff_main_checklist[] = {
225+
&lg4ff_g29_ident_info,
226+
&lg4ff_g29_ident_info2,
202227
&lg4ff_dfgt_ident_info,
203228
&lg4ff_g27_ident_info,
204229
&lg4ff_g25_ident_info,
@@ -237,6 +262,12 @@ static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_ext09_g27 = {
237262
0xf8, 0x09, 0x04, 0x01, 0x00, 0x00, 0x00} /* Switch mode to G27 with detach */
238263
};
239264

265+
static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_ext09_g29 = {
266+
2,
267+
{0xf8, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, /* Revert mode upon USB reset */
268+
0xf8, 0x09, 0x05, 0x01, 0x01, 0x00, 0x00} /* Switch mode to G29 with detach */
269+
};
270+
240271
/* EXT_CMD1 - Understood by DFP, G25, G27 and DFGT */
241272
static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_ext01_dfp = {
242273
1,
@@ -650,6 +681,23 @@ static const struct lg4ff_compat_mode_switch *lg4ff_get_mode_switch_command(cons
650681
return NULL;
651682
}
652683
break;
684+
case USB_DEVICE_ID_LOGITECH_G29_WHEEL:
685+
switch (target_product_id) {
686+
case USB_DEVICE_ID_LOGITECH_DFP_WHEEL:
687+
return &lg4ff_mode_switch_ext09_dfp;
688+
case USB_DEVICE_ID_LOGITECH_DFGT_WHEEL:
689+
return &lg4ff_mode_switch_ext09_dfgt;
690+
case USB_DEVICE_ID_LOGITECH_G25_WHEEL:
691+
return &lg4ff_mode_switch_ext09_g25;
692+
case USB_DEVICE_ID_LOGITECH_G27_WHEEL:
693+
return &lg4ff_mode_switch_ext09_g27;
694+
case USB_DEVICE_ID_LOGITECH_G29_WHEEL:
695+
return &lg4ff_mode_switch_ext09_g29;
696+
/* G29 can only be switched to DF-EX, DFP, DFGT, G25, G27 or its native mode */
697+
default:
698+
return NULL;
699+
}
700+
break;
653701
case USB_DEVICE_ID_LOGITECH_DFGT_WHEEL:
654702
switch (target_product_id) {
655703
case USB_DEVICE_ID_LOGITECH_WHEEL:
@@ -1232,12 +1280,13 @@ int lg4ff_init(struct hid_device *hid)
12321280
entry->wdata.set_range(hid, entry->wdata.range);
12331281

12341282
#ifdef CONFIG_LEDS_CLASS
1235-
/* register led subsystem - G27 only */
1283+
/* register led subsystem - G27/G29 only */
12361284
entry->wdata.led_state = 0;
12371285
for (j = 0; j < 5; j++)
12381286
entry->wdata.led[j] = NULL;
12391287

1240-
if (lg4ff_devices[i].product_id == USB_DEVICE_ID_LOGITECH_G27_WHEEL) {
1288+
if (lg4ff_devices[i].product_id == USB_DEVICE_ID_LOGITECH_G27_WHEEL ||
1289+
lg4ff_devices[i].product_id == USB_DEVICE_ID_LOGITECH_G29_WHEEL) {
12411290
struct led_classdev *led;
12421291
size_t name_sz;
12431292
char *name;

0 commit comments

Comments
 (0)