Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 
0003 /*
0004  *  LED & force feedback support for BigBen Interactive
0005  *
0006  *  0x146b:0x0902 "Bigben Interactive Bigben Game Pad"
0007  *  "Kid-friendly Wired Controller" PS3OFMINIPAD SONY
0008  *  sold for use with the PS3
0009  *
0010  *  Copyright (c) 2018 Hanno Zulla <kontakt@hanno.de>
0011  */
0012 
0013 #include <linux/input.h>
0014 #include <linux/slab.h>
0015 #include <linux/module.h>
0016 #include <linux/leds.h>
0017 #include <linux/hid.h>
0018 
0019 #include "hid-ids.h"
0020 
0021 
0022 /*
0023  * The original descriptor for 0x146b:0x0902
0024  *
0025  *   0x05, 0x01,        // Usage Page (Generic Desktop Ctrls)
0026  *   0x09, 0x05,        // Usage (Game Pad)
0027  *   0xA1, 0x01,        // Collection (Application)
0028  *   0x15, 0x00,        //   Logical Minimum (0)
0029  *   0x25, 0x01,        //   Logical Maximum (1)
0030  *   0x35, 0x00,        //   Physical Minimum (0)
0031  *   0x45, 0x01,        //   Physical Maximum (1)
0032  *   0x75, 0x01,        //   Report Size (1)
0033  *   0x95, 0x0D,        //   Report Count (13)
0034  *   0x05, 0x09,        //   Usage Page (Button)
0035  *   0x19, 0x01,        //   Usage Minimum (0x01)
0036  *   0x29, 0x0D,        //   Usage Maximum (0x0D)
0037  *   0x81, 0x02,        //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0038  *   0x95, 0x03,        //   Report Count (3)
0039  *   0x81, 0x01,        //   Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
0040  *   0x05, 0x01,        //   Usage Page (Generic Desktop Ctrls)
0041  *   0x25, 0x07,        //   Logical Maximum (7)
0042  *   0x46, 0x3B, 0x01,  //   Physical Maximum (315)
0043  *   0x75, 0x04,        //   Report Size (4)
0044  *   0x95, 0x01,        //   Report Count (1)
0045  *   0x65, 0x14,        //   Unit (System: English Rotation, Length: Centimeter)
0046  *   0x09, 0x39,        //   Usage (Hat switch)
0047  *   0x81, 0x42,        //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,Null State)
0048  *   0x65, 0x00,        //   Unit (None)
0049  *   0x95, 0x01,        //   Report Count (1)
0050  *   0x81, 0x01,        //   Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
0051  *   0x26, 0xFF, 0x00,  //   Logical Maximum (255)
0052  *   0x46, 0xFF, 0x00,  //   Physical Maximum (255)
0053  *   0x09, 0x30,        //   Usage (X)
0054  *   0x09, 0x31,        //   Usage (Y)
0055  *   0x09, 0x32,        //   Usage (Z)
0056  *   0x09, 0x35,        //   Usage (Rz)
0057  *   0x75, 0x08,        //   Report Size (8)
0058  *   0x95, 0x04,        //   Report Count (4)
0059  *   0x81, 0x02,        //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0060  *   0x06, 0x00, 0xFF,  //   Usage Page (Vendor Defined 0xFF00)
0061  *   0x09, 0x20,        //   Usage (0x20)
0062  *   0x09, 0x21,        //   Usage (0x21)
0063  *   0x09, 0x22,        //   Usage (0x22)
0064  *   0x09, 0x23,        //   Usage (0x23)
0065  *   0x09, 0x24,        //   Usage (0x24)
0066  *   0x09, 0x25,        //   Usage (0x25)
0067  *   0x09, 0x26,        //   Usage (0x26)
0068  *   0x09, 0x27,        //   Usage (0x27)
0069  *   0x09, 0x28,        //   Usage (0x28)
0070  *   0x09, 0x29,        //   Usage (0x29)
0071  *   0x09, 0x2A,        //   Usage (0x2A)
0072  *   0x09, 0x2B,        //   Usage (0x2B)
0073  *   0x95, 0x0C,        //   Report Count (12)
0074  *   0x81, 0x02,        //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0075  *   0x0A, 0x21, 0x26,  //   Usage (0x2621)
0076  *   0x95, 0x08,        //   Report Count (8)
0077  *   0xB1, 0x02,        //   Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0078  *   0x0A, 0x21, 0x26,  //   Usage (0x2621)
0079  *   0x91, 0x02,        //   Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0080  *   0x26, 0xFF, 0x03,  //   Logical Maximum (1023)
0081  *   0x46, 0xFF, 0x03,  //   Physical Maximum (1023)
0082  *   0x09, 0x2C,        //   Usage (0x2C)
0083  *   0x09, 0x2D,        //   Usage (0x2D)
0084  *   0x09, 0x2E,        //   Usage (0x2E)
0085  *   0x09, 0x2F,        //   Usage (0x2F)
0086  *   0x75, 0x10,        //   Report Size (16)
0087  *   0x95, 0x04,        //   Report Count (4)
0088  *   0x81, 0x02,        //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0089  *   0xC0,              // End Collection
0090  */
0091 
0092 #define PID0902_RDESC_ORIG_SIZE 137
0093 
0094 /*
0095  * The fixed descriptor for 0x146b:0x0902
0096  *
0097  * - map buttons according to gamepad.rst
0098  * - assign right stick from Z/Rz to Rx/Ry
0099  * - map previously unused analog trigger data to Z/RZ
0100  * - simplify feature and output descriptor
0101  */
0102 static __u8 pid0902_rdesc_fixed[] = {
0103     0x05, 0x01,        /* Usage Page (Generic Desktop Ctrls) */
0104     0x09, 0x05,        /* Usage (Game Pad) */
0105     0xA1, 0x01,        /* Collection (Application) */
0106     0x15, 0x00,        /*   Logical Minimum (0) */
0107     0x25, 0x01,        /*   Logical Maximum (1) */
0108     0x35, 0x00,        /*   Physical Minimum (0) */
0109     0x45, 0x01,        /*   Physical Maximum (1) */
0110     0x75, 0x01,        /*   Report Size (1) */
0111     0x95, 0x0D,        /*   Report Count (13) */
0112     0x05, 0x09,        /*   Usage Page (Button) */
0113     0x09, 0x05,        /*   Usage (BTN_WEST) */
0114     0x09, 0x01,        /*   Usage (BTN_SOUTH) */
0115     0x09, 0x02,        /*   Usage (BTN_EAST) */
0116     0x09, 0x04,        /*   Usage (BTN_NORTH) */
0117     0x09, 0x07,        /*   Usage (BTN_TL) */
0118     0x09, 0x08,        /*   Usage (BTN_TR) */
0119     0x09, 0x09,        /*   Usage (BTN_TL2) */
0120     0x09, 0x0A,        /*   Usage (BTN_TR2) */
0121     0x09, 0x0B,        /*   Usage (BTN_SELECT) */
0122     0x09, 0x0C,        /*   Usage (BTN_START) */
0123     0x09, 0x0E,        /*   Usage (BTN_THUMBL) */
0124     0x09, 0x0F,        /*   Usage (BTN_THUMBR) */
0125     0x09, 0x0D,        /*   Usage (BTN_MODE) */
0126     0x81, 0x02,        /*   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */
0127     0x75, 0x01,        /*   Report Size (1) */
0128     0x95, 0x03,        /*   Report Count (3) */
0129     0x81, 0x01,        /*   Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) */
0130     0x05, 0x01,        /*   Usage Page (Generic Desktop Ctrls) */
0131     0x25, 0x07,        /*   Logical Maximum (7) */
0132     0x46, 0x3B, 0x01,  /*   Physical Maximum (315) */
0133     0x75, 0x04,        /*   Report Size (4) */
0134     0x95, 0x01,        /*   Report Count (1) */
0135     0x65, 0x14,        /*   Unit (System: English Rotation, Length: Centimeter) */
0136     0x09, 0x39,        /*   Usage (Hat switch) */
0137     0x81, 0x42,        /*   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,Null State) */
0138     0x65, 0x00,        /*   Unit (None) */
0139     0x95, 0x01,        /*   Report Count (1) */
0140     0x81, 0x01,        /*   Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) */
0141     0x26, 0xFF, 0x00,  /*   Logical Maximum (255) */
0142     0x46, 0xFF, 0x00,  /*   Physical Maximum (255) */
0143     0x09, 0x30,        /*   Usage (X) */
0144     0x09, 0x31,        /*   Usage (Y) */
0145     0x09, 0x33,        /*   Usage (Rx) */
0146     0x09, 0x34,        /*   Usage (Ry) */
0147     0x75, 0x08,        /*   Report Size (8) */
0148     0x95, 0x04,        /*   Report Count (4) */
0149     0x81, 0x02,        /*   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */
0150     0x95, 0x0A,        /*   Report Count (10) */
0151     0x81, 0x01,        /*   Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) */
0152     0x05, 0x01,        /*   Usage Page (Generic Desktop Ctrls) */
0153     0x26, 0xFF, 0x00,  /*   Logical Maximum (255) */
0154     0x46, 0xFF, 0x00,  /*   Physical Maximum (255) */
0155     0x09, 0x32,        /*   Usage (Z) */
0156     0x09, 0x35,        /*   Usage (Rz) */
0157     0x95, 0x02,        /*   Report Count (2) */
0158     0x81, 0x02,        /*   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */
0159     0x95, 0x08,        /*   Report Count (8) */
0160     0x81, 0x01,        /*   Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) */
0161     0x06, 0x00, 0xFF,  /*   Usage Page (Vendor Defined 0xFF00) */
0162     0xB1, 0x02,        /*   Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) */
0163     0x0A, 0x21, 0x26,  /*   Usage (0x2621) */
0164     0x95, 0x08,        /*   Report Count (8) */
0165     0x91, 0x02,        /*   Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) */
0166     0x0A, 0x21, 0x26,  /*   Usage (0x2621) */
0167     0x95, 0x08,        /*   Report Count (8) */
0168     0x81, 0x02,        /*   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */
0169     0xC0,              /* End Collection */
0170 };
0171 
0172 #define NUM_LEDS 4
0173 
0174 struct bigben_device {
0175     struct hid_device *hid;
0176     struct hid_report *report;
0177     bool removed;
0178     u8 led_state;         /* LED1 = 1 .. LED4 = 8 */
0179     u8 right_motor_on;    /* right motor off/on 0/1 */
0180     u8 left_motor_force;  /* left motor force 0-255 */
0181     struct led_classdev *leds[NUM_LEDS];
0182     bool work_led;
0183     bool work_ff;
0184     struct work_struct worker;
0185 };
0186 
0187 
0188 static void bigben_worker(struct work_struct *work)
0189 {
0190     struct bigben_device *bigben = container_of(work,
0191         struct bigben_device, worker);
0192     struct hid_field *report_field = bigben->report->field[0];
0193 
0194     if (bigben->removed || !report_field)
0195         return;
0196 
0197     if (bigben->work_led) {
0198         bigben->work_led = false;
0199         report_field->value[0] = 0x01; /* 1 = led message */
0200         report_field->value[1] = 0x08; /* reserved value, always 8 */
0201         report_field->value[2] = bigben->led_state;
0202         report_field->value[3] = 0x00; /* padding */
0203         report_field->value[4] = 0x00; /* padding */
0204         report_field->value[5] = 0x00; /* padding */
0205         report_field->value[6] = 0x00; /* padding */
0206         report_field->value[7] = 0x00; /* padding */
0207         hid_hw_request(bigben->hid, bigben->report, HID_REQ_SET_REPORT);
0208     }
0209 
0210     if (bigben->work_ff) {
0211         bigben->work_ff = false;
0212         report_field->value[0] = 0x02; /* 2 = rumble effect message */
0213         report_field->value[1] = 0x08; /* reserved value, always 8 */
0214         report_field->value[2] = bigben->right_motor_on;
0215         report_field->value[3] = bigben->left_motor_force;
0216         report_field->value[4] = 0xff; /* duration 0-254 (255 = nonstop) */
0217         report_field->value[5] = 0x00; /* padding */
0218         report_field->value[6] = 0x00; /* padding */
0219         report_field->value[7] = 0x00; /* padding */
0220         hid_hw_request(bigben->hid, bigben->report, HID_REQ_SET_REPORT);
0221     }
0222 }
0223 
0224 static int hid_bigben_play_effect(struct input_dev *dev, void *data,
0225              struct ff_effect *effect)
0226 {
0227     struct hid_device *hid = input_get_drvdata(dev);
0228     struct bigben_device *bigben = hid_get_drvdata(hid);
0229     u8 right_motor_on;
0230     u8 left_motor_force;
0231 
0232     if (!bigben) {
0233         hid_err(hid, "no device data\n");
0234         return 0;
0235     }
0236 
0237     if (effect->type != FF_RUMBLE)
0238         return 0;
0239 
0240     right_motor_on   = effect->u.rumble.weak_magnitude ? 1 : 0;
0241     left_motor_force = effect->u.rumble.strong_magnitude / 256;
0242 
0243     if (right_motor_on != bigben->right_motor_on ||
0244             left_motor_force != bigben->left_motor_force) {
0245         bigben->right_motor_on   = right_motor_on;
0246         bigben->left_motor_force = left_motor_force;
0247         bigben->work_ff = true;
0248         schedule_work(&bigben->worker);
0249     }
0250 
0251     return 0;
0252 }
0253 
0254 static void bigben_set_led(struct led_classdev *led,
0255     enum led_brightness value)
0256 {
0257     struct device *dev = led->dev->parent;
0258     struct hid_device *hid = to_hid_device(dev);
0259     struct bigben_device *bigben = hid_get_drvdata(hid);
0260     int n;
0261     bool work;
0262 
0263     if (!bigben) {
0264         hid_err(hid, "no device data\n");
0265         return;
0266     }
0267 
0268     for (n = 0; n < NUM_LEDS; n++) {
0269         if (led == bigben->leds[n]) {
0270             if (value == LED_OFF) {
0271                 work = (bigben->led_state & BIT(n));
0272                 bigben->led_state &= ~BIT(n);
0273             } else {
0274                 work = !(bigben->led_state & BIT(n));
0275                 bigben->led_state |= BIT(n);
0276             }
0277 
0278             if (work) {
0279                 bigben->work_led = true;
0280                 schedule_work(&bigben->worker);
0281             }
0282             return;
0283         }
0284     }
0285 }
0286 
0287 static enum led_brightness bigben_get_led(struct led_classdev *led)
0288 {
0289     struct device *dev = led->dev->parent;
0290     struct hid_device *hid = to_hid_device(dev);
0291     struct bigben_device *bigben = hid_get_drvdata(hid);
0292     int n;
0293 
0294     if (!bigben) {
0295         hid_err(hid, "no device data\n");
0296         return LED_OFF;
0297     }
0298 
0299     for (n = 0; n < NUM_LEDS; n++) {
0300         if (led == bigben->leds[n])
0301             return (bigben->led_state & BIT(n)) ? LED_ON : LED_OFF;
0302     }
0303 
0304     return LED_OFF;
0305 }
0306 
0307 static void bigben_remove(struct hid_device *hid)
0308 {
0309     struct bigben_device *bigben = hid_get_drvdata(hid);
0310 
0311     bigben->removed = true;
0312     cancel_work_sync(&bigben->worker);
0313     hid_hw_stop(hid);
0314 }
0315 
0316 static int bigben_probe(struct hid_device *hid,
0317     const struct hid_device_id *id)
0318 {
0319     struct bigben_device *bigben;
0320     struct hid_input *hidinput;
0321     struct list_head *report_list;
0322     struct led_classdev *led;
0323     char *name;
0324     size_t name_sz;
0325     int n, error;
0326 
0327     bigben = devm_kzalloc(&hid->dev, sizeof(*bigben), GFP_KERNEL);
0328     if (!bigben)
0329         return -ENOMEM;
0330     hid_set_drvdata(hid, bigben);
0331     bigben->hid = hid;
0332     bigben->removed = false;
0333 
0334     error = hid_parse(hid);
0335     if (error) {
0336         hid_err(hid, "parse failed\n");
0337         return error;
0338     }
0339 
0340     error = hid_hw_start(hid, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
0341     if (error) {
0342         hid_err(hid, "hw start failed\n");
0343         return error;
0344     }
0345 
0346     report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
0347     bigben->report = list_entry(report_list->next,
0348         struct hid_report, list);
0349 
0350     if (list_empty(&hid->inputs)) {
0351         hid_err(hid, "no inputs found\n");
0352         error = -ENODEV;
0353         goto error_hw_stop;
0354     }
0355 
0356     hidinput = list_first_entry(&hid->inputs, struct hid_input, list);
0357     set_bit(FF_RUMBLE, hidinput->input->ffbit);
0358 
0359     INIT_WORK(&bigben->worker, bigben_worker);
0360 
0361     error = input_ff_create_memless(hidinput->input, NULL,
0362         hid_bigben_play_effect);
0363     if (error)
0364         goto error_hw_stop;
0365 
0366     name_sz = strlen(dev_name(&hid->dev)) + strlen(":red:bigben#") + 1;
0367 
0368     for (n = 0; n < NUM_LEDS; n++) {
0369         led = devm_kzalloc(
0370             &hid->dev,
0371             sizeof(struct led_classdev) + name_sz,
0372             GFP_KERNEL
0373         );
0374         if (!led) {
0375             error = -ENOMEM;
0376             goto error_hw_stop;
0377         }
0378         name = (void *)(&led[1]);
0379         snprintf(name, name_sz,
0380             "%s:red:bigben%d",
0381             dev_name(&hid->dev), n + 1
0382         );
0383         led->name = name;
0384         led->brightness = (n == 0) ? LED_ON : LED_OFF;
0385         led->max_brightness = 1;
0386         led->brightness_get = bigben_get_led;
0387         led->brightness_set = bigben_set_led;
0388         bigben->leds[n] = led;
0389         error = devm_led_classdev_register(&hid->dev, led);
0390         if (error)
0391             goto error_hw_stop;
0392     }
0393 
0394     /* initial state: LED1 is on, no rumble effect */
0395     bigben->led_state = BIT(0);
0396     bigben->right_motor_on = 0;
0397     bigben->left_motor_force = 0;
0398     bigben->work_led = true;
0399     bigben->work_ff = true;
0400     schedule_work(&bigben->worker);
0401 
0402     hid_info(hid, "LED and force feedback support for BigBen gamepad\n");
0403 
0404     return 0;
0405 
0406 error_hw_stop:
0407     hid_hw_stop(hid);
0408     return error;
0409 }
0410 
0411 static __u8 *bigben_report_fixup(struct hid_device *hid, __u8 *rdesc,
0412     unsigned int *rsize)
0413 {
0414     if (*rsize == PID0902_RDESC_ORIG_SIZE) {
0415         rdesc = pid0902_rdesc_fixed;
0416         *rsize = sizeof(pid0902_rdesc_fixed);
0417     } else
0418         hid_warn(hid, "unexpected rdesc, please submit for review\n");
0419     return rdesc;
0420 }
0421 
0422 static const struct hid_device_id bigben_devices[] = {
0423     { HID_USB_DEVICE(USB_VENDOR_ID_BIGBEN, USB_DEVICE_ID_BIGBEN_PS3OFMINIPAD) },
0424     { }
0425 };
0426 MODULE_DEVICE_TABLE(hid, bigben_devices);
0427 
0428 static struct hid_driver bigben_driver = {
0429     .name = "bigben",
0430     .id_table = bigben_devices,
0431     .probe = bigben_probe,
0432     .report_fixup = bigben_report_fixup,
0433     .remove = bigben_remove,
0434 };
0435 module_hid_driver(bigben_driver);
0436 
0437 MODULE_LICENSE("GPL");