linux/drivers/hid/hid-lg3ff.c
<<
>>
Prefs
   1/*
   2 *  Force feedback support for Logitech Flight System G940
   3 *
   4 *  Copyright (c) 2009 Gary Stein <LordCnidarian@gmail.com>
   5 */
   6
   7/*
   8 * This program is free software; you can redistribute it and/or modify
   9 * it under the terms of the GNU General Public License as published by
  10 * the Free Software Foundation; either version 2 of the License, or
  11 * (at your option) any later version.
  12 *
  13 * This program is distributed in the hope that it will be useful,
  14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16 * GNU General Public License for more details.
  17 *
  18 * You should have received a copy of the GNU General Public License
  19 * along with this program; if not, write to the Free Software
  20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  21 */
  22
  23
  24#include <linux/input.h>
  25#include <linux/hid.h>
  26
  27#include "hid-lg.h"
  28
  29/*
  30 * G940 Theory of Operation (from experimentation)
  31 *
  32 * There are 63 fields (only 3 of them currently used)
  33 * 0 - seems to be command field
  34 * 1 - 30 deal with the x axis
  35 * 31 -60 deal with the y axis
  36 *
  37 * Field 1 is x axis constant force
  38 * Field 31 is y axis constant force
  39 *
  40 * other interesting fields 1,2,3,4 on x axis
  41 * (same for 31,32,33,34 on y axis)
  42 *
  43 * 0 0 127 127 makes the joystick autocenter hard
  44 *
  45 * 127 0 127 127 makes the joystick loose on the right,
  46 * but stops all movemnt left
  47 *
  48 * -127 0 -127 -127 makes the joystick loose on the left,
  49 * but stops all movement right
  50 *
  51 * 0 0 -127 -127 makes the joystick rattle very hard
  52 *
  53 * I'm sure these are effects that I don't know enough about them
  54 */
  55
  56struct lg3ff_device {
  57        struct hid_report *report;
  58};
  59
  60static int hid_lg3ff_play(struct input_dev *dev, void *data,
  61                         struct ff_effect *effect)
  62{
  63        struct hid_device *hid = input_get_drvdata(dev);
  64        struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
  65        struct hid_report *report = list_entry(report_list->next, struct hid_report, list);
  66        int x, y;
  67
  68/*
  69 * Maxusage should always be 63 (maximum fields)
  70 * likely a better way to ensure this data is clean
  71 */
  72        memset(report->field[0]->value, 0, sizeof(__s32)*report->field[0]->maxusage);
  73
  74        switch (effect->type) {
  75        case FF_CONSTANT:
  76/*
  77 * Already clamped in ff_memless
  78 * 0 is center (different then other logitech)
  79 */
  80                x = effect->u.ramp.start_level;
  81                y = effect->u.ramp.end_level;
  82
  83                /* send command byte */
  84                report->field[0]->value[0] = 0x51;
  85
  86/*
  87 * Sign backwards from other Force3d pro
  88 * which get recast here in two's complement 8 bits
  89 */
  90                report->field[0]->value[1] = (unsigned char)(-x);
  91                report->field[0]->value[31] = (unsigned char)(-y);
  92
  93                hid_hw_request(hid, report, HID_REQ_SET_REPORT);
  94                break;
  95        }
  96        return 0;
  97}
  98static void hid_lg3ff_set_autocenter(struct input_dev *dev, u16 magnitude)
  99{
 100        struct hid_device *hid = input_get_drvdata(dev);
 101        struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
 102        struct hid_report *report = list_entry(report_list->next, struct hid_report, list);
 103
 104/*
 105 * Auto Centering probed from device
 106 * NOTE: deadman's switch on G940 must be covered
 107 * for effects to work
 108 */
 109        report->field[0]->value[0] = 0x51;
 110        report->field[0]->value[1] = 0x00;
 111        report->field[0]->value[2] = 0x00;
 112        report->field[0]->value[3] = 0x7F;
 113        report->field[0]->value[4] = 0x7F;
 114        report->field[0]->value[31] = 0x00;
 115        report->field[0]->value[32] = 0x00;
 116        report->field[0]->value[33] = 0x7F;
 117        report->field[0]->value[34] = 0x7F;
 118
 119        hid_hw_request(hid, report, HID_REQ_SET_REPORT);
 120}
 121
 122
 123static const signed short ff3_joystick_ac[] = {
 124        FF_CONSTANT,
 125        FF_AUTOCENTER,
 126        -1
 127};
 128
 129int lg3ff_init(struct hid_device *hid)
 130{
 131        struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list);
 132        struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
 133        struct input_dev *dev = hidinput->input;
 134        struct hid_report *report;
 135        struct hid_field *field;
 136        const signed short *ff_bits = ff3_joystick_ac;
 137        int error;
 138        int i;
 139
 140        /* Find the report to use */
 141        if (list_empty(report_list)) {
 142                hid_err(hid, "No output report found\n");
 143                return -1;
 144        }
 145
 146        /* Check that the report looks ok */
 147        report = list_entry(report_list->next, struct hid_report, list);
 148        if (!report) {
 149                hid_err(hid, "NULL output report\n");
 150                return -1;
 151        }
 152
 153        field = report->field[0];
 154        if (!field) {
 155                hid_err(hid, "NULL field\n");
 156                return -1;
 157        }
 158
 159        /* Assume single fixed device G940 */
 160        for (i = 0; ff_bits[i] >= 0; i++)
 161                set_bit(ff_bits[i], dev->ffbit);
 162
 163        error = input_ff_create_memless(dev, NULL, hid_lg3ff_play);
 164        if (error)
 165                return error;
 166
 167        if (test_bit(FF_AUTOCENTER, dev->ffbit))
 168                dev->ff->set_autocenter = hid_lg3ff_set_autocenter;
 169
 170        hid_info(hid, "Force feedback for Logitech Flight System G940 by Gary Stein <LordCnidarian@gmail.com>\n");
 171        return 0;
 172}
 173
 174
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.