aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Wood <simon@mungewell.org>2015-11-02 09:56:52 -0500
committerJiri Kosina <jkosina@suse.cz>2015-11-06 15:18:06 -0500
commit29fae1c85166ef525b8b6518e749295e0c9d1e20 (patch)
tree709315d3d46ca1c33de9e4a681e70d93e1e99e64
parentbbec1bd0faa211a0a0abaf947cd4a236d080ad28 (diff)
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 <simon@mungewell.org> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
-rw-r--r--drivers/hid/hid-core.c1
-rw-r--r--drivers/hid/hid-lg.c9
-rw-r--r--drivers/hid/hid-lg4ff.c57
3 files changed, 63 insertions, 4 deletions
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index bcd914a63af2..1ec2bea39d9a 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1896,6 +1896,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
1896 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD_CORD) }, 1896 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD_CORD) },
1897 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD) }, 1897 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD) },
1898 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2) }, 1898 { 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) },
1899 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_F3D) }, 1900 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_F3D) },
1900 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FFG ) }, 1901 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FFG ) },
1901 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FORCE3D_PRO) }, 1902 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FORCE3D_PRO) },
diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c
index 5332fb7d072a..c20ac76c0a8c 100644
--- a/drivers/hid/hid-lg.c
+++ b/drivers/hid/hid-lg.c
@@ -620,6 +620,7 @@ static int lg_input_mapped(struct hid_device *hdev, struct hid_input *hi,
620 usage->code == ABS_Y || usage->code == ABS_Z || 620 usage->code == ABS_Y || usage->code == ABS_Z ||
621 usage->code == ABS_RZ)) { 621 usage->code == ABS_RZ)) {
622 switch (hdev->product) { 622 switch (hdev->product) {
623 case USB_DEVICE_ID_LOGITECH_G29_WHEEL:
623 case USB_DEVICE_ID_LOGITECH_WHEEL: 624 case USB_DEVICE_ID_LOGITECH_WHEEL:
624 case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL: 625 case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL:
625 case USB_DEVICE_ID_LOGITECH_DFP_WHEEL: 626 case USB_DEVICE_ID_LOGITECH_DFP_WHEEL:
@@ -658,10 +659,18 @@ static int lg_event(struct hid_device *hdev, struct hid_field *field,
658 659
659static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id) 660static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
660{ 661{
662 struct usb_interface *iface = to_usb_interface(hdev->dev.parent);
663 __u8 iface_num = iface->cur_altsetting->desc.bInterfaceNumber;
661 unsigned int connect_mask = HID_CONNECT_DEFAULT; 664 unsigned int connect_mask = HID_CONNECT_DEFAULT;
662 struct lg_drv_data *drv_data; 665 struct lg_drv_data *drv_data;
663 int ret; 666 int ret;
664 667
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
665 drv_data = kzalloc(sizeof(struct lg_drv_data), GFP_KERNEL); 674 drv_data = kzalloc(sizeof(struct lg_drv_data), GFP_KERNEL);
666 if (!drv_data) { 675 if (!drv_data) {
667 hid_err(hdev, "Insufficient memory, cannot allocate driver data\n"); 676 hid_err(hdev, "Insufficient memory, cannot allocate driver data\n");
diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c
index b363d88267c2..fbddcb37ae98 100644
--- a/drivers/hid/hid-lg4ff.c
+++ b/drivers/hid/hid-lg4ff.c
@@ -45,7 +45,8 @@
45#define LG4FF_MODE_G25_IDX 3 45#define LG4FF_MODE_G25_IDX 3
46#define LG4FF_MODE_DFGT_IDX 4 46#define LG4FF_MODE_DFGT_IDX 4
47#define LG4FF_MODE_G27_IDX 5 47#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
49 50
50#define LG4FF_MODE_NATIVE BIT(LG4FF_MODE_NATIVE_IDX) 51#define LG4FF_MODE_NATIVE BIT(LG4FF_MODE_NATIVE_IDX)
51#define LG4FF_MODE_DFEX BIT(LG4FF_MODE_DFEX_IDX) 52#define LG4FF_MODE_DFEX BIT(LG4FF_MODE_DFEX_IDX)
@@ -53,6 +54,7 @@
53#define LG4FF_MODE_G25 BIT(LG4FF_MODE_G25_IDX) 54#define LG4FF_MODE_G25 BIT(LG4FF_MODE_G25_IDX)
54#define LG4FF_MODE_DFGT BIT(LG4FF_MODE_DFGT_IDX) 55#define LG4FF_MODE_DFGT BIT(LG4FF_MODE_DFGT_IDX)
55#define LG4FF_MODE_G27 BIT(LG4FF_MODE_G27_IDX) 56#define LG4FF_MODE_G27 BIT(LG4FF_MODE_G27_IDX)
57#define LG4FF_MODE_G29 BIT(LG4FF_MODE_G29_IDX)
56 58
57#define LG4FF_DFEX_TAG "DF-EX" 59#define LG4FF_DFEX_TAG "DF-EX"
58#define LG4FF_DFEX_NAME "Driving Force / Formula EX" 60#define LG4FF_DFEX_NAME "Driving Force / Formula EX"
@@ -62,6 +64,8 @@
62#define LG4FF_G25_NAME "G25 Racing Wheel" 64#define LG4FF_G25_NAME "G25 Racing Wheel"
63#define LG4FF_G27_TAG "G27" 65#define LG4FF_G27_TAG "G27"
64#define LG4FF_G27_NAME "G27 Racing Wheel" 66#define LG4FF_G27_NAME "G27 Racing Wheel"
67#define LG4FF_G29_TAG "G29"
68#define LG4FF_G29_NAME "G29 Racing Wheel"
65#define LG4FF_DFGT_TAG "DFGT" 69#define LG4FF_DFGT_TAG "DFGT"
66#define LG4FF_DFGT_NAME "Driving Force GT" 70#define LG4FF_DFGT_NAME "Driving Force GT"
67 71
@@ -140,6 +144,7 @@ static const struct lg4ff_wheel lg4ff_devices[] = {
140 {USB_DEVICE_ID_LOGITECH_G25_WHEEL, lg4ff_wheel_effects, 40, 900, lg4ff_set_range_g25}, 144 {USB_DEVICE_ID_LOGITECH_G25_WHEEL, lg4ff_wheel_effects, 40, 900, lg4ff_set_range_g25},
141 {USB_DEVICE_ID_LOGITECH_DFGT_WHEEL, lg4ff_wheel_effects, 40, 900, lg4ff_set_range_g25}, 145 {USB_DEVICE_ID_LOGITECH_DFGT_WHEEL, lg4ff_wheel_effects, 40, 900, lg4ff_set_range_g25},
142 {USB_DEVICE_ID_LOGITECH_G27_WHEEL, lg4ff_wheel_effects, 40, 900, lg4ff_set_range_g25}, 146 {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},
143 {USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2, lg4ff_wheel_effects, 40, 270, NULL}, 148 {USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2, lg4ff_wheel_effects, 40, 270, NULL},
144 {USB_DEVICE_ID_LOGITECH_WII_WHEEL, lg4ff_wheel_effects, 40, 270, NULL} 149 {USB_DEVICE_ID_LOGITECH_WII_WHEEL, lg4ff_wheel_effects, 40, 270, NULL}
145}; 150};
@@ -157,6 +162,9 @@ static const struct lg4ff_multimode_wheel lg4ff_multimode_wheels[] = {
157 {USB_DEVICE_ID_LOGITECH_G27_WHEEL, 162 {USB_DEVICE_ID_LOGITECH_G27_WHEEL,
158 LG4FF_MODE_NATIVE | LG4FF_MODE_G27 | LG4FF_MODE_G25 | LG4FF_MODE_DFP | LG4FF_MODE_DFEX, 163 LG4FF_MODE_NATIVE | LG4FF_MODE_G27 | LG4FF_MODE_G25 | LG4FF_MODE_DFP | LG4FF_MODE_DFEX,
159 LG4FF_G27_TAG, LG4FF_G27_NAME}, 164 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},
160}; 168};
161 169
162static const struct lg4ff_alternate_mode lg4ff_alternate_modes[] = { 170static const struct lg4ff_alternate_mode lg4ff_alternate_modes[] = {
@@ -165,7 +173,8 @@ static const struct lg4ff_alternate_mode lg4ff_alternate_modes[] = {
165 [LG4FF_MODE_DFP_IDX] = {USB_DEVICE_ID_LOGITECH_DFP_WHEEL, LG4FF_DFP_TAG, LG4FF_DFP_NAME}, 173 [LG4FF_MODE_DFP_IDX] = {USB_DEVICE_ID_LOGITECH_DFP_WHEEL, LG4FF_DFP_TAG, LG4FF_DFP_NAME},
166 [LG4FF_MODE_G25_IDX] = {USB_DEVICE_ID_LOGITECH_G25_WHEEL, LG4FF_G25_TAG, LG4FF_G25_NAME}, 174 [LG4FF_MODE_G25_IDX] = {USB_DEVICE_ID_LOGITECH_G25_WHEEL, LG4FF_G25_TAG, LG4FF_G25_NAME},
167 [LG4FF_MODE_DFGT_IDX] = {USB_DEVICE_ID_LOGITECH_DFGT_WHEEL, LG4FF_DFGT_TAG, LG4FF_DFGT_NAME}, 175 [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},
169}; 178};
170 179
171/* Multimode wheel identificators */ 180/* Multimode wheel identificators */
@@ -197,8 +206,24 @@ static const struct lg4ff_wheel_ident_info lg4ff_dfgt_ident_info = {
197 USB_DEVICE_ID_LOGITECH_DFGT_WHEEL 206 USB_DEVICE_ID_LOGITECH_DFGT_WHEEL
198}; 207};
199 208
209static 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
216static 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
200/* Multimode wheel identification checklists */ 223/* Multimode wheel identification checklists */
201static const struct lg4ff_wheel_ident_info *lg4ff_main_checklist[] = { 224static const struct lg4ff_wheel_ident_info *lg4ff_main_checklist[] = {
225 &lg4ff_g29_ident_info,
226 &lg4ff_g29_ident_info2,
202 &lg4ff_dfgt_ident_info, 227 &lg4ff_dfgt_ident_info,
203 &lg4ff_g27_ident_info, 228 &lg4ff_g27_ident_info,
204 &lg4ff_g25_ident_info, 229 &lg4ff_g25_ident_info,
@@ -237,6 +262,12 @@ static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_ext09_g27 = {
237 0xf8, 0x09, 0x04, 0x01, 0x00, 0x00, 0x00} /* Switch mode to G27 with detach */ 262 0xf8, 0x09, 0x04, 0x01, 0x00, 0x00, 0x00} /* Switch mode to G27 with detach */
238}; 263};
239 264
265static 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
240/* EXT_CMD1 - Understood by DFP, G25, G27 and DFGT */ 271/* EXT_CMD1 - Understood by DFP, G25, G27 and DFGT */
241static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_ext01_dfp = { 272static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_ext01_dfp = {
242 1, 273 1,
@@ -650,6 +681,23 @@ static const struct lg4ff_compat_mode_switch *lg4ff_get_mode_switch_command(cons
650 return NULL; 681 return NULL;
651 } 682 }
652 break; 683 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;
653 case USB_DEVICE_ID_LOGITECH_DFGT_WHEEL: 701 case USB_DEVICE_ID_LOGITECH_DFGT_WHEEL:
654 switch (target_product_id) { 702 switch (target_product_id) {
655 case USB_DEVICE_ID_LOGITECH_WHEEL: 703 case USB_DEVICE_ID_LOGITECH_WHEEL:
@@ -1232,12 +1280,13 @@ int lg4ff_init(struct hid_device *hid)
1232 entry->wdata.set_range(hid, entry->wdata.range); 1280 entry->wdata.set_range(hid, entry->wdata.range);
1233 1281
1234#ifdef CONFIG_LEDS_CLASS 1282#ifdef CONFIG_LEDS_CLASS
1235 /* register led subsystem - G27 only */ 1283 /* register led subsystem - G27/G29 only */
1236 entry->wdata.led_state = 0; 1284 entry->wdata.led_state = 0;
1237 for (j = 0; j < 5; j++) 1285 for (j = 0; j < 5; j++)
1238 entry->wdata.led[j] = NULL; 1286 entry->wdata.led[j] = NULL;
1239 1287
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) {
1241 struct led_classdev *led; 1290 struct led_classdev *led;
1242 size_t name_sz; 1291 size_t name_sz;
1243 char *name; 1292 char *name;