linux/drivers/hid/hid-lg4ff.c
<<
>>
Prefs
   1/*
   2 *  Force feedback support for Logitech Gaming Wheels
   3 *
   4 *  Including G27, G25, DFP, DFGT, FFEX, Momo, Momo2 &
   5 *  Speed Force Wireless (WiiWheel)
   6 *
   7 *  Copyright (c) 2010 Simon Wood <simon@mungewell.org>
   8 */
   9
  10/*
  11 * This program is free software; you can redistribute it and/or modify
  12 * it under the terms of the GNU General Public License as published by
  13 * the Free Software Foundation; either version 2 of the License, or
  14 * (at your option) any later version.
  15 *
  16 * This program is distributed in the hope that it will be useful,
  17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19 * GNU General Public License for more details.
  20 *
  21 * You should have received a copy of the GNU General Public License
  22 * along with this program; if not, write to the Free Software
  23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  24 */
  25
  26
  27#include <linux/input.h>
  28#include <linux/usb.h>
  29#include <linux/hid.h>
  30
  31#include "usbhid/usbhid.h"
  32#include "hid-lg.h"
  33#include "hid-lg4ff.h"
  34#include "hid-ids.h"
  35
  36#define LG4FF_MMODE_IS_MULTIMODE 0
  37#define LG4FF_MMODE_SWITCHED 1
  38#define LG4FF_MMODE_NOT_MULTIMODE 2
  39
  40#define LG4FF_MODE_NATIVE_IDX 0
  41#define LG4FF_MODE_DFEX_IDX 1
  42#define LG4FF_MODE_DFP_IDX 2
  43#define LG4FF_MODE_G25_IDX 3
  44#define LG4FF_MODE_DFGT_IDX 4
  45#define LG4FF_MODE_G27_IDX 5
  46#define LG4FF_MODE_G29_IDX 6
  47#define LG4FF_MODE_MAX_IDX 7
  48
  49#define LG4FF_MODE_NATIVE BIT(LG4FF_MODE_NATIVE_IDX)
  50#define LG4FF_MODE_DFEX BIT(LG4FF_MODE_DFEX_IDX)
  51#define LG4FF_MODE_DFP BIT(LG4FF_MODE_DFP_IDX)
  52#define LG4FF_MODE_G25 BIT(LG4FF_MODE_G25_IDX)
  53#define LG4FF_MODE_DFGT BIT(LG4FF_MODE_DFGT_IDX)
  54#define LG4FF_MODE_G27 BIT(LG4FF_MODE_G27_IDX)
  55#define LG4FF_MODE_G29 BIT(LG4FF_MODE_G29_IDX)
  56
  57#define LG4FF_DFEX_TAG "DF-EX"
  58#define LG4FF_DFEX_NAME "Driving Force / Formula EX"
  59#define LG4FF_DFP_TAG "DFP"
  60#define LG4FF_DFP_NAME "Driving Force Pro"
  61#define LG4FF_G25_TAG "G25"
  62#define LG4FF_G25_NAME "G25 Racing Wheel"
  63#define LG4FF_G27_TAG "G27"
  64#define LG4FF_G27_NAME "G27 Racing Wheel"
  65#define LG4FF_G29_TAG "G29"
  66#define LG4FF_G29_NAME "G29 Racing Wheel"
  67#define LG4FF_DFGT_TAG "DFGT"
  68#define LG4FF_DFGT_NAME "Driving Force GT"
  69
  70#define LG4FF_FFEX_REV_MAJ 0x21
  71#define LG4FF_FFEX_REV_MIN 0x00
  72
  73static void lg4ff_set_range_dfp(struct hid_device *hid, u16 range);
  74static void lg4ff_set_range_g25(struct hid_device *hid, u16 range);
  75
  76struct lg4ff_wheel_data {
  77        const u32 product_id;
  78        u16 combine;
  79        u16 range;
  80        const u16 min_range;
  81        const u16 max_range;
  82#ifdef CONFIG_LEDS_CLASS
  83        u8  led_state;
  84        struct led_classdev *led[5];
  85#endif
  86        const u32 alternate_modes;
  87        const char * const real_tag;
  88        const char * const real_name;
  89        const u16 real_product_id;
  90
  91        void (*set_range)(struct hid_device *hid, u16 range);
  92};
  93
  94struct lg4ff_device_entry {
  95        spinlock_t report_lock; /* Protect output HID report */
  96        struct hid_report *report;
  97        struct lg4ff_wheel_data wdata;
  98};
  99
 100static const signed short lg4ff_wheel_effects[] = {
 101        FF_CONSTANT,
 102        FF_AUTOCENTER,
 103        -1
 104};
 105
 106struct lg4ff_wheel {
 107        const u32 product_id;
 108        const signed short *ff_effects;
 109        const u16 min_range;
 110        const u16 max_range;
 111        void (*set_range)(struct hid_device *hid, u16 range);
 112};
 113
 114struct lg4ff_compat_mode_switch {
 115        const u8 cmd_count;     /* Number of commands to send */
 116        const u8 cmd[];
 117};
 118
 119struct lg4ff_wheel_ident_info {
 120        const u32 modes;
 121        const u16 mask;
 122        const u16 result;
 123        const u16 real_product_id;
 124};
 125
 126struct lg4ff_multimode_wheel {
 127        const u16 product_id;
 128        const u32 alternate_modes;
 129        const char *real_tag;
 130        const char *real_name;
 131};
 132
 133struct lg4ff_alternate_mode {
 134        const u16 product_id;
 135        const char *tag;
 136        const char *name;
 137};
 138
 139static const struct lg4ff_wheel lg4ff_devices[] = {
 140        {USB_DEVICE_ID_LOGITECH_WINGMAN_FFG, lg4ff_wheel_effects, 40, 180, NULL},
 141        {USB_DEVICE_ID_LOGITECH_WHEEL,       lg4ff_wheel_effects, 40, 270, NULL},
 142        {USB_DEVICE_ID_LOGITECH_MOMO_WHEEL,  lg4ff_wheel_effects, 40, 270, NULL},
 143        {USB_DEVICE_ID_LOGITECH_DFP_WHEEL,   lg4ff_wheel_effects, 40, 900, lg4ff_set_range_dfp},
 144        {USB_DEVICE_ID_LOGITECH_G25_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},
 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},
 148        {USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2, lg4ff_wheel_effects, 40, 270, NULL},
 149        {USB_DEVICE_ID_LOGITECH_WII_WHEEL,   lg4ff_wheel_effects, 40, 270, NULL}
 150};
 151
 152static const struct lg4ff_multimode_wheel lg4ff_multimode_wheels[] = {
 153        {USB_DEVICE_ID_LOGITECH_DFP_WHEEL,
 154         LG4FF_MODE_NATIVE | LG4FF_MODE_DFP | LG4FF_MODE_DFEX,
 155         LG4FF_DFP_TAG, LG4FF_DFP_NAME},
 156        {USB_DEVICE_ID_LOGITECH_G25_WHEEL,
 157         LG4FF_MODE_NATIVE | LG4FF_MODE_G25 | LG4FF_MODE_DFP | LG4FF_MODE_DFEX,
 158         LG4FF_G25_TAG, LG4FF_G25_NAME},
 159        {USB_DEVICE_ID_LOGITECH_DFGT_WHEEL,
 160         LG4FF_MODE_NATIVE | LG4FF_MODE_DFGT | LG4FF_MODE_DFP | LG4FF_MODE_DFEX,
 161         LG4FF_DFGT_TAG, LG4FF_DFGT_NAME},
 162        {USB_DEVICE_ID_LOGITECH_G27_WHEEL,
 163         LG4FF_MODE_NATIVE | LG4FF_MODE_G27 | LG4FF_MODE_G25 | LG4FF_MODE_DFP | LG4FF_MODE_DFEX,
 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},
 168};
 169
 170static const struct lg4ff_alternate_mode lg4ff_alternate_modes[] = {
 171        [LG4FF_MODE_NATIVE_IDX] = {0, "native", ""},
 172        [LG4FF_MODE_DFEX_IDX] = {USB_DEVICE_ID_LOGITECH_WHEEL, LG4FF_DFEX_TAG, LG4FF_DFEX_NAME},
 173        [LG4FF_MODE_DFP_IDX] = {USB_DEVICE_ID_LOGITECH_DFP_WHEEL, LG4FF_DFP_TAG, LG4FF_DFP_NAME},
 174        [LG4FF_MODE_G25_IDX] = {USB_DEVICE_ID_LOGITECH_G25_WHEEL, LG4FF_G25_TAG, LG4FF_G25_NAME},
 175        [LG4FF_MODE_DFGT_IDX] = {USB_DEVICE_ID_LOGITECH_DFGT_WHEEL, LG4FF_DFGT_TAG, LG4FF_DFGT_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},
 178};
 179
 180/* Multimode wheel identificators */
 181static const struct lg4ff_wheel_ident_info lg4ff_dfp_ident_info = {
 182        LG4FF_MODE_DFP | LG4FF_MODE_DFEX,
 183        0xf000,
 184        0x1000,
 185        USB_DEVICE_ID_LOGITECH_DFP_WHEEL
 186};
 187
 188static const struct lg4ff_wheel_ident_info lg4ff_g25_ident_info = {
 189        LG4FF_MODE_G25 | LG4FF_MODE_DFP | LG4FF_MODE_DFEX,
 190        0xff00,
 191        0x1200,
 192        USB_DEVICE_ID_LOGITECH_G25_WHEEL
 193};
 194
 195static const struct lg4ff_wheel_ident_info lg4ff_g27_ident_info = {
 196        LG4FF_MODE_G27 | LG4FF_MODE_G25 | LG4FF_MODE_DFP | LG4FF_MODE_DFEX,
 197        0xfff0,
 198        0x1230,
 199        USB_DEVICE_ID_LOGITECH_G27_WHEEL
 200};
 201
 202static const struct lg4ff_wheel_ident_info lg4ff_dfgt_ident_info = {
 203        LG4FF_MODE_DFGT | LG4FF_MODE_DFP | LG4FF_MODE_DFEX,
 204        0xff00,
 205        0x1300,
 206        USB_DEVICE_ID_LOGITECH_DFGT_WHEEL
 207};
 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
 223/* Multimode wheel identification checklists */
 224static const struct lg4ff_wheel_ident_info *lg4ff_main_checklist[] = {
 225        &lg4ff_g29_ident_info,
 226        &lg4ff_g29_ident_info2,
 227        &lg4ff_dfgt_ident_info,
 228        &lg4ff_g27_ident_info,
 229        &lg4ff_g25_ident_info,
 230        &lg4ff_dfp_ident_info
 231};
 232
 233/* Compatibility mode switching commands */
 234/* EXT_CMD9 - Understood by G27 and DFGT */
 235static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_ext09_dfex = {
 236        2,
 237        {0xf8, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,      /* Revert mode upon USB reset */
 238         0xf8, 0x09, 0x00, 0x01, 0x00, 0x00, 0x00}      /* Switch mode to DF-EX with detach */
 239};
 240
 241static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_ext09_dfp = {
 242        2,
 243        {0xf8, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,      /* Revert mode upon USB reset */
 244         0xf8, 0x09, 0x01, 0x01, 0x00, 0x00, 0x00}      /* Switch mode to DFP with detach */
 245};
 246
 247static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_ext09_g25 = {
 248        2,
 249        {0xf8, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,      /* Revert mode upon USB reset */
 250         0xf8, 0x09, 0x02, 0x01, 0x00, 0x00, 0x00}      /* Switch mode to G25 with detach */
 251};
 252
 253static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_ext09_dfgt = {
 254        2,
 255        {0xf8, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,      /* Revert mode upon USB reset */
 256         0xf8, 0x09, 0x03, 0x01, 0x00, 0x00, 0x00}      /* Switch mode to DFGT with detach */
 257};
 258
 259static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_ext09_g27 = {
 260        2,
 261        {0xf8, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,      /* Revert mode upon USB reset */
 262         0xf8, 0x09, 0x04, 0x01, 0x00, 0x00, 0x00}      /* Switch mode to G27 with detach */
 263};
 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
 271/* EXT_CMD1 - Understood by DFP, G25, G27 and DFGT */
 272static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_ext01_dfp = {
 273        1,
 274        {0xf8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00}
 275};
 276
 277/* EXT_CMD16 - Understood by G25 and G27 */
 278static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_ext16_g25 = {
 279        1,
 280        {0xf8, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00}
 281};
 282
 283/* Recalculates X axis value accordingly to currently selected range */
 284static s32 lg4ff_adjust_dfp_x_axis(s32 value, u16 range)
 285{
 286        u16 max_range;
 287        s32 new_value;
 288
 289        if (range == 900)
 290                return value;
 291        else if (range == 200)
 292                return value;
 293        else if (range < 200)
 294                max_range = 200;
 295        else
 296                max_range = 900;
 297
 298        new_value = 8192 + mult_frac(value - 8192, max_range, range);
 299        if (new_value < 0)
 300                return 0;
 301        else if (new_value > 16383)
 302                return 16383;
 303        else
 304                return new_value;
 305}
 306
 307int lg4ff_adjust_input_event(struct hid_device *hid, struct hid_field *field,
 308                             struct hid_usage *usage, s32 value, struct lg_drv_data *drv_data)
 309{
 310        struct lg4ff_device_entry *entry = drv_data->device_props;
 311        s32 new_value = 0;
 312
 313        if (!entry) {
 314                hid_err(hid, "Device properties not found");
 315                return 0;
 316        }
 317
 318        switch (entry->wdata.product_id) {
 319        case USB_DEVICE_ID_LOGITECH_DFP_WHEEL:
 320                switch (usage->code) {
 321                case ABS_X:
 322                        new_value = lg4ff_adjust_dfp_x_axis(value, entry->wdata.range);
 323                        input_event(field->hidinput->input, usage->type, usage->code, new_value);
 324                        return 1;
 325                default:
 326                        return 0;
 327                }
 328        default:
 329                return 0;
 330        }
 331}
 332
 333int lg4ff_raw_event(struct hid_device *hdev, struct hid_report *report,
 334                u8 *rd, int size, struct lg_drv_data *drv_data)
 335{
 336        int offset;
 337        struct lg4ff_device_entry *entry = drv_data->device_props;
 338
 339        if (!entry)
 340                return 0;
 341
 342        /* adjust HID report present combined pedals data */
 343        if (entry->wdata.combine) {
 344                switch (entry->wdata.product_id) {
 345                case USB_DEVICE_ID_LOGITECH_WHEEL:
 346                        rd[5] = rd[3];
 347                        rd[6] = 0x7F;
 348                        return 1;
 349                case USB_DEVICE_ID_LOGITECH_WINGMAN_FFG:
 350                case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL:
 351                case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2:
 352                        rd[4] = rd[3];
 353                        rd[5] = 0x7F;
 354                        return 1;
 355                case USB_DEVICE_ID_LOGITECH_DFP_WHEEL:
 356                        rd[5] = rd[4];
 357                        rd[6] = 0x7F;
 358                        return 1;
 359                case USB_DEVICE_ID_LOGITECH_G25_WHEEL:
 360                case USB_DEVICE_ID_LOGITECH_G27_WHEEL:
 361                        offset = 5;
 362                        break;
 363                case USB_DEVICE_ID_LOGITECH_DFGT_WHEEL:
 364                case USB_DEVICE_ID_LOGITECH_G29_WHEEL:
 365                        offset = 6;
 366                        break;
 367                case USB_DEVICE_ID_LOGITECH_WII_WHEEL:
 368                        offset = 3;
 369                        break;
 370                default:
 371                        return 0;
 372                }
 373
 374                /* Compute a combined axis when wheel does not supply it */
 375                rd[offset] = (0xFF + rd[offset] - rd[offset+1]) >> 1;
 376                rd[offset+1] = 0x7F;
 377                return 1;
 378        }
 379
 380        return 0;
 381}
 382
 383static void lg4ff_init_wheel_data(struct lg4ff_wheel_data * const wdata, const struct lg4ff_wheel *wheel,
 384                                  const struct lg4ff_multimode_wheel *mmode_wheel,
 385                                  const u16 real_product_id)
 386{
 387        u32 alternate_modes = 0;
 388        const char *real_tag = NULL;
 389        const char *real_name = NULL;
 390
 391        if (mmode_wheel) {
 392                alternate_modes = mmode_wheel->alternate_modes;
 393                real_tag = mmode_wheel->real_tag;
 394                real_name = mmode_wheel->real_name;
 395        }
 396
 397        {
 398                struct lg4ff_wheel_data t_wdata =  { .product_id = wheel->product_id,
 399                                                     .real_product_id = real_product_id,
 400                                                     .combine = 0,
 401                                                     .min_range = wheel->min_range,
 402                                                     .max_range = wheel->max_range,
 403                                                     .set_range = wheel->set_range,
 404                                                     .alternate_modes = alternate_modes,
 405                                                     .real_tag = real_tag,
 406                                                     .real_name = real_name };
 407
 408                memcpy(wdata, &t_wdata, sizeof(t_wdata));
 409        }
 410}
 411
 412static int lg4ff_play(struct input_dev *dev, void *data, struct ff_effect *effect)
 413{
 414        struct hid_device *hid = input_get_drvdata(dev);
 415        struct lg4ff_device_entry *entry;
 416        struct lg_drv_data *drv_data;
 417        unsigned long flags;
 418        s32 *value;
 419        int x;
 420
 421        drv_data = hid_get_drvdata(hid);
 422        if (!drv_data) {
 423                hid_err(hid, "Private driver data not found!\n");
 424                return -EINVAL;
 425        }
 426
 427        entry = drv_data->device_props;
 428        if (!entry) {
 429                hid_err(hid, "Device properties not found!\n");
 430                return -EINVAL;
 431        }
 432        value = entry->report->field[0]->value;
 433
 434#define CLAMP(x) do { if (x < 0) x = 0; else if (x > 0xff) x = 0xff; } while (0)
 435
 436        switch (effect->type) {
 437        case FF_CONSTANT:
 438                x = effect->u.ramp.start_level + 0x80;  /* 0x80 is no force */
 439                CLAMP(x);
 440
 441                spin_lock_irqsave(&entry->report_lock, flags);
 442                if (x == 0x80) {
 443                        /* De-activate force in slot-1*/
 444                        value[0] = 0x13;
 445                        value[1] = 0x00;
 446                        value[2] = 0x00;
 447                        value[3] = 0x00;
 448                        value[4] = 0x00;
 449                        value[5] = 0x00;
 450                        value[6] = 0x00;
 451
 452                        hid_hw_request(hid, entry->report, HID_REQ_SET_REPORT);
 453                        spin_unlock_irqrestore(&entry->report_lock, flags);
 454                        return 0;
 455                }
 456
 457                value[0] = 0x11;        /* Slot 1 */
 458                value[1] = 0x08;
 459                value[2] = x;
 460                value[3] = 0x80;
 461                value[4] = 0x00;
 462                value[5] = 0x00;
 463                value[6] = 0x00;
 464
 465                hid_hw_request(hid, entry->report, HID_REQ_SET_REPORT);
 466                spin_unlock_irqrestore(&entry->report_lock, flags);
 467                break;
 468        }
 469        return 0;
 470}
 471
 472/* Sends default autocentering command compatible with
 473 * all wheels except Formula Force EX */
 474static void lg4ff_set_autocenter_default(struct input_dev *dev, u16 magnitude)
 475{
 476        struct hid_device *hid = input_get_drvdata(dev);
 477        struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
 478        struct hid_report *report = list_entry(report_list->next, struct hid_report, list);
 479        s32 *value = report->field[0]->value;
 480        u32 expand_a, expand_b;
 481        struct lg4ff_device_entry *entry;
 482        struct lg_drv_data *drv_data;
 483        unsigned long flags;
 484
 485        drv_data = hid_get_drvdata(hid);
 486        if (!drv_data) {
 487                hid_err(hid, "Private driver data not found!\n");
 488                return;
 489        }
 490
 491        entry = drv_data->device_props;
 492        if (!entry) {
 493                hid_err(hid, "Device properties not found!\n");
 494                return;
 495        }
 496        value = entry->report->field[0]->value;
 497
 498        /* De-activate Auto-Center */
 499        spin_lock_irqsave(&entry->report_lock, flags);
 500        if (magnitude == 0) {
 501                value[0] = 0xf5;
 502                value[1] = 0x00;
 503                value[2] = 0x00;
 504                value[3] = 0x00;
 505                value[4] = 0x00;
 506                value[5] = 0x00;
 507                value[6] = 0x00;
 508
 509                hid_hw_request(hid, entry->report, HID_REQ_SET_REPORT);
 510                spin_unlock_irqrestore(&entry->report_lock, flags);
 511                return;
 512        }
 513
 514        if (magnitude <= 0xaaaa) {
 515                expand_a = 0x0c * magnitude;
 516                expand_b = 0x80 * magnitude;
 517        } else {
 518                expand_a = (0x0c * 0xaaaa) + 0x06 * (magnitude - 0xaaaa);
 519                expand_b = (0x80 * 0xaaaa) + 0xff * (magnitude - 0xaaaa);
 520        }
 521
 522        /* Adjust for non-MOMO wheels */
 523        switch (entry->wdata.product_id) {
 524        case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL:
 525        case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2:
 526                break;
 527        default:
 528                expand_a = expand_a >> 1;
 529                break;
 530        }
 531
 532        value[0] = 0xfe;
 533        value[1] = 0x0d;
 534        value[2] = expand_a / 0xaaaa;
 535        value[3] = expand_a / 0xaaaa;
 536        value[4] = expand_b / 0xaaaa;
 537        value[5] = 0x00;
 538        value[6] = 0x00;
 539
 540        hid_hw_request(hid, entry->report, HID_REQ_SET_REPORT);
 541
 542        /* Activate Auto-Center */
 543        value[0] = 0x14;
 544        value[1] = 0x00;
 545        value[2] = 0x00;
 546        value[3] = 0x00;
 547        value[4] = 0x00;
 548        value[5] = 0x00;
 549        value[6] = 0x00;
 550
 551        hid_hw_request(hid, entry->report, HID_REQ_SET_REPORT);
 552        spin_unlock_irqrestore(&entry->report_lock, flags);
 553}
 554
 555/* Sends autocentering command compatible with Formula Force EX */
 556static void lg4ff_set_autocenter_ffex(struct input_dev *dev, u16 magnitude)
 557{
 558        struct hid_device *hid = input_get_drvdata(dev);
 559        struct lg4ff_device_entry *entry;
 560        struct lg_drv_data *drv_data;
 561        unsigned long flags;
 562        s32 *value;
 563        magnitude = magnitude * 90 / 65535;
 564
 565        drv_data = hid_get_drvdata(hid);
 566        if (!drv_data) {
 567                hid_err(hid, "Private driver data not found!\n");
 568                return;
 569        }
 570
 571        entry = drv_data->device_props;
 572        if (!entry) {
 573                hid_err(hid, "Device properties not found!\n");
 574                return;
 575        }
 576        value = entry->report->field[0]->value;
 577
 578        spin_lock_irqsave(&entry->report_lock, flags);
 579        value[0] = 0xfe;
 580        value[1] = 0x03;
 581        value[2] = magnitude >> 14;
 582        value[3] = magnitude >> 14;
 583        value[4] = magnitude;
 584        value[5] = 0x00;
 585        value[6] = 0x00;
 586
 587        hid_hw_request(hid, entry->report, HID_REQ_SET_REPORT);
 588        spin_unlock_irqrestore(&entry->report_lock, flags);
 589}
 590
 591/* Sends command to set range compatible with G25/G27/Driving Force GT */
 592static void lg4ff_set_range_g25(struct hid_device *hid, u16 range)
 593{
 594        struct lg4ff_device_entry *entry;
 595        struct lg_drv_data *drv_data;
 596        unsigned long flags;
 597        s32 *value;
 598
 599        drv_data = hid_get_drvdata(hid);
 600        if (!drv_data) {
 601                hid_err(hid, "Private driver data not found!\n");
 602                return;
 603        }
 604
 605        entry = drv_data->device_props;
 606        if (!entry) {
 607                hid_err(hid, "Device properties not found!\n");
 608                return;
 609        }
 610        value = entry->report->field[0]->value;
 611        dbg_hid("G25/G27/DFGT: setting range to %u\n", range);
 612
 613        spin_lock_irqsave(&entry->report_lock, flags);
 614        value[0] = 0xf8;
 615        value[1] = 0x81;
 616        value[2] = range & 0x00ff;
 617        value[3] = (range & 0xff00) >> 8;
 618        value[4] = 0x00;
 619        value[5] = 0x00;
 620        value[6] = 0x00;
 621
 622        hid_hw_request(hid, entry->report, HID_REQ_SET_REPORT);
 623        spin_unlock_irqrestore(&entry->report_lock, flags);
 624}
 625
 626/* Sends commands to set range compatible with Driving Force Pro wheel */
 627static void lg4ff_set_range_dfp(struct hid_device *hid, u16 range)
 628{
 629        struct lg4ff_device_entry *entry;
 630        struct lg_drv_data *drv_data;
 631        unsigned long flags;
 632        int start_left, start_right, full_range;
 633        s32 *value;
 634
 635        drv_data = hid_get_drvdata(hid);
 636        if (!drv_data) {
 637                hid_err(hid, "Private driver data not found!\n");
 638                return;
 639        }
 640
 641        entry = drv_data->device_props;
 642        if (!entry) {
 643                hid_err(hid, "Device properties not found!\n");
 644                return;
 645        }
 646        value = entry->report->field[0]->value;
 647        dbg_hid("Driving Force Pro: setting range to %u\n", range);
 648
 649        /* Prepare "coarse" limit command */
 650        spin_lock_irqsave(&entry->report_lock, flags);
 651        value[0] = 0xf8;
 652        value[1] = 0x00;        /* Set later */
 653        value[2] = 0x00;
 654        value[3] = 0x00;
 655        value[4] = 0x00;
 656        value[5] = 0x00;
 657        value[6] = 0x00;
 658
 659        if (range > 200) {
 660                value[1] = 0x03;
 661                full_range = 900;
 662        } else {
 663                value[1] = 0x02;
 664                full_range = 200;
 665        }
 666        hid_hw_request(hid, entry->report, HID_REQ_SET_REPORT);
 667
 668        /* Prepare "fine" limit command */
 669        value[0] = 0x81;
 670        value[1] = 0x0b;
 671        value[2] = 0x00;
 672        value[3] = 0x00;
 673        value[4] = 0x00;
 674        value[5] = 0x00;
 675        value[6] = 0x00;
 676
 677        if (range == 200 || range == 900) {     /* Do not apply any fine limit */
 678                hid_hw_request(hid, entry->report, HID_REQ_SET_REPORT);
 679                spin_unlock_irqrestore(&entry->report_lock, flags);
 680                return;
 681        }
 682
 683        /* Construct fine limit command */
 684        start_left = (((full_range - range + 1) * 2047) / full_range);
 685        start_right = 0xfff - start_left;
 686
 687        value[2] = start_left >> 4;
 688        value[3] = start_right >> 4;
 689        value[4] = 0xff;
 690        value[5] = (start_right & 0xe) << 4 | (start_left & 0xe);
 691        value[6] = 0xff;
 692
 693        hid_hw_request(hid, entry->report, HID_REQ_SET_REPORT);
 694        spin_unlock_irqrestore(&entry->report_lock, flags);
 695}
 696
 697static const struct lg4ff_compat_mode_switch *lg4ff_get_mode_switch_command(const u16 real_product_id, const u16 target_product_id)
 698{
 699        switch (real_product_id) {
 700        case USB_DEVICE_ID_LOGITECH_DFP_WHEEL:
 701                switch (target_product_id) {
 702                case USB_DEVICE_ID_LOGITECH_DFP_WHEEL:
 703                        return &lg4ff_mode_switch_ext01_dfp;
 704                /* DFP can only be switched to its native mode */
 705                default:
 706                        return NULL;
 707                }
 708                break;
 709        case USB_DEVICE_ID_LOGITECH_G25_WHEEL:
 710                switch (target_product_id) {
 711                case USB_DEVICE_ID_LOGITECH_DFP_WHEEL:
 712                        return &lg4ff_mode_switch_ext01_dfp;
 713                case USB_DEVICE_ID_LOGITECH_G25_WHEEL:
 714                        return &lg4ff_mode_switch_ext16_g25;
 715                /* G25 can only be switched to DFP mode or its native mode */
 716                default:
 717                        return NULL;
 718                }
 719                break;
 720        case USB_DEVICE_ID_LOGITECH_G27_WHEEL:
 721                switch (target_product_id) {
 722                case USB_DEVICE_ID_LOGITECH_WHEEL:
 723                        return &lg4ff_mode_switch_ext09_dfex;
 724                case USB_DEVICE_ID_LOGITECH_DFP_WHEEL:
 725                        return &lg4ff_mode_switch_ext09_dfp;
 726                case USB_DEVICE_ID_LOGITECH_G25_WHEEL:
 727                        return &lg4ff_mode_switch_ext09_g25;
 728                case USB_DEVICE_ID_LOGITECH_G27_WHEEL:
 729                        return &lg4ff_mode_switch_ext09_g27;
 730                /* G27 can only be switched to DF-EX, DFP, G25 or its native mode */
 731                default:
 732                        return NULL;
 733                }
 734                break;
 735        case USB_DEVICE_ID_LOGITECH_G29_WHEEL:
 736                switch (target_product_id) {
 737                case USB_DEVICE_ID_LOGITECH_DFP_WHEEL:
 738                        return &lg4ff_mode_switch_ext09_dfp;
 739                case USB_DEVICE_ID_LOGITECH_DFGT_WHEEL:
 740                        return &lg4ff_mode_switch_ext09_dfgt;
 741                case USB_DEVICE_ID_LOGITECH_G25_WHEEL:
 742                        return &lg4ff_mode_switch_ext09_g25;
 743                case USB_DEVICE_ID_LOGITECH_G27_WHEEL:
 744                        return &lg4ff_mode_switch_ext09_g27;
 745                case USB_DEVICE_ID_LOGITECH_G29_WHEEL:
 746                        return &lg4ff_mode_switch_ext09_g29;
 747                /* G29 can only be switched to DF-EX, DFP, DFGT, G25, G27 or its native mode */
 748                default:
 749                        return NULL;
 750                }
 751                break;
 752        case USB_DEVICE_ID_LOGITECH_DFGT_WHEEL:
 753                switch (target_product_id) {
 754                case USB_DEVICE_ID_LOGITECH_WHEEL:
 755                        return &lg4ff_mode_switch_ext09_dfex;
 756                case USB_DEVICE_ID_LOGITECH_DFP_WHEEL:
 757                        return &lg4ff_mode_switch_ext09_dfp;
 758                case USB_DEVICE_ID_LOGITECH_DFGT_WHEEL:
 759                        return &lg4ff_mode_switch_ext09_dfgt;
 760                /* DFGT can only be switched to DF-EX, DFP or its native mode */
 761                default:
 762                        return NULL;
 763                }
 764                break;
 765        /* No other wheels have multiple modes */
 766        default:
 767                return NULL;
 768        }
 769}
 770
 771static int lg4ff_switch_compatibility_mode(struct hid_device *hid, const struct lg4ff_compat_mode_switch *s)
 772{
 773        struct lg4ff_device_entry *entry;
 774        struct lg_drv_data *drv_data;
 775        unsigned long flags;
 776        s32 *value;
 777        u8 i;
 778
 779        drv_data = hid_get_drvdata(hid);
 780        if (!drv_data) {
 781                hid_err(hid, "Private driver data not found!\n");
 782                return -EINVAL;
 783        }
 784
 785        entry = drv_data->device_props;
 786        if (!entry) {
 787                hid_err(hid, "Device properties not found!\n");
 788                return -EINVAL;
 789        }
 790        value = entry->report->field[0]->value;
 791
 792        spin_lock_irqsave(&entry->report_lock, flags);
 793        for (i = 0; i < s->cmd_count; i++) {
 794                u8 j;
 795
 796                for (j = 0; j < 7; j++)
 797                        value[j] = s->cmd[j + (7*i)];
 798
 799                hid_hw_request(hid, entry->report, HID_REQ_SET_REPORT);
 800        }
 801        spin_unlock_irqrestore(&entry->report_lock, flags);
 802        hid_hw_wait(hid);
 803        return 0;
 804}
 805
 806static ssize_t lg4ff_alternate_modes_show(struct device *dev, struct device_attribute *attr, char *buf)
 807{
 808        struct hid_device *hid = to_hid_device(dev);
 809        struct lg4ff_device_entry *entry;
 810        struct lg_drv_data *drv_data;
 811        ssize_t count = 0;
 812        int i;
 813
 814        drv_data = hid_get_drvdata(hid);
 815        if (!drv_data) {
 816                hid_err(hid, "Private driver data not found!\n");
 817                return 0;
 818        }
 819
 820        entry = drv_data->device_props;
 821        if (!entry) {
 822                hid_err(hid, "Device properties not found!\n");
 823                return 0;
 824        }
 825
 826        if (!entry->wdata.real_name) {
 827                hid_err(hid, "NULL pointer to string\n");
 828                return 0;
 829        }
 830
 831        for (i = 0; i < LG4FF_MODE_MAX_IDX; i++) {
 832                if (entry->wdata.alternate_modes & BIT(i)) {
 833                        /* Print tag and full name */
 834                        count += scnprintf(buf + count, PAGE_SIZE - count, "%s: %s",
 835                                           lg4ff_alternate_modes[i].tag,
 836                                           !lg4ff_alternate_modes[i].product_id ? entry->wdata.real_name : lg4ff_alternate_modes[i].name);
 837                        if (count >= PAGE_SIZE - 1)
 838                                return count;
 839
 840                        /* Mark the currently active mode with an asterisk */
 841                        if (lg4ff_alternate_modes[i].product_id == entry->wdata.product_id ||
 842                            (lg4ff_alternate_modes[i].product_id == 0 && entry->wdata.product_id == entry->wdata.real_product_id))
 843                                count += scnprintf(buf + count, PAGE_SIZE - count, " *\n");
 844                        else
 845                                count += scnprintf(buf + count, PAGE_SIZE - count, "\n");
 846
 847                        if (count >= PAGE_SIZE - 1)
 848                                return count;
 849                }
 850        }
 851
 852        return count;
 853}
 854
 855static ssize_t lg4ff_alternate_modes_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
 856{
 857        struct hid_device *hid = to_hid_device(dev);
 858        struct lg4ff_device_entry *entry;
 859        struct lg_drv_data *drv_data;
 860        const struct lg4ff_compat_mode_switch *s;
 861        u16 target_product_id = 0;
 862        int i, ret;
 863        char *lbuf;
 864
 865        drv_data = hid_get_drvdata(hid);
 866        if (!drv_data) {
 867                hid_err(hid, "Private driver data not found!\n");
 868                return -EINVAL;
 869        }
 870
 871        entry = drv_data->device_props;
 872        if (!entry) {
 873                hid_err(hid, "Device properties not found!\n");
 874                return -EINVAL;
 875        }
 876
 877        /* Allow \n at the end of the input parameter */
 878        lbuf = kasprintf(GFP_KERNEL, "%s", buf);
 879        if (!lbuf)
 880                return -ENOMEM;
 881
 882        i = strlen(lbuf);
 883        if (lbuf[i-1] == '\n') {
 884                if (i == 1) {
 885                        kfree(lbuf);
 886                        return -EINVAL;
 887                }
 888                lbuf[i-1] = '\0';
 889        }
 890
 891        for (i = 0; i < LG4FF_MODE_MAX_IDX; i++) {
 892                const u16 mode_product_id = lg4ff_alternate_modes[i].product_id;
 893                const char *tag = lg4ff_alternate_modes[i].tag;
 894
 895                if (entry->wdata.alternate_modes & BIT(i)) {
 896                        if (!strcmp(tag, lbuf)) {
 897                                if (!mode_product_id)
 898                                        target_product_id = entry->wdata.real_product_id;
 899                                else
 900                                        target_product_id = mode_product_id;
 901                                break;
 902                        }
 903                }
 904        }
 905
 906        if (i == LG4FF_MODE_MAX_IDX) {
 907                hid_info(hid, "Requested mode \"%s\" is not supported by the device\n", lbuf);
 908                kfree(lbuf);
 909                return -EINVAL;
 910        }
 911        kfree(lbuf); /* Not needed anymore */
 912
 913        if (target_product_id == entry->wdata.product_id) /* Nothing to do */
 914                return count;
 915
 916        /* Automatic switching has to be disabled for the switch to DF-EX mode to work correctly */
 917        if (target_product_id == USB_DEVICE_ID_LOGITECH_WHEEL && !lg4ff_no_autoswitch) {
 918                hid_info(hid, "\"%s\" cannot be switched to \"DF-EX\" mode. Load the \"hid_logitech\" module with \"lg4ff_no_autoswitch=1\" parameter set and try again\n",
 919                         entry->wdata.real_name);
 920                return -EINVAL;
 921        }
 922
 923        /* Take care of hardware limitations */
 924        if ((entry->wdata.real_product_id == USB_DEVICE_ID_LOGITECH_DFP_WHEEL || entry->wdata.real_product_id == USB_DEVICE_ID_LOGITECH_G25_WHEEL) &&
 925            entry->wdata.product_id > target_product_id) {
 926                hid_info(hid, "\"%s\" cannot be switched back into \"%s\" mode\n", entry->wdata.real_name, lg4ff_alternate_modes[i].name);
 927                return -EINVAL;
 928        }
 929
 930        s = lg4ff_get_mode_switch_command(entry->wdata.real_product_id, target_product_id);
 931        if (!s) {
 932                hid_err(hid, "Invalid target product ID %X\n", target_product_id);
 933                return -EINVAL;
 934        }
 935
 936        ret = lg4ff_switch_compatibility_mode(hid, s);
 937        return (ret == 0 ? count : ret);
 938}
 939static DEVICE_ATTR(alternate_modes, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH, lg4ff_alternate_modes_show, lg4ff_alternate_modes_store);
 940
 941static ssize_t lg4ff_combine_show(struct device *dev, struct device_attribute *attr,
 942                                char *buf)
 943{
 944        struct hid_device *hid = to_hid_device(dev);
 945        struct lg4ff_device_entry *entry;
 946        struct lg_drv_data *drv_data;
 947        size_t count;
 948
 949        drv_data = hid_get_drvdata(hid);
 950        if (!drv_data) {
 951                hid_err(hid, "Private driver data not found!\n");
 952                return 0;
 953        }
 954
 955        entry = drv_data->device_props;
 956        if (!entry) {
 957                hid_err(hid, "Device properties not found!\n");
 958                return 0;
 959        }
 960
 961        count = scnprintf(buf, PAGE_SIZE, "%u\n", entry->wdata.combine);
 962        return count;
 963}
 964
 965static ssize_t lg4ff_combine_store(struct device *dev, struct device_attribute *attr,
 966                                 const char *buf, size_t count)
 967{
 968        struct hid_device *hid = to_hid_device(dev);
 969        struct lg4ff_device_entry *entry;
 970        struct lg_drv_data *drv_data;
 971        u16 combine = simple_strtoul(buf, NULL, 10);
 972
 973        drv_data = hid_get_drvdata(hid);
 974        if (!drv_data) {
 975                hid_err(hid, "Private driver data not found!\n");
 976                return -EINVAL;
 977        }
 978
 979        entry = drv_data->device_props;
 980        if (!entry) {
 981                hid_err(hid, "Device properties not found!\n");
 982                return -EINVAL;
 983        }
 984
 985        if (combine > 1)
 986                combine = 1;
 987
 988        entry->wdata.combine = combine;
 989        return count;
 990}
 991static DEVICE_ATTR(combine_pedals, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH, lg4ff_combine_show, lg4ff_combine_store);
 992
 993/* Export the currently set range of the wheel */
 994static ssize_t lg4ff_range_show(struct device *dev, struct device_attribute *attr,
 995                                char *buf)
 996{
 997        struct hid_device *hid = to_hid_device(dev);
 998        struct lg4ff_device_entry *entry;
 999        struct lg_drv_data *drv_data;
1000        size_t count;
1001
1002        drv_data = hid_get_drvdata(hid);
1003        if (!drv_data) {
1004                hid_err(hid, "Private driver data not found!\n");
1005                return 0;
1006        }
1007
1008        entry = drv_data->device_props;
1009        if (!entry) {
1010                hid_err(hid, "Device properties not found!\n");
1011                return 0;
1012        }
1013
1014        count = scnprintf(buf, PAGE_SIZE, "%u\n", entry->wdata.range);
1015        return count;
1016}
1017
1018/* Set range to user specified value, call appropriate function
1019 * according to the type of the wheel */
1020static ssize_t lg4ff_range_store(struct device *dev, struct device_attribute *attr,
1021                                 const char *buf, size_t count)
1022{
1023        struct hid_device *hid = to_hid_device(dev);
1024        struct lg4ff_device_entry *entry;
1025        struct lg_drv_data *drv_data;
1026        u16 range = simple_strtoul(buf, NULL, 10);
1027
1028        drv_data = hid_get_drvdata(hid);
1029        if (!drv_data) {
1030                hid_err(hid, "Private driver data not found!\n");
1031                return -EINVAL;
1032        }
1033
1034        entry = drv_data->device_props;
1035        if (!entry) {
1036                hid_err(hid, "Device properties not found!\n");
1037                return -EINVAL;
1038        }
1039
1040        if (range == 0)
1041                range = entry->wdata.max_range;
1042
1043        /* Check if the wheel supports range setting
1044         * and that the range is within limits for the wheel */
1045        if (entry->wdata.set_range && range >= entry->wdata.min_range && range <= entry->wdata.max_range) {
1046                entry->wdata.set_range(hid, range);
1047                entry->wdata.range = range;
1048        }
1049
1050        return count;
1051}
1052static DEVICE_ATTR(range, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH, lg4ff_range_show, lg4ff_range_store);
1053
1054static ssize_t lg4ff_real_id_show(struct device *dev, struct device_attribute *attr, char *buf)
1055{
1056        struct hid_device *hid = to_hid_device(dev);
1057        struct lg4ff_device_entry *entry;
1058        struct lg_drv_data *drv_data;
1059        size_t count;
1060
1061        drv_data = hid_get_drvdata(hid);
1062        if (!drv_data) {
1063                hid_err(hid, "Private driver data not found!\n");
1064                return 0;
1065        }
1066
1067        entry = drv_data->device_props;
1068        if (!entry) {
1069                hid_err(hid, "Device properties not found!\n");
1070                return 0;
1071        }
1072
1073        if (!entry->wdata.real_tag || !entry->wdata.real_name) {
1074                hid_err(hid, "NULL pointer to string\n");
1075                return 0;
1076        }
1077
1078        count = scnprintf(buf, PAGE_SIZE, "%s: %s\n", entry->wdata.real_tag, entry->wdata.real_name);
1079        return count;
1080}
1081
1082static ssize_t lg4ff_real_id_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
1083{
1084        /* Real ID is a read-only value */
1085        return -EPERM;
1086}
1087static DEVICE_ATTR(real_id, S_IRUGO, lg4ff_real_id_show, lg4ff_real_id_store);
1088
1089#ifdef CONFIG_LEDS_CLASS
1090static void lg4ff_set_leds(struct hid_device *hid, u8 leds)
1091{
1092        struct lg_drv_data *drv_data;
1093        struct lg4ff_device_entry *entry;
1094        unsigned long flags;
1095        s32 *value;
1096
1097        drv_data = hid_get_drvdata(hid);
1098        if (!drv_data) {
1099                hid_err(hid, "Private driver data not found!\n");
1100                return;
1101        }
1102
1103        entry = drv_data->device_props;
1104        if (!entry) {
1105                hid_err(hid, "Device properties not found!\n");
1106                return;
1107        }
1108        value = entry->report->field[0]->value;
1109
1110        spin_lock_irqsave(&entry->report_lock, flags);
1111        value[0] = 0xf8;
1112        value[1] = 0x12;
1113        value[2] = leds;
1114        value[3] = 0x00;
1115        value[4] = 0x00;
1116        value[5] = 0x00;
1117        value[6] = 0x00;
1118        hid_hw_request(hid, entry->report, HID_REQ_SET_REPORT);
1119        spin_unlock_irqrestore(&entry->report_lock, flags);
1120}
1121
1122static void lg4ff_led_set_brightness(struct led_classdev *led_cdev,
1123                        enum led_brightness value)
1124{
1125        struct device *dev = led_cdev->dev->parent;
1126        struct hid_device *hid = to_hid_device(dev);
1127        struct lg_drv_data *drv_data = hid_get_drvdata(hid);
1128        struct lg4ff_device_entry *entry;
1129        int i, state = 0;
1130
1131        if (!drv_data) {
1132                hid_err(hid, "Device data not found.");
1133                return;
1134        }
1135
1136        entry = drv_data->device_props;
1137
1138        if (!entry) {
1139                hid_err(hid, "Device properties not found.");
1140                return;
1141        }
1142
1143        for (i = 0; i < 5; i++) {
1144                if (led_cdev != entry->wdata.led[i])
1145                        continue;
1146                state = (entry->wdata.led_state >> i) & 1;
1147                if (value == LED_OFF && state) {
1148                        entry->wdata.led_state &= ~(1 << i);
1149                        lg4ff_set_leds(hid, entry->wdata.led_state);
1150                } else if (value != LED_OFF && !state) {
1151                        entry->wdata.led_state |= 1 << i;
1152                        lg4ff_set_leds(hid, entry->wdata.led_state);
1153                }
1154                break;
1155        }
1156}
1157
1158static enum led_brightness lg4ff_led_get_brightness(struct led_classdev *led_cdev)
1159{
1160        struct device *dev = led_cdev->dev->parent;
1161        struct hid_device *hid = to_hid_device(dev);
1162        struct lg_drv_data *drv_data = hid_get_drvdata(hid);
1163        struct lg4ff_device_entry *entry;
1164        int i, value = 0;
1165
1166        if (!drv_data) {
1167                hid_err(hid, "Device data not found.");
1168                return LED_OFF;
1169        }
1170
1171        entry = drv_data->device_props;
1172
1173        if (!entry) {
1174                hid_err(hid, "Device properties not found.");
1175                return LED_OFF;
1176        }
1177
1178        for (i = 0; i < 5; i++)
1179                if (led_cdev == entry->wdata.led[i]) {
1180                        value = (entry->wdata.led_state >> i) & 1;
1181                        break;
1182                }
1183
1184        return value ? LED_FULL : LED_OFF;
1185}
1186#endif
1187
1188static u16 lg4ff_identify_multimode_wheel(struct hid_device *hid, const u16 reported_product_id, const u16 bcdDevice)
1189{
1190        u32 current_mode;
1191        int i;
1192
1193        /* identify current mode from USB PID */
1194        for (i = 1; i < ARRAY_SIZE(lg4ff_alternate_modes); i++) {
1195                dbg_hid("Testing whether PID is %X\n", lg4ff_alternate_modes[i].product_id);
1196                if (reported_product_id == lg4ff_alternate_modes[i].product_id)
1197                        break;
1198        }
1199
1200        if (i == ARRAY_SIZE(lg4ff_alternate_modes))
1201                return 0;
1202
1203        current_mode = BIT(i);
1204
1205        for (i = 0; i < ARRAY_SIZE(lg4ff_main_checklist); i++) {
1206                const u16 mask = lg4ff_main_checklist[i]->mask;
1207                const u16 result = lg4ff_main_checklist[i]->result;
1208                const u16 real_product_id = lg4ff_main_checklist[i]->real_product_id;
1209
1210                if ((current_mode & lg4ff_main_checklist[i]->modes) && \
1211                                (bcdDevice & mask) == result) {
1212                        dbg_hid("Found wheel with real PID %X whose reported PID is %X\n", real_product_id, reported_product_id);
1213                        return real_product_id;
1214                }
1215        }
1216
1217        /* No match found. This is either Driving Force or an unknown
1218         * wheel model, do not touch it */
1219        dbg_hid("Wheel with bcdDevice %X was not recognized as multimode wheel, leaving in its current mode\n", bcdDevice);
1220        return 0;
1221}
1222
1223static int lg4ff_handle_multimode_wheel(struct hid_device *hid, u16 *real_product_id, const u16 bcdDevice)
1224{
1225        const u16 reported_product_id = hid->product;
1226        int ret;
1227
1228        *real_product_id = lg4ff_identify_multimode_wheel(hid, reported_product_id, bcdDevice);
1229        /* Probed wheel is not a multimode wheel */
1230        if (!*real_product_id) {
1231                *real_product_id = reported_product_id;
1232                dbg_hid("Wheel is not a multimode wheel\n");
1233                return LG4FF_MMODE_NOT_MULTIMODE;
1234        }
1235
1236        /* Switch from "Driving Force" mode to native mode automatically.
1237         * Otherwise keep the wheel in its current mode */
1238        if (reported_product_id == USB_DEVICE_ID_LOGITECH_WHEEL &&
1239            reported_product_id != *real_product_id &&
1240            !lg4ff_no_autoswitch) {
1241                const struct lg4ff_compat_mode_switch *s = lg4ff_get_mode_switch_command(*real_product_id, *real_product_id);
1242
1243                if (!s) {
1244                        hid_err(hid, "Invalid product id %X\n", *real_product_id);
1245                        return LG4FF_MMODE_NOT_MULTIMODE;
1246                }
1247
1248                ret = lg4ff_switch_compatibility_mode(hid, s);
1249                if (ret) {
1250                        /* Wheel could not have been switched to native mode,
1251                         * leave it in "Driving Force" mode and continue */
1252                        hid_err(hid, "Unable to switch wheel mode, errno %d\n", ret);
1253                        return LG4FF_MMODE_IS_MULTIMODE;
1254                }
1255                return LG4FF_MMODE_SWITCHED;
1256        }
1257
1258        return LG4FF_MMODE_IS_MULTIMODE;
1259}
1260
1261
1262int lg4ff_init(struct hid_device *hid)
1263{
1264        struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list);
1265        struct input_dev *dev = hidinput->input;
1266        struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
1267        struct hid_report *report = list_entry(report_list->next, struct hid_report, list);
1268        const struct usb_device_descriptor *udesc = &(hid_to_usb_dev(hid)->descriptor);
1269        const u16 bcdDevice = le16_to_cpu(udesc->bcdDevice);
1270        const struct lg4ff_multimode_wheel *mmode_wheel = NULL;
1271        struct lg4ff_device_entry *entry;
1272        struct lg_drv_data *drv_data;
1273        int error, i, j;
1274        int mmode_ret, mmode_idx = -1;
1275        u16 real_product_id;
1276
1277        /* Check that the report looks ok */
1278        if (!hid_validate_values(hid, HID_OUTPUT_REPORT, 0, 0, 7))
1279                return -1;
1280
1281        drv_data = hid_get_drvdata(hid);
1282        if (!drv_data) {
1283                hid_err(hid, "Cannot add device, private driver data not allocated\n");
1284                return -1;
1285        }
1286        entry = kzalloc(sizeof(*entry), GFP_KERNEL);
1287        if (!entry)
1288                return -ENOMEM;
1289        spin_lock_init(&entry->report_lock);
1290        entry->report = report;
1291        drv_data->device_props = entry;
1292
1293        /* Check if a multimode wheel has been connected and
1294         * handle it appropriately */
1295        mmode_ret = lg4ff_handle_multimode_wheel(hid, &real_product_id, bcdDevice);
1296
1297        /* Wheel has been told to switch to native mode. There is no point in going on
1298         * with the initialization as the wheel will do a USB reset when it switches mode
1299         */
1300        if (mmode_ret == LG4FF_MMODE_SWITCHED)
1301                return 0;
1302        else if (mmode_ret < 0) {
1303                hid_err(hid, "Unable to switch device mode during initialization, errno %d\n", mmode_ret);
1304                error = mmode_ret;
1305                goto err_init;
1306        }
1307
1308        /* Check what wheel has been connected */
1309        for (i = 0; i < ARRAY_SIZE(lg4ff_devices); i++) {
1310                if (hid->product == lg4ff_devices[i].product_id) {
1311                        dbg_hid("Found compatible device, product ID %04X\n", lg4ff_devices[i].product_id);
1312                        break;
1313                }
1314        }
1315
1316        if (i == ARRAY_SIZE(lg4ff_devices)) {
1317                hid_err(hid, "This device is flagged to be handled by the lg4ff module but this module does not know how to handle it. "
1318                             "Please report this as a bug to LKML, Simon Wood <simon@mungewell.org> or "
1319                             "Michal Maly <madcatxster@devoid-pointer.net>\n");
1320                error = -1;
1321                goto err_init;
1322        }
1323
1324        if (mmode_ret == LG4FF_MMODE_IS_MULTIMODE) {
1325                for (mmode_idx = 0; mmode_idx < ARRAY_SIZE(lg4ff_multimode_wheels); mmode_idx++) {
1326                        if (real_product_id == lg4ff_multimode_wheels[mmode_idx].product_id)
1327                                break;
1328                }
1329
1330                if (mmode_idx == ARRAY_SIZE(lg4ff_multimode_wheels)) {
1331                        hid_err(hid, "Device product ID %X is not listed as a multimode wheel", real_product_id);
1332                        error = -1;
1333                        goto err_init;
1334                }
1335        }
1336
1337        /* Set supported force feedback capabilities */
1338        for (j = 0; lg4ff_devices[i].ff_effects[j] >= 0; j++)
1339                set_bit(lg4ff_devices[i].ff_effects[j], dev->ffbit);
1340
1341        error = input_ff_create_memless(dev, NULL, lg4ff_play);
1342
1343        if (error)
1344                goto err_init;
1345
1346        /* Initialize device properties */
1347        if (mmode_ret == LG4FF_MMODE_IS_MULTIMODE) {
1348                BUG_ON(mmode_idx == -1);
1349                mmode_wheel = &lg4ff_multimode_wheels[mmode_idx];
1350        }
1351        lg4ff_init_wheel_data(&entry->wdata, &lg4ff_devices[i], mmode_wheel, real_product_id);
1352
1353        /* Check if autocentering is available and
1354         * set the centering force to zero by default */
1355        if (test_bit(FF_AUTOCENTER, dev->ffbit)) {
1356                /* Formula Force EX expects different autocentering command */
1357                if ((bcdDevice >> 8) == LG4FF_FFEX_REV_MAJ &&
1358                    (bcdDevice & 0xff) == LG4FF_FFEX_REV_MIN)
1359                        dev->ff->set_autocenter = lg4ff_set_autocenter_ffex;
1360                else
1361                        dev->ff->set_autocenter = lg4ff_set_autocenter_default;
1362
1363                dev->ff->set_autocenter(dev, 0);
1364        }
1365
1366        /* Create sysfs interface */
1367        error = device_create_file(&hid->dev, &dev_attr_combine_pedals);
1368        if (error)
1369                hid_warn(hid, "Unable to create sysfs interface for \"combine\", errno %d\n", error);
1370        error = device_create_file(&hid->dev, &dev_attr_range);
1371        if (error)
1372                hid_warn(hid, "Unable to create sysfs interface for \"range\", errno %d\n", error);
1373        if (mmode_ret == LG4FF_MMODE_IS_MULTIMODE) {
1374                error = device_create_file(&hid->dev, &dev_attr_real_id);
1375                if (error)
1376                        hid_warn(hid, "Unable to create sysfs interface for \"real_id\", errno %d\n", error);
1377                error = device_create_file(&hid->dev, &dev_attr_alternate_modes);
1378                if (error)
1379                        hid_warn(hid, "Unable to create sysfs interface for \"alternate_modes\", errno %d\n", error);
1380        }
1381        dbg_hid("sysfs interface created\n");
1382
1383        /* Set the maximum range to start with */
1384        entry->wdata.range = entry->wdata.max_range;
1385        if (entry->wdata.set_range)
1386                entry->wdata.set_range(hid, entry->wdata.range);
1387
1388#ifdef CONFIG_LEDS_CLASS
1389        /* register led subsystem - G27/G29 only */
1390        entry->wdata.led_state = 0;
1391        for (j = 0; j < 5; j++)
1392                entry->wdata.led[j] = NULL;
1393
1394        if (lg4ff_devices[i].product_id == USB_DEVICE_ID_LOGITECH_G27_WHEEL ||
1395                        lg4ff_devices[i].product_id == USB_DEVICE_ID_LOGITECH_G29_WHEEL) {
1396                struct led_classdev *led;
1397                size_t name_sz;
1398                char *name;
1399
1400                lg4ff_set_leds(hid, 0);
1401
1402                name_sz = strlen(dev_name(&hid->dev)) + 8;
1403
1404                for (j = 0; j < 5; j++) {
1405                        led = kzalloc(sizeof(struct led_classdev)+name_sz, GFP_KERNEL);
1406                        if (!led) {
1407                                hid_err(hid, "can't allocate memory for LED %d\n", j);
1408                                goto err_leds;
1409                        }
1410
1411                        name = (void *)(&led[1]);
1412                        snprintf(name, name_sz, "%s::RPM%d", dev_name(&hid->dev), j+1);
1413                        led->name = name;
1414                        led->brightness = 0;
1415                        led->max_brightness = 1;
1416                        led->brightness_get = lg4ff_led_get_brightness;
1417                        led->brightness_set = lg4ff_led_set_brightness;
1418
1419                        entry->wdata.led[j] = led;
1420                        error = led_classdev_register(&hid->dev, led);
1421
1422                        if (error) {
1423                                hid_err(hid, "failed to register LED %d. Aborting.\n", j);
1424err_leds:
1425                                /* Deregister LEDs (if any) */
1426                                for (j = 0; j < 5; j++) {
1427                                        led = entry->wdata.led[j];
1428                                        entry->wdata.led[j] = NULL;
1429                                        if (!led)
1430                                                continue;
1431                                        led_classdev_unregister(led);
1432                                        kfree(led);
1433                                }
1434                                goto out;       /* Let the driver continue without LEDs */
1435                        }
1436                }
1437        }
1438out:
1439#endif
1440        hid_info(hid, "Force feedback support for Logitech Gaming Wheels\n");
1441        return 0;
1442
1443err_init:
1444        drv_data->device_props = NULL;
1445        kfree(entry);
1446        return error;
1447}
1448
1449int lg4ff_deinit(struct hid_device *hid)
1450{
1451        struct lg4ff_device_entry *entry;
1452        struct lg_drv_data *drv_data;
1453
1454        drv_data = hid_get_drvdata(hid);
1455        if (!drv_data) {
1456                hid_err(hid, "Error while deinitializing device, no private driver data.\n");
1457                return -1;
1458        }
1459        entry = drv_data->device_props;
1460        if (!entry)
1461                goto out; /* Nothing more to do */
1462
1463        /* Multimode devices will have at least the "MODE_NATIVE" bit set */
1464        if (entry->wdata.alternate_modes) {
1465                device_remove_file(&hid->dev, &dev_attr_real_id);
1466                device_remove_file(&hid->dev, &dev_attr_alternate_modes);
1467        }
1468
1469        device_remove_file(&hid->dev, &dev_attr_combine_pedals);
1470        device_remove_file(&hid->dev, &dev_attr_range);
1471#ifdef CONFIG_LEDS_CLASS
1472        {
1473                int j;
1474                struct led_classdev *led;
1475
1476                /* Deregister LEDs (if any) */
1477                for (j = 0; j < 5; j++) {
1478
1479                        led = entry->wdata.led[j];
1480                        entry->wdata.led[j] = NULL;
1481                        if (!led)
1482                                continue;
1483                        led_classdev_unregister(led);
1484                        kfree(led);
1485                }
1486        }
1487#endif
1488        hid_hw_stop(hid);
1489        drv_data->device_props = NULL;
1490
1491        kfree(entry);
1492out:
1493        dbg_hid("Device successfully unregistered\n");
1494        return 0;
1495}
1496