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