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        s32 *value;
 478        u32 expand_a, expand_b;
 479        struct lg4ff_device_entry *entry;
 480        struct lg_drv_data *drv_data;
 481        unsigned long flags;
 482
 483        drv_data = hid_get_drvdata(hid);
 484        if (!drv_data) {
 485                hid_err(hid, "Private driver data not found!\n");
 486                return;
 487        }
 488
 489        entry = drv_data->device_props;
 490        if (!entry) {
 491                hid_err(hid, "Device properties not found!\n");
 492                return;
 493        }
 494        value = entry->report->field[0]->value;
 495
 496        /* De-activate Auto-Center */
 497        spin_lock_irqsave(&entry->report_lock, flags);
 498        if (magnitude == 0) {
 499                value[0] = 0xf5;
 500                value[1] = 0x00;
 501                value[2] = 0x00;
 502                value[3] = 0x00;
 503                value[4] = 0x00;
 504                value[5] = 0x00;
 505                value[6] = 0x00;
 506
 507                hid_hw_request(hid, entry->report, HID_REQ_SET_REPORT);
 508                spin_unlock_irqrestore(&entry->report_lock, flags);
 509                return;
 510        }
 511
 512        if (magnitude <= 0xaaaa) {
 513                expand_a = 0x0c * magnitude;
 514                expand_b = 0x80 * magnitude;
 515        } else {
 516                expand_a = (0x0c * 0xaaaa) + 0x06 * (magnitude - 0xaaaa);
 517                expand_b = (0x80 * 0xaaaa) + 0xff * (magnitude - 0xaaaa);
 518        }
 519
 520        /* Adjust for non-MOMO wheels */
 521        switch (entry->wdata.product_id) {
 522        case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL:
 523        case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2:
 524                break;
 525        default:
 526                expand_a = expand_a >> 1;
 527                break;
 528        }
 529
 530        value[0] = 0xfe;
 531        value[1] = 0x0d;
 532        value[2] = expand_a / 0xaaaa;
 533        value[3] = expand_a / 0xaaaa;
 534        value[4] = expand_b / 0xaaaa;
 535        value[5] = 0x00;
 536        value[6] = 0x00;
 537
 538        hid_hw_request(hid, entry->report, HID_REQ_SET_REPORT);
 539
 540        /* Activate Auto-Center */
 541        value[0] = 0x14;
 542        value[1] = 0x00;
 543        value[2] = 0x00;
 544        value[3] = 0x00;
 545        value[4] = 0x00;
 546        value[5] = 0x00;
 547        value[6] = 0x00;
 548
 549        hid_hw_request(hid, entry->report, HID_REQ_SET_REPORT);
 550        spin_unlock_irqrestore(&entry->report_lock, flags);
 551}
 552
 553/* Sends autocentering command compatible with Formula Force EX */
 554static void lg4ff_set_autocenter_ffex(struct input_dev *dev, u16 magnitude)
 555{
 556        struct hid_device *hid = input_get_drvdata(dev);
 557        struct lg4ff_device_entry *entry;
 558        struct lg_drv_data *drv_data;
 559        unsigned long flags;
 560        s32 *value;
 561        magnitude = magnitude * 90 / 65535;
 562
 563        drv_data = hid_get_drvdata(hid);
 564        if (!drv_data) {
 565                hid_err(hid, "Private driver data not found!\n");
 566                return;
 567        }
 568
 569        entry = drv_data->device_props;
 570        if (!entry) {
 571                hid_err(hid, "Device properties not found!\n");
 572                return;
 573        }
 574        value = entry->report->field[0]->value;
 575
 576        spin_lock_irqsave(&entry->report_lock, flags);
 577        value[0] = 0xfe;
 578        value[1] = 0x03;
 579        value[2] = magnitude >> 14;
 580        value[3] = magnitude >> 14;
 581        value[4] = magnitude;
 582        value[5] = 0x00;
 583        value[6] = 0x00;
 584
 585        hid_hw_request(hid, entry->report, HID_REQ_SET_REPORT);
 586        spin_unlock_irqrestore(&entry->report_lock, flags);
 587}
 588
 589/* Sends command to set range compatible with G25/G27/Driving Force GT */
 590static void lg4ff_set_range_g25(struct hid_device *hid, u16 range)
 591{
 592        struct lg4ff_device_entry *entry;
 593        struct lg_drv_data *drv_data;
 594        unsigned long flags;
 595        s32 *value;
 596
 597        drv_data = hid_get_drvdata(hid);
 598        if (!drv_data) {
 599                hid_err(hid, "Private driver data not found!\n");
 600                return;
 601        }
 602
 603        entry = drv_data->device_props;
 604        if (!entry) {
 605                hid_err(hid, "Device properties not found!\n");
 606                return;
 607        }
 608        value = entry->report->field[0]->value;
 609        dbg_hid("G25/G27/DFGT: setting range to %u\n", range);
 610
 611        spin_lock_irqsave(&entry->report_lock, flags);
 612        value[0] = 0xf8;
 613        value[1] = 0x81;
 614        value[2] = range & 0x00ff;
 615        value[3] = (range & 0xff00) >> 8;
 616        value[4] = 0x00;
 617        value[5] = 0x00;
 618        value[6] = 0x00;
 619
 620        hid_hw_request(hid, entry->report, HID_REQ_SET_REPORT);
 621        spin_unlock_irqrestore(&entry->report_lock, flags);
 622}
 623
 624/* Sends commands to set range compatible with Driving Force Pro wheel */
 625static void lg4ff_set_range_dfp(struct hid_device *hid, u16 range)
 626{
 627        struct lg4ff_device_entry *entry;
 628        struct lg_drv_data *drv_data;
 629        unsigned long flags;
 630        int start_left, start_right, full_range;
 631        s32 *value;
 632
 633        drv_data = hid_get_drvdata(hid);
 634        if (!drv_data) {
 635                hid_err(hid, "Private driver data not found!\n");
 636                return;
 637        }
 638
 639        entry = drv_data->device_props;
 640        if (!entry) {
 641                hid_err(hid, "Device properties not found!\n");
 642                return;
 643        }
 644        value = entry->report->field[0]->value;
 645        dbg_hid("Driving Force Pro: setting range to %u\n", range);
 646
 647        /* Prepare "coarse" limit command */
 648        spin_lock_irqsave(&entry->report_lock, flags);
 649        value[0] = 0xf8;
 650        value[1] = 0x00;        /* Set later */
 651        value[2] = 0x00;
 652        value[3] = 0x00;
 653        value[4] = 0x00;
 654        value[5] = 0x00;
 655        value[6] = 0x00;
 656
 657        if (range > 200) {
 658                value[1] = 0x03;
 659                full_range = 900;
 660        } else {
 661                value[1] = 0x02;
 662                full_range = 200;
 663        }
 664        hid_hw_request(hid, entry->report, HID_REQ_SET_REPORT);
 665
 666        /* Prepare "fine" limit command */
 667        value[0] = 0x81;
 668        value[1] = 0x0b;
 669        value[2] = 0x00;
 670        value[3] = 0x00;
 671        value[4] = 0x00;
 672        value[5] = 0x00;
 673        value[6] = 0x00;
 674
 675        if (range == 200 || range == 900) {     /* Do not apply any fine limit */
 676                hid_hw_request(hid, entry->report, HID_REQ_SET_REPORT);
 677                spin_unlock_irqrestore(&entry->report_lock, flags);
 678                return;
 679        }
 680
 681        /* Construct fine limit command */
 682        start_left = (((full_range - range + 1) * 2047) / full_range);
 683        start_right = 0xfff - start_left;
 684
 685        value[2] = start_left >> 4;
 686        value[3] = start_right >> 4;
 687        value[4] = 0xff;
 688        value[5] = (start_right & 0xe) << 4 | (start_left & 0xe);
 689        value[6] = 0xff;
 690
 691        hid_hw_request(hid, entry->report, HID_REQ_SET_REPORT);
 692        spin_unlock_irqrestore(&entry->report_lock, flags);
 693}
 694
 695static const struct lg4ff_compat_mode_switch *lg4ff_get_mode_switch_command(const u16 real_product_id, const u16 target_product_id)
 696{
 697        switch (real_product_id) {
 698        case USB_DEVICE_ID_LOGITECH_DFP_WHEEL:
 699                switch (target_product_id) {
 700                case USB_DEVICE_ID_LOGITECH_DFP_WHEEL:
 701                        return &lg4ff_mode_switch_ext01_dfp;
 702                /* DFP can only be switched to its native mode */
 703                default:
 704                        return NULL;
 705                }
 706                break;
 707        case USB_DEVICE_ID_LOGITECH_G25_WHEEL:
 708                switch (target_product_id) {
 709                case USB_DEVICE_ID_LOGITECH_DFP_WHEEL:
 710                        return &lg4ff_mode_switch_ext01_dfp;
 711                case USB_DEVICE_ID_LOGITECH_G25_WHEEL:
 712                        return &lg4ff_mode_switch_ext16_g25;
 713                /* G25 can only be switched to DFP mode or its native mode */
 714                default:
 715                        return NULL;
 716                }
 717                break;
 718        case USB_DEVICE_ID_LOGITECH_G27_WHEEL:
 719                switch (target_product_id) {
 720                case USB_DEVICE_ID_LOGITECH_WHEEL:
 721                        return &lg4ff_mode_switch_ext09_dfex;
 722                case USB_DEVICE_ID_LOGITECH_DFP_WHEEL:
 723                        return &lg4ff_mode_switch_ext09_dfp;
 724                case USB_DEVICE_ID_LOGITECH_G25_WHEEL:
 725                        return &lg4ff_mode_switch_ext09_g25;
 726                case USB_DEVICE_ID_LOGITECH_G27_WHEEL:
 727                        return &lg4ff_mode_switch_ext09_g27;
 728                /* G27 can only be switched to DF-EX, DFP, G25 or its native mode */
 729                default:
 730                        return NULL;
 731                }
 732                break;
 733        case USB_DEVICE_ID_LOGITECH_G29_WHEEL:
 734                switch (target_product_id) {
 735                case USB_DEVICE_ID_LOGITECH_DFP_WHEEL:
 736                        return &lg4ff_mode_switch_ext09_dfp;
 737                case USB_DEVICE_ID_LOGITECH_DFGT_WHEEL:
 738                        return &lg4ff_mode_switch_ext09_dfgt;
 739                case USB_DEVICE_ID_LOGITECH_G25_WHEEL:
 740                        return &lg4ff_mode_switch_ext09_g25;
 741                case USB_DEVICE_ID_LOGITECH_G27_WHEEL:
 742                        return &lg4ff_mode_switch_ext09_g27;
 743                case USB_DEVICE_ID_LOGITECH_G29_WHEEL:
 744                        return &lg4ff_mode_switch_ext09_g29;
 745                /* G29 can only be switched to DF-EX, DFP, DFGT, G25, G27 or its native mode */
 746                default:
 747                        return NULL;
 748                }
 749                break;
 750        case USB_DEVICE_ID_LOGITECH_DFGT_WHEEL:
 751                switch (target_product_id) {
 752                case USB_DEVICE_ID_LOGITECH_WHEEL:
 753                        return &lg4ff_mode_switch_ext09_dfex;
 754                case USB_DEVICE_ID_LOGITECH_DFP_WHEEL:
 755                        return &lg4ff_mode_switch_ext09_dfp;
 756                case USB_DEVICE_ID_LOGITECH_DFGT_WHEEL:
 757                        return &lg4ff_mode_switch_ext09_dfgt;
 758                /* DFGT can only be switched to DF-EX, DFP or its native mode */
 759                default:
 760                        return NULL;
 761                }
 762                break;
 763        /* No other wheels have multiple modes */
 764        default:
 765                return NULL;
 766        }
 767}
 768
 769static int lg4ff_switch_compatibility_mode(struct hid_device *hid, const struct lg4ff_compat_mode_switch *s)
 770{
 771        struct lg4ff_device_entry *entry;
 772        struct lg_drv_data *drv_data;
 773        unsigned long flags;
 774        s32 *value;
 775        u8 i;
 776
 777        drv_data = hid_get_drvdata(hid);
 778        if (!drv_data) {
 779                hid_err(hid, "Private driver data not found!\n");
 780                return -EINVAL;
 781        }
 782
 783        entry = drv_data->device_props;
 784        if (!entry) {
 785                hid_err(hid, "Device properties not found!\n");
 786                return -EINVAL;
 787        }
 788        value = entry->report->field[0]->value;
 789
 790        spin_lock_irqsave(&entry->report_lock, flags);
 791        for (i = 0; i < s->cmd_count; i++) {
 792                u8 j;
 793
 794                for (j = 0; j < 7; j++)
 795                        value[j] = s->cmd[j + (7*i)];
 796
 797                hid_hw_request(hid, entry->report, HID_REQ_SET_REPORT);
 798        }
 799        spin_unlock_irqrestore(&entry->report_lock, flags);
 800        hid_hw_wait(hid);
 801        return 0;
 802}
 803
 804static ssize_t lg4ff_alternate_modes_show(struct device *dev, struct device_attribute *attr, char *buf)
 805{
 806        struct hid_device *hid = to_hid_device(dev);
 807        struct lg4ff_device_entry *entry;
 808        struct lg_drv_data *drv_data;
 809        ssize_t count = 0;
 810        int i;
 811
 812        drv_data = hid_get_drvdata(hid);
 813        if (!drv_data) {
 814                hid_err(hid, "Private driver data not found!\n");
 815                return 0;
 816        }
 817
 818        entry = drv_data->device_props;
 819        if (!entry) {
 820                hid_err(hid, "Device properties not found!\n");
 821                return 0;
 822        }
 823
 824        if (!entry->wdata.real_name) {
 825                hid_err(hid, "NULL pointer to string\n");
 826                return 0;
 827        }
 828
 829        for (i = 0; i < LG4FF_MODE_MAX_IDX; i++) {
 830                if (entry->wdata.alternate_modes & BIT(i)) {
 831                        /* Print tag and full name */
 832                        count += scnprintf(buf + count, PAGE_SIZE - count, "%s: %s",
 833                                           lg4ff_alternate_modes[i].tag,
 834                                           !lg4ff_alternate_modes[i].product_id ? entry->wdata.real_name : lg4ff_alternate_modes[i].name);
 835                        if (count >= PAGE_SIZE - 1)
 836                                return count;
 837
 838                        /* Mark the currently active mode with an asterisk */
 839                        if (lg4ff_alternate_modes[i].product_id == entry->wdata.product_id ||
 840                            (lg4ff_alternate_modes[i].product_id == 0 && entry->wdata.product_id == entry->wdata.real_product_id))
 841                                count += scnprintf(buf + count, PAGE_SIZE - count, " *\n");
 842                        else
 843                                count += scnprintf(buf + count, PAGE_SIZE - count, "\n");
 844
 845                        if (count >= PAGE_SIZE - 1)
 846                                return count;
 847                }
 848        }
 849
 850        return count;
 851}
 852
 853static ssize_t lg4ff_alternate_modes_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
 854{
 855        struct hid_device *hid = to_hid_device(dev);
 856        struct lg4ff_device_entry *entry;
 857        struct lg_drv_data *drv_data;
 858        const struct lg4ff_compat_mode_switch *s;
 859        u16 target_product_id = 0;
 860        int i, ret;
 861        char *lbuf;
 862
 863        drv_data = hid_get_drvdata(hid);
 864        if (!drv_data) {
 865                hid_err(hid, "Private driver data not found!\n");
 866                return -EINVAL;
 867        }
 868
 869        entry = drv_data->device_props;
 870        if (!entry) {
 871                hid_err(hid, "Device properties not found!\n");
 872                return -EINVAL;
 873        }
 874
 875        /* Allow \n at the end of the input parameter */
 876        lbuf = kasprintf(GFP_KERNEL, "%s", buf);
 877        if (!lbuf)
 878                return -ENOMEM;
 879
 880        i = strlen(lbuf);
 881        if (lbuf[i-1] == '\n') {
 882                if (i == 1) {
 883                        kfree(lbuf);
 884                        return -EINVAL;
 885                }
 886                lbuf[i-1] = '\0';
 887        }
 888
 889        for (i = 0; i < LG4FF_MODE_MAX_IDX; i++) {
 890                const u16 mode_product_id = lg4ff_alternate_modes[i].product_id;
 891                const char *tag = lg4ff_alternate_modes[i].tag;
 892
 893                if (entry->wdata.alternate_modes & BIT(i)) {
 894                        if (!strcmp(tag, lbuf)) {
 895                                if (!mode_product_id)
 896                                        target_product_id = entry->wdata.real_product_id;
 897                                else
 898                                        target_product_id = mode_product_id;
 899                                break;
 900                        }
 901                }
 902        }
 903
 904        if (i == LG4FF_MODE_MAX_IDX) {
 905                hid_info(hid, "Requested mode \"%s\" is not supported by the device\n", lbuf);
 906                kfree(lbuf);
 907                return -EINVAL;
 908        }
 909        kfree(lbuf); /* Not needed anymore */
 910
 911        if (target_product_id == entry->wdata.product_id) /* Nothing to do */
 912                return count;
 913
 914        /* Automatic switching has to be disabled for the switch to DF-EX mode to work correctly */
 915        if (target_product_id == USB_DEVICE_ID_LOGITECH_WHEEL && !lg4ff_no_autoswitch) {
 916                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",
 917                         entry->wdata.real_name);
 918                return -EINVAL;
 919        }
 920
 921        /* Take care of hardware limitations */
 922        if ((entry->wdata.real_product_id == USB_DEVICE_ID_LOGITECH_DFP_WHEEL || entry->wdata.real_product_id == USB_DEVICE_ID_LOGITECH_G25_WHEEL) &&
 923            entry->wdata.product_id > target_product_id) {
 924                hid_info(hid, "\"%s\" cannot be switched back into \"%s\" mode\n", entry->wdata.real_name, lg4ff_alternate_modes[i].name);
 925                return -EINVAL;
 926        }
 927
 928        s = lg4ff_get_mode_switch_command(entry->wdata.real_product_id, target_product_id);
 929        if (!s) {
 930                hid_err(hid, "Invalid target product ID %X\n", target_product_id);
 931                return -EINVAL;
 932        }
 933
 934        ret = lg4ff_switch_compatibility_mode(hid, s);
 935        return (ret == 0 ? count : ret);
 936}
 937static DEVICE_ATTR(alternate_modes, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH, lg4ff_alternate_modes_show, lg4ff_alternate_modes_store);
 938
 939static ssize_t lg4ff_combine_show(struct device *dev, struct device_attribute *attr,
 940                                char *buf)
 941{
 942        struct hid_device *hid = to_hid_device(dev);
 943        struct lg4ff_device_entry *entry;
 944        struct lg_drv_data *drv_data;
 945        size_t count;
 946
 947        drv_data = hid_get_drvdata(hid);
 948        if (!drv_data) {
 949                hid_err(hid, "Private driver data not found!\n");
 950                return 0;
 951        }
 952
 953        entry = drv_data->device_props;
 954        if (!entry) {
 955                hid_err(hid, "Device properties not found!\n");
 956                return 0;
 957        }
 958
 959        count = scnprintf(buf, PAGE_SIZE, "%u\n", entry->wdata.combine);
 960        return count;
 961}
 962
 963static ssize_t lg4ff_combine_store(struct device *dev, struct device_attribute *attr,
 964                                 const char *buf, size_t count)
 965{
 966        struct hid_device *hid = to_hid_device(dev);
 967        struct lg4ff_device_entry *entry;
 968        struct lg_drv_data *drv_data;
 969        u16 combine = simple_strtoul(buf, NULL, 10);
 970
 971        drv_data = hid_get_drvdata(hid);
 972        if (!drv_data) {
 973                hid_err(hid, "Private driver data not found!\n");
 974                return -EINVAL;
 975        }
 976
 977        entry = drv_data->device_props;
 978        if (!entry) {
 979                hid_err(hid, "Device properties not found!\n");
 980                return -EINVAL;
 981        }
 982
 983        if (combine > 1)
 984                combine = 1;
 985
 986        entry->wdata.combine = combine;
 987        return count;
 988}
 989static DEVICE_ATTR(combine_pedals, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH, lg4ff_combine_show, lg4ff_combine_store);
 990
 991/* Export the currently set range of the wheel */
 992static ssize_t lg4ff_range_show(struct device *dev, struct device_attribute *attr,
 993                                char *buf)
 994{
 995        struct hid_device *hid = to_hid_device(dev);
 996        struct lg4ff_device_entry *entry;
 997        struct lg_drv_data *drv_data;
 998        size_t count;
 999
1000        drv_data = hid_get_drvdata(hid);
1001        if (!drv_data) {
1002                hid_err(hid, "Private driver data not found!\n");
1003                return 0;
1004        }
1005
1006        entry = drv_data->device_props;
1007        if (!entry) {
1008                hid_err(hid, "Device properties not found!\n");
1009                return 0;
1010        }
1011
1012        count = scnprintf(buf, PAGE_SIZE, "%u\n", entry->wdata.range);
1013        return count;
1014}
1015
1016/* Set range to user specified value, call appropriate function
1017 * according to the type of the wheel */
1018static ssize_t lg4ff_range_store(struct device *dev, struct device_attribute *attr,
1019                                 const char *buf, size_t count)
1020{
1021        struct hid_device *hid = to_hid_device(dev);
1022        struct lg4ff_device_entry *entry;
1023        struct lg_drv_data *drv_data;
1024        u16 range = simple_strtoul(buf, NULL, 10);
1025
1026        drv_data = hid_get_drvdata(hid);
1027        if (!drv_data) {
1028                hid_err(hid, "Private driver data not found!\n");
1029                return -EINVAL;
1030        }
1031
1032        entry = drv_data->device_props;
1033        if (!entry) {
1034                hid_err(hid, "Device properties not found!\n");
1035                return -EINVAL;
1036        }
1037
1038        if (range == 0)
1039                range = entry->wdata.max_range;
1040
1041        /* Check if the wheel supports range setting
1042         * and that the range is within limits for the wheel */
1043        if (entry->wdata.set_range && range >= entry->wdata.min_range && range <= entry->wdata.max_range) {
1044                entry->wdata.set_range(hid, range);
1045                entry->wdata.range = range;
1046        }
1047
1048        return count;
1049}
1050static DEVICE_ATTR(range, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH, lg4ff_range_show, lg4ff_range_store);
1051
1052static ssize_t lg4ff_real_id_show(struct device *dev, struct device_attribute *attr, char *buf)
1053{
1054        struct hid_device *hid = to_hid_device(dev);
1055        struct lg4ff_device_entry *entry;
1056        struct lg_drv_data *drv_data;
1057        size_t count;
1058
1059        drv_data = hid_get_drvdata(hid);
1060        if (!drv_data) {
1061                hid_err(hid, "Private driver data not found!\n");
1062                return 0;
1063        }
1064
1065        entry = drv_data->device_props;
1066        if (!entry) {
1067                hid_err(hid, "Device properties not found!\n");
1068                return 0;
1069        }
1070
1071        if (!entry->wdata.real_tag || !entry->wdata.real_name) {
1072                hid_err(hid, "NULL pointer to string\n");
1073                return 0;
1074        }
1075
1076        count = scnprintf(buf, PAGE_SIZE, "%s: %s\n", entry->wdata.real_tag, entry->wdata.real_name);
1077        return count;
1078}
1079
1080static ssize_t lg4ff_real_id_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
1081{
1082        /* Real ID is a read-only value */
1083        return -EPERM;
1084}
1085static DEVICE_ATTR(real_id, S_IRUGO, lg4ff_real_id_show, lg4ff_real_id_store);
1086
1087#ifdef CONFIG_LEDS_CLASS
1088static void lg4ff_set_leds(struct hid_device *hid, u8 leds)
1089{
1090        struct lg_drv_data *drv_data;
1091        struct lg4ff_device_entry *entry;
1092        unsigned long flags;
1093        s32 *value;
1094
1095        drv_data = hid_get_drvdata(hid);
1096        if (!drv_data) {
1097                hid_err(hid, "Private driver data not found!\n");
1098                return;
1099        }
1100
1101        entry = drv_data->device_props;
1102        if (!entry) {
1103                hid_err(hid, "Device properties not found!\n");
1104                return;
1105        }
1106        value = entry->report->field[0]->value;
1107
1108        spin_lock_irqsave(&entry->report_lock, flags);
1109        value[0] = 0xf8;
1110        value[1] = 0x12;
1111        value[2] = leds;
1112        value[3] = 0x00;
1113        value[4] = 0x00;
1114        value[5] = 0x00;
1115        value[6] = 0x00;
1116        hid_hw_request(hid, entry->report, HID_REQ_SET_REPORT);
1117        spin_unlock_irqrestore(&entry->report_lock, flags);
1118}
1119
1120static void lg4ff_led_set_brightness(struct led_classdev *led_cdev,
1121                        enum led_brightness value)
1122{
1123        struct device *dev = led_cdev->dev->parent;
1124        struct hid_device *hid = to_hid_device(dev);
1125        struct lg_drv_data *drv_data = hid_get_drvdata(hid);
1126        struct lg4ff_device_entry *entry;
1127        int i, state = 0;
1128
1129        if (!drv_data) {
1130                hid_err(hid, "Device data not found.");
1131                return;
1132        }
1133
1134        entry = drv_data->device_props;
1135
1136        if (!entry) {
1137                hid_err(hid, "Device properties not found.");
1138                return;
1139        }
1140
1141        for (i = 0; i < 5; i++) {
1142                if (led_cdev != entry->wdata.led[i])
1143                        continue;
1144                state = (entry->wdata.led_state >> i) & 1;
1145                if (value == LED_OFF && state) {
1146                        entry->wdata.led_state &= ~(1 << i);
1147                        lg4ff_set_leds(hid, entry->wdata.led_state);
1148                } else if (value != LED_OFF && !state) {
1149                        entry->wdata.led_state |= 1 << i;
1150                        lg4ff_set_leds(hid, entry->wdata.led_state);
1151                }
1152                break;
1153        }
1154}
1155
1156static enum led_brightness lg4ff_led_get_brightness(struct led_classdev *led_cdev)
1157{
1158        struct device *dev = led_cdev->dev->parent;
1159        struct hid_device *hid = to_hid_device(dev);
1160        struct lg_drv_data *drv_data = hid_get_drvdata(hid);
1161        struct lg4ff_device_entry *entry;
1162        int i, value = 0;
1163
1164        if (!drv_data) {
1165                hid_err(hid, "Device data not found.");
1166                return LED_OFF;
1167        }
1168
1169        entry = drv_data->device_props;
1170
1171        if (!entry) {
1172                hid_err(hid, "Device properties not found.");
1173                return LED_OFF;
1174        }
1175
1176        for (i = 0; i < 5; i++)
1177                if (led_cdev == entry->wdata.led[i]) {
1178                        value = (entry->wdata.led_state >> i) & 1;
1179                        break;
1180                }
1181
1182        return value ? LED_FULL : LED_OFF;
1183}
1184#endif
1185
1186static u16 lg4ff_identify_multimode_wheel(struct hid_device *hid, const u16 reported_product_id, const u16 bcdDevice)
1187{
1188        u32 current_mode;
1189        int i;
1190
1191        /* identify current mode from USB PID */
1192        for (i = 1; i < ARRAY_SIZE(lg4ff_alternate_modes); i++) {
1193                dbg_hid("Testing whether PID is %X\n", lg4ff_alternate_modes[i].product_id);
1194                if (reported_product_id == lg4ff_alternate_modes[i].product_id)
1195                        break;
1196        }
1197
1198        if (i == ARRAY_SIZE(lg4ff_alternate_modes))
1199                return 0;
1200
1201        current_mode = BIT(i);
1202
1203        for (i = 0; i < ARRAY_SIZE(lg4ff_main_checklist); i++) {
1204                const u16 mask = lg4ff_main_checklist[i]->mask;
1205                const u16 result = lg4ff_main_checklist[i]->result;
1206                const u16 real_product_id = lg4ff_main_checklist[i]->real_product_id;
1207
1208                if ((current_mode & lg4ff_main_checklist[i]->modes) && \
1209                                (bcdDevice & mask) == result) {
1210                        dbg_hid("Found wheel with real PID %X whose reported PID is %X\n", real_product_id, reported_product_id);
1211                        return real_product_id;
1212                }
1213        }
1214
1215        /* No match found. This is either Driving Force or an unknown
1216         * wheel model, do not touch it */
1217        dbg_hid("Wheel with bcdDevice %X was not recognized as multimode wheel, leaving in its current mode\n", bcdDevice);
1218        return 0;
1219}
1220
1221static int lg4ff_handle_multimode_wheel(struct hid_device *hid, u16 *real_product_id, const u16 bcdDevice)
1222{
1223        const u16 reported_product_id = hid->product;
1224        int ret;
1225
1226        *real_product_id = lg4ff_identify_multimode_wheel(hid, reported_product_id, bcdDevice);
1227        /* Probed wheel is not a multimode wheel */
1228        if (!*real_product_id) {
1229                *real_product_id = reported_product_id;
1230                dbg_hid("Wheel is not a multimode wheel\n");
1231                return LG4FF_MMODE_NOT_MULTIMODE;
1232        }
1233
1234        /* Switch from "Driving Force" mode to native mode automatically.
1235         * Otherwise keep the wheel in its current mode */
1236        if (reported_product_id == USB_DEVICE_ID_LOGITECH_WHEEL &&
1237            reported_product_id != *real_product_id &&
1238            !lg4ff_no_autoswitch) {
1239                const struct lg4ff_compat_mode_switch *s = lg4ff_get_mode_switch_command(*real_product_id, *real_product_id);
1240
1241                if (!s) {
1242                        hid_err(hid, "Invalid product id %X\n", *real_product_id);
1243                        return LG4FF_MMODE_NOT_MULTIMODE;
1244                }
1245
1246                ret = lg4ff_switch_compatibility_mode(hid, s);
1247                if (ret) {
1248                        /* Wheel could not have been switched to native mode,
1249                         * leave it in "Driving Force" mode and continue */
1250                        hid_err(hid, "Unable to switch wheel mode, errno %d\n", ret);
1251                        return LG4FF_MMODE_IS_MULTIMODE;
1252                }
1253                return LG4FF_MMODE_SWITCHED;
1254        }
1255
1256        return LG4FF_MMODE_IS_MULTIMODE;
1257}
1258
1259
1260int lg4ff_init(struct hid_device *hid)
1261{
1262        struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list);
1263        struct input_dev *dev = hidinput->input;
1264        struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
1265        struct hid_report *report = list_entry(report_list->next, struct hid_report, list);
1266        const struct usb_device_descriptor *udesc = &(hid_to_usb_dev(hid)->descriptor);
1267        const u16 bcdDevice = le16_to_cpu(udesc->bcdDevice);
1268        const struct lg4ff_multimode_wheel *mmode_wheel = NULL;
1269        struct lg4ff_device_entry *entry;
1270        struct lg_drv_data *drv_data;
1271        int error, i, j;
1272        int mmode_ret, mmode_idx = -1;
1273        u16 real_product_id;
1274
1275        /* Check that the report looks ok */
1276        if (!hid_validate_values(hid, HID_OUTPUT_REPORT, 0, 0, 7))
1277                return -1;
1278
1279        drv_data = hid_get_drvdata(hid);
1280        if (!drv_data) {
1281                hid_err(hid, "Cannot add device, private driver data not allocated\n");
1282                return -1;
1283        }
1284        entry = kzalloc(sizeof(*entry), GFP_KERNEL);
1285        if (!entry)
1286                return -ENOMEM;
1287        spin_lock_init(&entry->report_lock);
1288        entry->report = report;
1289        drv_data->device_props = entry;
1290
1291        /* Check if a multimode wheel has been connected and
1292         * handle it appropriately */
1293        mmode_ret = lg4ff_handle_multimode_wheel(hid, &real_product_id, bcdDevice);
1294
1295        /* Wheel has been told to switch to native mode. There is no point in going on
1296         * with the initialization as the wheel will do a USB reset when it switches mode
1297         */
1298        if (mmode_ret == LG4FF_MMODE_SWITCHED)
1299                return 0;
1300        else if (mmode_ret < 0) {
1301                hid_err(hid, "Unable to switch device mode during initialization, errno %d\n", mmode_ret);
1302                error = mmode_ret;
1303                goto err_init;
1304        }
1305
1306        /* Check what wheel has been connected */
1307        for (i = 0; i < ARRAY_SIZE(lg4ff_devices); i++) {
1308                if (hid->product == lg4ff_devices[i].product_id) {
1309                        dbg_hid("Found compatible device, product ID %04X\n", lg4ff_devices[i].product_id);
1310                        break;
1311                }
1312        }
1313
1314        if (i == ARRAY_SIZE(lg4ff_devices)) {
1315                hid_err(hid, "This device is flagged to be handled by the lg4ff module but this module does not know how to handle it. "
1316                             "Please report this as a bug to LKML, Simon Wood <simon@mungewell.org> or "
1317                             "Michal Maly <madcatxster@devoid-pointer.net>\n");
1318                error = -1;
1319                goto err_init;
1320        }
1321
1322        if (mmode_ret == LG4FF_MMODE_IS_MULTIMODE) {
1323                for (mmode_idx = 0; mmode_idx < ARRAY_SIZE(lg4ff_multimode_wheels); mmode_idx++) {
1324                        if (real_product_id == lg4ff_multimode_wheels[mmode_idx].product_id)
1325                                break;
1326                }
1327
1328                if (mmode_idx == ARRAY_SIZE(lg4ff_multimode_wheels)) {
1329                        hid_err(hid, "Device product ID %X is not listed as a multimode wheel", real_product_id);
1330                        error = -1;
1331                        goto err_init;
1332                }
1333        }
1334
1335        /* Set supported force feedback capabilities */
1336        for (j = 0; lg4ff_devices[i].ff_effects[j] >= 0; j++)
1337                set_bit(lg4ff_devices[i].ff_effects[j], dev->ffbit);
1338
1339        error = input_ff_create_memless(dev, NULL, lg4ff_play);
1340
1341        if (error)
1342                goto err_init;
1343
1344        /* Initialize device properties */
1345        if (mmode_ret == LG4FF_MMODE_IS_MULTIMODE) {
1346                BUG_ON(mmode_idx == -1);
1347                mmode_wheel = &lg4ff_multimode_wheels[mmode_idx];
1348        }
1349        lg4ff_init_wheel_data(&entry->wdata, &lg4ff_devices[i], mmode_wheel, real_product_id);
1350
1351        /* Check if autocentering is available and
1352         * set the centering force to zero by default */
1353        if (test_bit(FF_AUTOCENTER, dev->ffbit)) {
1354                /* Formula Force EX expects different autocentering command */
1355                if ((bcdDevice >> 8) == LG4FF_FFEX_REV_MAJ &&
1356                    (bcdDevice & 0xff) == LG4FF_FFEX_REV_MIN)
1357                        dev->ff->set_autocenter = lg4ff_set_autocenter_ffex;
1358                else
1359                        dev->ff->set_autocenter = lg4ff_set_autocenter_default;
1360
1361                dev->ff->set_autocenter(dev, 0);
1362        }
1363
1364        /* Create sysfs interface */
1365        error = device_create_file(&hid->dev, &dev_attr_combine_pedals);
1366        if (error)
1367                hid_warn(hid, "Unable to create sysfs interface for \"combine\", errno %d\n", error);
1368        error = device_create_file(&hid->dev, &dev_attr_range);
1369        if (error)
1370                hid_warn(hid, "Unable to create sysfs interface for \"range\", errno %d\n", error);
1371        if (mmode_ret == LG4FF_MMODE_IS_MULTIMODE) {
1372                error = device_create_file(&hid->dev, &dev_attr_real_id);
1373                if (error)
1374                        hid_warn(hid, "Unable to create sysfs interface for \"real_id\", errno %d\n", error);
1375                error = device_create_file(&hid->dev, &dev_attr_alternate_modes);
1376                if (error)
1377                        hid_warn(hid, "Unable to create sysfs interface for \"alternate_modes\", errno %d\n", error);
1378        }
1379        dbg_hid("sysfs interface created\n");
1380
1381        /* Set the maximum range to start with */
1382        entry->wdata.range = entry->wdata.max_range;
1383        if (entry->wdata.set_range)
1384                entry->wdata.set_range(hid, entry->wdata.range);
1385
1386#ifdef CONFIG_LEDS_CLASS
1387        /* register led subsystem - G27/G29 only */
1388        entry->wdata.led_state = 0;
1389        for (j = 0; j < 5; j++)
1390                entry->wdata.led[j] = NULL;
1391
1392        if (lg4ff_devices[i].product_id == USB_DEVICE_ID_LOGITECH_G27_WHEEL ||
1393                        lg4ff_devices[i].product_id == USB_DEVICE_ID_LOGITECH_G29_WHEEL) {
1394                struct led_classdev *led;
1395                size_t name_sz;
1396                char *name;
1397
1398                lg4ff_set_leds(hid, 0);
1399
1400                name_sz = strlen(dev_name(&hid->dev)) + 8;
1401
1402                for (j = 0; j < 5; j++) {
1403                        led = kzalloc(sizeof(struct led_classdev)+name_sz, GFP_KERNEL);
1404                        if (!led) {
1405                                hid_err(hid, "can't allocate memory for LED %d\n", j);
1406                                goto err_leds;
1407                        }
1408
1409                        name = (void *)(&led[1]);
1410                        snprintf(name, name_sz, "%s::RPM%d", dev_name(&hid->dev), j+1);
1411                        led->name = name;
1412                        led->brightness = 0;
1413                        led->max_brightness = 1;
1414                        led->brightness_get = lg4ff_led_get_brightness;
1415                        led->brightness_set = lg4ff_led_set_brightness;
1416
1417                        entry->wdata.led[j] = led;
1418                        error = led_classdev_register(&hid->dev, led);
1419
1420                        if (error) {
1421                                hid_err(hid, "failed to register LED %d. Aborting.\n", j);
1422err_leds:
1423                                /* Deregister LEDs (if any) */
1424                                for (j = 0; j < 5; j++) {
1425                                        led = entry->wdata.led[j];
1426                                        entry->wdata.led[j] = NULL;
1427                                        if (!led)
1428                                                continue;
1429                                        led_classdev_unregister(led);
1430                                        kfree(led);
1431                                }
1432                                goto out;       /* Let the driver continue without LEDs */
1433                        }
1434                }
1435        }
1436out:
1437#endif
1438        hid_info(hid, "Force feedback support for Logitech Gaming Wheels\n");
1439        return 0;
1440
1441err_init:
1442        drv_data->device_props = NULL;
1443        kfree(entry);
1444        return error;
1445}
1446
1447int lg4ff_deinit(struct hid_device *hid)
1448{
1449        struct lg4ff_device_entry *entry;
1450        struct lg_drv_data *drv_data;
1451
1452        drv_data = hid_get_drvdata(hid);
1453        if (!drv_data) {
1454                hid_err(hid, "Error while deinitializing device, no private driver data.\n");
1455                return -1;
1456        }
1457        entry = drv_data->device_props;
1458        if (!entry)
1459                goto out; /* Nothing more to do */
1460
1461        /* Multimode devices will have at least the "MODE_NATIVE" bit set */
1462        if (entry->wdata.alternate_modes) {
1463                device_remove_file(&hid->dev, &dev_attr_real_id);
1464                device_remove_file(&hid->dev, &dev_attr_alternate_modes);
1465        }
1466
1467        device_remove_file(&hid->dev, &dev_attr_combine_pedals);
1468        device_remove_file(&hid->dev, &dev_attr_range);
1469#ifdef CONFIG_LEDS_CLASS
1470        {
1471                int j;
1472                struct led_classdev *led;
1473
1474                /* Deregister LEDs (if any) */
1475                for (j = 0; j < 5; j++) {
1476
1477                        led = entry->wdata.led[j];
1478                        entry->wdata.led[j] = NULL;
1479                        if (!led)
1480                                continue;
1481                        led_classdev_unregister(led);
1482                        kfree(led);
1483                }
1484        }
1485#endif
1486        hid_hw_stop(hid);
1487        drv_data->device_props = NULL;
1488
1489        kfree(entry);
1490out:
1491        dbg_hid("Device successfully unregistered\n");
1492        return 0;
1493}
1494