From patchwork Tue Dec 8 22:39:09 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gary Stein X-Patchwork-Id: 65826 Received: from vger.kernel.org (vger.kernel.org [209.132.176.167]) by demeter.kernel.org (8.14.2/8.14.2) with ESMTP id nB8MdFtZ002554 for ; Tue, 8 Dec 2009 22:39:15 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753285AbZLHWjH (ORCPT ); Tue, 8 Dec 2009 17:39:07 -0500 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1755619AbZLHWjH (ORCPT ); Tue, 8 Dec 2009 17:39:07 -0500 Received: from mail-fx0-f213.google.com ([209.85.220.213]:47475 "EHLO mail-fx0-f213.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753285AbZLHWjE (ORCPT ); Tue, 8 Dec 2009 17:39:04 -0500 Received: by fxm5 with SMTP id 5so6828387fxm.28 for ; Tue, 08 Dec 2009 14:39:09 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:mime-version:received:date:message-id:subject :from:to:cc:content-type; bh=2Y/YknPd2gAUuSQ3KKPDYrvSPIccFc/mHtG+KZC9P7g=; b=ku4RgUZZDg4Loh4QetXjFUAlUC0XZfPL2yyididqEI5pyL71DJWfqickYKRLlXUpZP +oRII3d7VUrlVogf27OJdpxcNjJl3HMFoWQPIdkR+7ZdVc9en+DsIivkixpbnLc4kXsn dJ7n73I8kSmmVD8RJa7zc/i+C4T5G86x65n3E= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=mime-version:date:message-id:subject:from:to:cc:content-type; b=ud09jRBt2H+TFgkNs3viZs9jsk6L33KeTYs9QYfkX5sfXubX/B+YUQEYi4pfWZAOgi d5pu7snG/gSBhNyliRjysXvjqE6wWYTpiUNjCNJz2pK4fSzyI0gxfE6Xu4xokGIhuJPn Vijt2Muqx3P2qIMw+v5DzveXyfcbsYl395FUA= MIME-Version: 1.0 Received: by 10.223.102.130 with SMTP id g2mr1319798fao.52.1260311949715; Tue, 08 Dec 2009 14:39:09 -0800 (PST) Date: Tue, 8 Dec 2009 17:39:09 -0500 Message-ID: Subject: [PATCH] Add Driver for Logitech Flight System G940 From: Gary Stein To: linux-input@vger.kernel.org Cc: jkosina@suse.cz, dmitry.torokhov@gmail.com Sender: linux-input-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-input@vger.kernel.org diff -uprN linux-2.6.31.orig/drivers/hid/Kconfig linux-2.6.31.next/drivers/hid/Kconfig --- linux-2.6.31.orig/drivers/hid/Kconfig 2009-09-09 17:13:59.000000000 -0500 +++ linux-2.6.31.next/drivers/hid/Kconfig 2009-12-01 12:29:44.000000000 -0500 @@ -190,6 +190,14 @@ config LOGIRUMBLEPAD2_FF Say Y here if you want to enable force feedback support for Logitech Rumblepad 2 devices. +config LOGIG940_FF + bool "Logitech Flight System G940 force feedback support" + depends on HID_LOGITECH + select INPUT_FF_MEMLESS + help + Say Y here if you want to enable force feedback support for Logitech + Flight System G940 devices. + config HID_MICROSOFT tristate "Microsoft" if EMBEDDED depends on USB_HID diff -uprN linux-2.6.31.orig/drivers/hid/Makefile linux-2.6.31.next/drivers/hid/Makefile --- linux-2.6.31.orig/drivers/hid/Makefile 2009-09-09 17:13:59.000000000 -0500 +++ linux-2.6.31.next/drivers/hid/Makefile 2009-12-01 12:29:44.000000000 -0500 @@ -15,6 +15,9 @@ endif ifdef CONFIG_LOGIRUMBLEPAD2_FF hid-logitech-objs += hid-lg2ff.o endif +ifdef CONFIG_LOGIG940_FF + hid-logitech-objs += hid-lg3ff.o +endif obj-$(CONFIG_HID_A4TECH) += hid-a4tech.o obj-$(CONFIG_HID_APPLE) += hid-apple.o diff -uprN linux-2.6.31.orig/drivers/hid/hid-core.c linux-2.6.31.next/drivers/hid/hid-core.c --- linux-2.6.31.orig/drivers/hid/hid-core.c 2009-09-09 17:13:59.000000000 -0500 +++ linux-2.6.31.next/drivers/hid/hid-core.c 2009-12-01 12:29:44.000000000 -0500 @@ -1293,6 +1293,7 @@ static const struct hid_device_id hid_bl { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_F3D) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FORCE3D_PRO) }, + { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FLIGHT_SYSTEM_G940) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G25_WHEEL) }, diff -uprN linux-2.6.31.orig/drivers/hid/hid-ids.h linux-2.6.31.next/drivers/hid/hid-ids.h --- linux-2.6.31.orig/drivers/hid/hid-ids.h 2009-09-09 17:13:59.000000000 -0500 +++ linux-2.6.31.next/drivers/hid/hid-ids.h 2009-12-01 12:29:44.000000000 -0500 @@ -295,6 +295,7 @@ #define USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2 0xc219 #define USB_DEVICE_ID_LOGITECH_WINGMAN_F3D 0xc283 #define USB_DEVICE_ID_LOGITECH_FORCE3D_PRO 0xc286 +#define USB_DEVICE_ID_LOGITECH_FLIGHT_SYSTEM_G940 0xc287 #define USB_DEVICE_ID_LOGITECH_WHEEL 0xc294 #define USB_DEVICE_ID_LOGITECH_MOMO_WHEEL 0xc295 #define USB_DEVICE_ID_LOGITECH_G25_WHEEL 0xc299 diff -uprN linux-2.6.31.orig/drivers/hid/hid-lg.c linux-2.6.31.next/drivers/hid/hid-lg.c --- linux-2.6.31.orig/drivers/hid/hid-lg.c 2009-09-09 17:13:59.000000000 -0500 +++ linux-2.6.31.next/drivers/hid/hid-lg.c 2009-12-01 12:29:44.000000000 -0500 @@ -33,6 +33,7 @@ #define LG_NOGET 0x100 #define LG_FF 0x200 #define LG_FF2 0x400 +#define LG_FF3 0x800 /* * Certain Logitech keyboards send in report #3 keys which are far @@ -238,7 +239,7 @@ static int lg_probe(struct hid_device *h goto err_free; } - if (quirks & (LG_FF | LG_FF2)) + if (quirks & (LG_FF | LG_FF2 | LG_FF3)) connect_mask &= ~HID_CONNECT_FF; ret = hid_hw_start(hdev, connect_mask); @@ -251,6 +252,8 @@ static int lg_probe(struct hid_device *h lgff_init(hdev); if (quirks & LG_FF2) lg2ff_init(hdev); + if (quirks & LG_FF3) + lg3ff_init(hdev); return 0; err_free: @@ -301,6 +304,8 @@ static const struct hid_device_id lg_dev .driver_data = LG_FF }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2), .driver_data = LG_FF2 }, + { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FLIGHT_SYSTEM_G940), + .driver_data = LG_FF3 }, { } }; MODULE_DEVICE_TABLE(hid, lg_devices); diff -uprN linux-2.6.31.orig/drivers/hid/hid-lg.h linux-2.6.31.next/drivers/hid/hid-lg.h --- linux-2.6.31.orig/drivers/hid/hid-lg.h 2009-09-09 17:13:59.000000000 -0500 +++ linux-2.6.31.next/drivers/hid/hid-lg.h 2009-12-01 12:29:44.000000000 -0500 @@ -15,4 +15,10 @@ int lg2ff_init(struct hid_device *hdev); static inline int lg2ff_init(struct hid_device *hdev) { return -1; } #endif +#ifdef CONFIG_LOGIG940_FF +int lg3ff_init(struct hid_device *hdev); +#else +static inline int lg3ff_init(struct hid_device *hdev) { return -1; } +#endif + #endif diff -uprN linux-2.6.31.orig/drivers/hid/hid-lg3ff.c linux-2.6.31.next/drivers/hid/hid-lg3ff.c --- linux-2.6.31.orig/drivers/hid/hid-lg3ff.c 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.6.31.next/drivers/hid/hid-lg3ff.c 2009-12-01 15:19:45.000000000 -0500 @@ -0,0 +1,202 @@ +/* + * Force feedback support for Logitech Flight System G940 + * + * Copyright (c) 2009 Gary Stein + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include +#include +#include + +#include "usbhid/usbhid.h" +#include "hid-lg.h" + +struct lg3ff_device { + struct hid_report *report; +}; + +static int hid_lg3ff_play(struct input_dev *dev, void *data, + struct ff_effect *effect) +{ + struct hid_device *hid = input_get_drvdata(dev); + struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; + struct hid_report *report = list_entry(report_list->next, struct hid_report, list); + int x, y; + +#define CLAMP(x) if (x < 0) x = 0; if (x > 0xff) x = 0xff + + //only constant supported + switch (effect->type) { + case FF_RAMP: + //these values are supposed to be -127 to 127 + x = effect->u.ramp.start_level; + y = effect->u.ramp.end_level; + + //There are 63 fields, only really figured out 3 of them + //0 - seems to be command field + //1 - 30 deal with the x axis? + //31 -60 deal with the y axis? + + //1 is x axis constant force + //31 is y axis constant force + + //other interesting things for fields 1,2,3,4 on x axis (same for 31,32,33,34 on y axis) + //0 0 127 127 makes the joystick autocenter hard + //127 0 127 127 makes the joystick loose on the right, but stops all movemnt left + //-127 0 -127 -127 makes the joystick loose on the left, but stops all movement right + //0 0 -127 -127 makes the joystick rattle very hard + + //I'm sure these are effects that I don't know enough about + + + memset(report->field[0]->value,0,sizeof(__s32)*63); + + report->field[0]->value[0] = 0x51; + + //which get recast here in two's complement 8 bits + report->field[0]->value[1]=(unsigned char)x; + + //pitch opposite of carteasian + report->field[0]->value[31]=(unsigned char)(-y); + + //printk("Size: %d %d\n",report->size,report->maxfield); + //printk("Field: %d %d\n",report->field[0]->report_size,report->field[0]->maxusage); + //Size: 504 1 + //Field: 8 63 + + //dbg_hid("(x, y)=(%04x, %04x)\n", x, y); + //printk("Custom (x, y)=(%04x, %04x)\n", x, y); + usbhid_submit_report(hid, report, USB_DIR_OUT); + break; + case FF_CONSTANT: + + //Already clamped in ff_memless + //0 is center + x = effect->u.ramp.start_level; + y = effect->u.ramp.end_level; + + memset(report->field[0]->value,0,sizeof(__s32)*63); + + report->field[0]->value[0] = 0x51; + + //sign backwards from other Force3d pro + + //which get recast here in two's complement 8 bits + report->field[0]->value[1]=(unsigned char)(-x); + + //pitch opposite of carteasian + report->field[0]->value[31]=(unsigned char)(-y); + + //printk("Size: %d %d\n",report->size,report->maxfield); + //printk("Field: %d %d\n",report->field[0]->report_size,report->field[0]->maxusage); + //Size: 504 1 + //Field: 8 63 + + //dbg_hid("(x, y)=(%04x, %04x)\n", x, y); + //printk("Custom (x, y)=(%04x, %04x)\n", x, y); + usbhid_submit_report(hid, report, USB_DIR_OUT); + break; + + default: + printk("FF Type Not Supported: %d\n",effect->type); + } + return 0; +} +static void hid_lg3ff_set_autocenter(struct input_dev *dev, u16 magnitude) +{ + struct hid_device *hid = input_get_drvdata(dev); + struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; + struct hid_report *report = list_entry(report_list->next, struct hid_report, list); + + report->field[0]->value[0] = 0x51; + report->field[0]->value[1] = 0x00; + report->field[0]->value[2] = 0x00; + report->field[0]->value[3] = 0x7F; + report->field[0]->value[4] = 0x7F; + report->field[0]->value[31] = 0x00; + report->field[0]->value[32] = 0x00; + report->field[0]->value[33] = 0x7F; + report->field[0]->value[34] = 0x7F; + + usbhid_submit_report(hid, report, USB_DIR_OUT); +} + + +static const signed short ff3_joystick_ac[] = { + FF_CONSTANT, + FF_RAMP, + FF_AUTOCENTER, + -1 +}; + +int lg3ff_init(struct hid_device* hid) +{ + struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list); + struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; + struct input_dev *dev = hidinput->input; + struct hid_report *report; + struct hid_field *field; + const signed short *ff_bits = ff3_joystick_ac; + int error; + int i; + + /* Find the report to use */ + if (list_empty(report_list)) { + err_hid("No output report found"); + return -1; + } + + /* Check that the report looks ok */ + report = list_entry(report_list->next, struct hid_report, list); + if (!report) { + err_hid("NULL output report"); + return -1; + } + + field = report->field[0]; + if (!field) { + err_hid("NULL field"); + return -1; + } + + //don't search + /*for (i = 0; i < ARRAY_SIZE(devices); i++) { + if (dev->id.vendor == devices[i].idVendor && + dev->id.product == devices[i].idProduct) { + ff_bits = devices[i].ff; + break; + } + }*/ + + for (i = 0; ff_bits[i] >= 0; i++) + set_bit(ff_bits[i], dev->ffbit); + + error = input_ff_create_memless(dev, NULL, hid_lg3ff_play); + if (error) + return error; + + if ( test_bit(FF_AUTOCENTER, dev->ffbit) ) + dev->ff->set_autocenter = hid_lg3ff_set_autocenter; + + dev_info(&hid->dev, "Force feedback for Logitech Flight System G940 by " + "Gary Stein \n"); + return 0; +} + diff -uprN linux-2.6.31.orig/drivers/hid/hid-lgff.c linux-2.6.31.next/drivers/hid/hid-lgff.c --- linux-2.6.31.orig/drivers/hid/hid-lgff.c 2009-09-09 17:13:59.000000000 -0500 +++ linux-2.6.31.next/drivers/hid/hid-lgff.c 2009-12-01 15:19:49.000000000 -0500 @@ -67,6 +67,7 @@ static const struct dev_type devices[] = { 0x046d, 0xc219, ff_rumble }, { 0x046d, 0xc283, ff_joystick }, { 0x046d, 0xc286, ff_joystick_ac }, + { 0x046d, 0xc287, ff_joystick_ac }, { 0x046d, 0xc294, ff_wheel }, { 0x046d, 0xc295, ff_joystick }, { 0x046d, 0xca03, ff_wheel }, @@ -95,7 +96,6 @@ static int hid_lgff_play(struct input_de dbg_hid("(x, y)=(%04x, %04x)\n", x, y); usbhid_submit_report(hid, report, USB_DIR_OUT); break; - case FF_RUMBLE: right = effect->u.rumble.strong_magnitude; left = effect->u.rumble.weak_magnitude;