Thread (13 messages) 13 messages, 3 authors, 2018-03-01

Re: [PATCH v4 1/4] HID: add driver for Valve Steam Controller

From: Andy Shevchenko <hidden>
Date: 2018-02-28 19:21:18
Also in: lkml

On Wed, Feb 28, 2018 at 8:43 PM, Rodrigo Rivas Costa
[off-list ref] wrote:
There are two ways to connect the Steam Controller: directly to the USB
or with the USB wireless adapter.  Both methods are similar, but the
wireless adapter can connect up to 4 devices at the same time.

The wired device will appear as 3 interfaces: a virtual mouse, a virtual
keyboard and a custom HID device.

The wireless device will appear as 5 interfaces: a virtual keyboard and
4 custom HID devices, that will remain silent until a device is actually
connected.

The custom HID device has a report descriptor with all vendor specific
usages, so the hid-generic is not very useful. In a PC/SteamBox Valve
Steam Client provices a software translation by using direct USB access
and a creates a uinput virtual gamepad.

This driver was reverse engineered to provide direct kernel support in
case you cannot, or do not want to, use Valve Steam Client. It disables
the virtual keyboard and mouse, as they are not so useful when you have
a working gamepad.
+// SPDX-License-Identifier: GPL-2.0
+MODULE_LICENSE("GPL");
Not the same.
+static void steam_unregister(struct steam_device *steam)
+{
+       struct input_dev *input;
+
+       rcu_read_lock();
+       input = rcu_dereference(steam->input);
+       rcu_read_unlock();
+
+       if (input) {
if (!input)
 return;

?
+               RCU_INIT_POINTER(steam->input, NULL);
+               synchronize_rcu();
+               hid_info(steam->hdev, "Steam Controller disconnected");
+               input_unregister_device(input);
+       }
+}
+static bool steam_is_valve_interface(struct hid_device *hdev)
+{
+       struct hid_report_enum *rep_enum;
+       struct hid_report *hreport;
+
+       /*
+        * The wired device creates 3 interfaces:
+        *  0: emulated mouse.
+        *  1: emulated keyboard.
+        *  2: the real game pad.
+        * The wireless device creates 5 interfaces:
+        *  0: emulated keyboard.
+        *  1-4: slots where up to 4 real game pads will be connected to.
+        * We know which one is the real gamepad interface because they are the
+        * only ones with a feature report.
+        */
+       rep_enum = &hdev->report_enum[HID_FEATURE_REPORT];
+       list_for_each_entry(hreport, &rep_enum->report_list, list) {
+               /* should we check hreport->id == 0? */
+               return true;
+       }
+       return false;
So, for now it's just an equivalent of

return !list_empty();

?
+}
+       /*
+        * From this point on, if anything fails return 0 and ignores
+        * the error, so that the default HID devices are still bound.
+        */
+       steam = devm_kzalloc(&hdev->dev,
+                       sizeof(struct steam_device), GFP_KERNEL);
sizeof(*steam) saves a line.
+       if (!steam) {
+               ret = -ENOMEM;
+               goto mem_fail;
+       }
+static void steam_remove(struct hid_device *hdev)
+{
+       struct steam_device *steam = hid_get_drvdata(hdev);
+
+       if (steam && (steam->quirks & STEAM_QUIRK_WIRELESS)) {
+               hid_info(hdev, "Steam wireless receiver disconnected");
+               hid_hw_close(hdev);
+       }
+
+       hid_hw_stop(hdev);
+
+       if (steam) {
+               cancel_work_sync(&steam->work_connect);
+               steam_unregister(steam);
+               hid_set_drvdata(hdev, NULL);
Hmm.. Doesn't HID do this?
+       }
if (steam) {
...
       hid_hw_stop(hdev);
...
} else {
       hid_hw_stop(hdev);
}

?
+}
+static void steam_do_input_event(struct steam_device *steam,
+               struct input_dev *input, u8 *data)
+{
+       /* 24 bits of buttons */
+       u8 b8, b9, b10;
+       bool lpad_touched, lpad_and_joy;
+
+       b8 = data[8];
+       b9 = data[9];
+       b10 = data[10];
+
+       input_report_abs(input, ABS_Z, data[11]);
+       input_report_abs(input, ABS_RZ, data[12]);
+
+       /*
+        * These two bits tells how to interpret the values X and Y.
+        * lpad_and_joy tells that the joystick and the lpad are used at the
+        * same time.
+        * lpad_touched tells whether X/Y are to be read as lpad coord or
+        * joystick values.
+        * (lpad_touched || lpad_and_joy) tells if the lpad is really touched.
+        */
+       lpad_touched = b10 & 0x08;
BIT(3) ?
+       lpad_and_joy = b10 & 0x80;
BIT(7) ?
+       input_event(input, EV_KEY, BTN_TR2, !!(b8 & 0x01));
+       input_event(input, EV_KEY, BTN_TL2, !!(b8 & 0x02));
+       input_event(input, EV_KEY, BTN_TR, !!(b8 & 0x04));
+       input_event(input, EV_KEY, BTN_TL, !!(b8 & 0x08));
+       input_event(input, EV_KEY, BTN_Y, !!(b8 & 0x10));
+       input_event(input, EV_KEY, BTN_B, !!(b8 & 0x20));
+       input_event(input, EV_KEY, BTN_X, !!(b8 & 0x40));
+       input_event(input, EV_KEY, BTN_A, !!(b8 & 0x80));
+       input_event(input, EV_KEY, BTN_SELECT, !!(b9 & 0x10));
+       input_event(input, EV_KEY, BTN_MODE, !!(b9 & 0x20));
+       input_event(input, EV_KEY, BTN_START, !!(b9 & 0x40));
+       input_event(input, EV_KEY, BTN_GEAR_DOWN, !!(b9 & 0x80));
+       input_event(input, EV_KEY, BTN_GEAR_UP, !!(b10 & 0x01));
+       input_event(input, EV_KEY, BTN_THUMBR, !!(b10 & 0x04));
+       input_event(input, EV_KEY, BTN_THUMBL, !!(b10 & 0x40));
+       input_event(input, EV_KEY, BTN_THUMB, lpad_touched || lpad_and_joy);
+       input_event(input, EV_KEY, BTN_THUMB2, !!(b10 & 0x10));
BIT(x) ?
+
+       input_report_abs(input, ABS_HAT0X,
+                       !!(b9 & 0x02) - !!(b9 & 0x04));
+       input_report_abs(input, ABS_HAT0Y,
+                       !!(b9 & 0x08) - !!(b9 & 0x01));
BIT(x) ?
+}
+static int steam_raw_event(struct hid_device *hdev,
+                       struct hid_report *report, u8 *data,
+                       int size)
+{
+       struct steam_device *steam = hid_get_drvdata(hdev);
+       struct input_dev *input;
+
+       if (!steam)
+               return 0;
When it's possible?
+       return 0;
+}
-- 
With Best Regards,
Andy Shevchenko
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help