diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index e6fce23..2e9c706 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1874,6 +1874,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD_CORD) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2) }, + { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G29_WHEEL) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_F3D) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FFG ) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FORCE3D_PRO) }, diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c index 02cec83..d0c3da5 100644 --- a/drivers/hid/hid-lg4ff.c +++ b/drivers/hid/hid-lg4ff.c @@ -45,7 +45,8 @@ #define LG4FF_MODE_G25_IDX 3 #define LG4FF_MODE_DFGT_IDX 4 #define LG4FF_MODE_G27_IDX 5 -#define LG4FF_MODE_MAX_IDX 6 +#define LG4FF_MODE_G29_IDX 6 +#define LG4FF_MODE_MAX_IDX 7 #define LG4FF_MODE_NATIVE BIT(LG4FF_MODE_NATIVE_IDX) #define LG4FF_MODE_DFEX BIT(LG4FF_MODE_DFEX_IDX) @@ -53,6 +54,7 @@ #define LG4FF_MODE_G25 BIT(LG4FF_MODE_G25_IDX) #define LG4FF_MODE_DFGT BIT(LG4FF_MODE_DFGT_IDX) #define LG4FF_MODE_G27 BIT(LG4FF_MODE_G27_IDX) +#define LG4FF_MODE_G29 BIT(LG4FF_MODE_G29_IDX) #define LG4FF_DFEX_TAG "DF-EX" #define LG4FF_DFEX_NAME "Driving Force / Formula EX" @@ -62,6 +64,8 @@ #define LG4FF_G25_NAME "G25 Racing Wheel" #define LG4FF_G27_TAG "G27" #define LG4FF_G27_NAME "G27 Racing Wheel" +#define LG4FF_G29_TAG "G29" +#define LG4FF_G29_NAME "G29 Racing Wheel" #define LG4FF_DFGT_TAG "DFGT" #define LG4FF_DFGT_NAME "Driving Force GT" @@ -144,6 +148,7 @@ static const struct lg4ff_wheel lg4ff_devices[] = { {USB_DEVICE_ID_LOGITECH_G25_WHEEL, lg4ff_wheel_effects, 40, 900, lg4ff_set_range_g25}, {USB_DEVICE_ID_LOGITECH_DFGT_WHEEL, lg4ff_wheel_effects, 40, 900, lg4ff_set_range_g25}, {USB_DEVICE_ID_LOGITECH_G27_WHEEL, lg4ff_wheel_effects, 40, 900, lg4ff_set_range_g25}, + {USB_DEVICE_ID_LOGITECH_G29_WHEEL, lg4ff_wheel_effects, 40, 900, lg4ff_set_range_g25}, {USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2, lg4ff_wheel_effects, 40, 270, NULL}, {USB_DEVICE_ID_LOGITECH_WII_WHEEL, lg4ff_wheel_effects, 40, 270, NULL} }; @@ -161,6 +166,9 @@ static const struct lg4ff_multimode_wheel lg4ff_multimode_wheels[] = { {USB_DEVICE_ID_LOGITECH_G27_WHEEL, LG4FF_MODE_NATIVE | LG4FF_MODE_G27 | LG4FF_MODE_G25 | LG4FF_MODE_DFP | LG4FF_MODE_DFEX, LG4FF_G27_TAG, LG4FF_G27_NAME}, + {USB_DEVICE_ID_LOGITECH_G29_WHEEL, + LG4FF_MODE_NATIVE | LG4FF_MODE_G29 | LG4FF_MODE_DFGT | LG4FF_MODE_DFP, + LG4FF_G29_TAG, LG4FF_G29_NAME}, }; static const struct lg4ff_alternate_mode lg4ff_alternate_modes[] = { @@ -169,7 +177,8 @@ static const struct lg4ff_alternate_mode lg4ff_alternate_modes[] = { [LG4FF_MODE_DFP_IDX] = {USB_DEVICE_ID_LOGITECH_DFP_WHEEL, LG4FF_DFP_TAG, LG4FF_DFP_NAME}, [LG4FF_MODE_G25_IDX] = {USB_DEVICE_ID_LOGITECH_G25_WHEEL, LG4FF_G25_TAG, LG4FF_G25_NAME}, [LG4FF_MODE_DFGT_IDX] = {USB_DEVICE_ID_LOGITECH_DFGT_WHEEL, LG4FF_DFGT_TAG, LG4FF_DFGT_NAME}, - [LG4FF_MODE_G27_IDX] = {USB_DEVICE_ID_LOGITECH_G27_WHEEL, LG4FF_G27_TAG, LG4FF_G27_NAME} + [LG4FF_MODE_G27_IDX] = {USB_DEVICE_ID_LOGITECH_G27_WHEEL, LG4FF_G27_TAG, LG4FF_G27_NAME}, + [LG4FF_MODE_G29_IDX] = {USB_DEVICE_ID_LOGITECH_G29_WHEEL, LG4FF_G29_TAG, LG4FF_G29_NAME} }; /* Multimode wheel identificators */ @@ -197,10 +206,17 @@ static const struct lg4ff_wheel_ident_info lg4ff_dfgt_ident_info = { USB_DEVICE_ID_LOGITECH_DFGT_WHEEL }; +static const struct lg4ff_wheel_ident_info lg4ff_g29_ident_info = { + 0xfff0, + 0x1350, + USB_DEVICE_ID_LOGITECH_G29_WHEEL +}; + /* Multimode wheel identification checklists */ static const struct lg4ff_wheel_ident_checklist lg4ff_main_checklist = { - 4, - {&lg4ff_dfgt_ident_info, + 5, + {&lg4ff_g29_ident_info, + &lg4ff_dfgt_ident_info, &lg4ff_g27_ident_info, &lg4ff_g25_ident_info, &lg4ff_dfp_ident_info} @@ -238,6 +254,12 @@ static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_ext09_g27 = { 0xf8, 0x09, 0x04, 0x01, 0x00, 0x00, 0x00} /* Switch mode to G27 with detach */ }; +static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_ext09_g29 = { + 2, + {0xf8, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, /* Revert mode upon USB reset */ + 0xf8, 0x09, 0x05, 0x01, 0x00, 0x00, 0x00} /* Switch mode to G29 with detach */ +}; + /* EXT_CMD1 - Understood by DFP, G25, G27 and DFGT */ static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_ext01_dfp = { 1, @@ -651,6 +673,19 @@ static const struct lg4ff_compat_mode_switch *lg4ff_get_mode_switch_command(cons return NULL; } break; + case USB_DEVICE_ID_LOGITECH_G29_WHEEL: + switch (target_product_id) { + case USB_DEVICE_ID_LOGITECH_DFP_WHEEL: + return &lg4ff_mode_switch_ext09_dfp; + case USB_DEVICE_ID_LOGITECH_DFGT_WHEEL: + return &lg4ff_mode_switch_ext09_dfgt; + case USB_DEVICE_ID_LOGITECH_G29_WHEEL: + return &lg4ff_mode_switch_ext09_g29; + /* G29 can only be switched to DFP, DFGT or its native mode */ + default: + return NULL; + } + break; case USB_DEVICE_ID_LOGITECH_DFGT_WHEEL: switch (target_product_id) { case USB_DEVICE_ID_LOGITECH_WHEEL: @@ -1049,12 +1084,12 @@ static u16 lg4ff_identify_multimode_wheel(struct hid_device *hid, const u16 repo break; case USB_DEVICE_ID_LOGITECH_G25_WHEEL: checklist = &lg4ff_main_checklist; - from_idx = 0; + from_idx = 1; to_idx = checklist->count - 2; /* End identity check at G25 */ break; case USB_DEVICE_ID_LOGITECH_G27_WHEEL: checklist = &lg4ff_main_checklist; - from_idx = 1; /* Start identity check at G27 */ + from_idx = 2; /* Start identity check at G27 */ to_idx = checklist->count - 3; /* End identity check at G27 */ break; case USB_DEVICE_ID_LOGITECH_DFGT_WHEEL: @@ -1062,6 +1097,9 @@ static u16 lg4ff_identify_multimode_wheel(struct hid_device *hid, const u16 repo from_idx = 0; to_idx = checklist->count - 4; /* End identity check at DFGT */ break; + case USB_DEVICE_ID_LOGITECH_G29_WHEEL: + /* G29 can only be in native mode */ + return USB_DEVICE_ID_LOGITECH_G29_WHEEL; default: return 0; } @@ -1251,7 +1289,8 @@ int lg4ff_init(struct hid_device *hid) for (j = 0; j < 5; j++) entry->wdata.led[j] = NULL; - if (lg4ff_devices[i].product_id == USB_DEVICE_ID_LOGITECH_G27_WHEEL) { + if (lg4ff_devices[i].product_id == USB_DEVICE_ID_LOGITECH_G27_WHEEL || + lg4ff_devices[i].product_id == USB_DEVICE_ID_LOGITECH_G29_WHEEL) { struct led_classdev *led; size_t name_sz; char *name;