Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *  Force feedback support for Logitech RumblePad and Rumblepad 2
0004  *
0005  *  Copyright (c) 2008 Anssi Hannula <anssi.hannula@gmail.com>
0006  */
0007 
0008 /*
0009  */
0010 
0011 
0012 #include <linux/input.h>
0013 #include <linux/slab.h>
0014 #include <linux/hid.h>
0015 
0016 #include "hid-lg.h"
0017 
0018 struct lg2ff_device {
0019     struct hid_report *report;
0020 };
0021 
0022 static int play_effect(struct input_dev *dev, void *data,
0023              struct ff_effect *effect)
0024 {
0025     struct hid_device *hid = input_get_drvdata(dev);
0026     struct lg2ff_device *lg2ff = data;
0027     int weak, strong;
0028 
0029     strong = effect->u.rumble.strong_magnitude;
0030     weak = effect->u.rumble.weak_magnitude;
0031 
0032     if (weak || strong) {
0033         weak = weak * 0xff / 0xffff;
0034         strong = strong * 0xff / 0xffff;
0035 
0036         lg2ff->report->field[0]->value[0] = 0x51;
0037         lg2ff->report->field[0]->value[2] = weak;
0038         lg2ff->report->field[0]->value[4] = strong;
0039     } else {
0040         lg2ff->report->field[0]->value[0] = 0xf3;
0041         lg2ff->report->field[0]->value[2] = 0x00;
0042         lg2ff->report->field[0]->value[4] = 0x00;
0043     }
0044 
0045     hid_hw_request(hid, lg2ff->report, HID_REQ_SET_REPORT);
0046     return 0;
0047 }
0048 
0049 int lg2ff_init(struct hid_device *hid)
0050 {
0051     struct lg2ff_device *lg2ff;
0052     struct hid_report *report;
0053     struct hid_input *hidinput;
0054     struct input_dev *dev;
0055     int error;
0056 
0057     if (list_empty(&hid->inputs)) {
0058         hid_err(hid, "no inputs found\n");
0059         return -ENODEV;
0060     }
0061     hidinput = list_entry(hid->inputs.next, struct hid_input, list);
0062     dev = hidinput->input;
0063 
0064     /* Check that the report looks ok */
0065     report = hid_validate_values(hid, HID_OUTPUT_REPORT, 0, 0, 7);
0066     if (!report)
0067         return -ENODEV;
0068 
0069     lg2ff = kmalloc(sizeof(struct lg2ff_device), GFP_KERNEL);
0070     if (!lg2ff)
0071         return -ENOMEM;
0072 
0073     set_bit(FF_RUMBLE, dev->ffbit);
0074 
0075     error = input_ff_create_memless(dev, lg2ff, play_effect);
0076     if (error) {
0077         kfree(lg2ff);
0078         return error;
0079     }
0080 
0081     lg2ff->report = report;
0082     report->field[0]->value[0] = 0xf3;
0083     report->field[0]->value[1] = 0x00;
0084     report->field[0]->value[2] = 0x00;
0085     report->field[0]->value[3] = 0x00;
0086     report->field[0]->value[4] = 0x00;
0087     report->field[0]->value[5] = 0x00;
0088     report->field[0]->value[6] = 0x00;
0089 
0090     hid_hw_request(hid, report, HID_REQ_SET_REPORT);
0091 
0092     hid_info(hid, "Force feedback for Logitech variant 2 rumble devices by Anssi Hannula <anssi.hannula@gmail.com>\n");
0093 
0094     return 0;
0095 }