diff --git a/README.md b/README.md index 4f9224d..1959f0e 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ And that's basically it ## What devices are supported? ### Bases: 1. MOZA R3, R5, R9, R12, R16, R21 -2. Cammus C5 +2. Cammus C5, C12 3. VRS DirectForce Pro 4. ... @@ -26,9 +26,9 @@ And that's basically it ## What does not work? -1. Telemetry functions (Shift lights, displays, SimHub, etc), mostly because telemetry works only with proprietary soft, which can't get access to shared memory chunks from games. +1. Telemetry functions. They are handeled by [Monocoque](https://github.com/Spacefreak18/monocoque) 2. `Firmware Update` function. Use Windows PC or Windows VM at the moment. -3. Setup through proprietary software. May require [some tweaking](#how-to-set-up-a-base-parameters)) +3. Setup through proprietary software. May require [some tweaking](#how-to-set-up-a-base-parameters) ## How to install this driver? You can install it through AUR package, through DKMS or manually. @@ -62,7 +62,10 @@ Best for debugging purposes, where you need frequently change codebase/branches To unload module: `sudo rmmod hid_universal_pidff` -## How to set up a wheelbase parameters (max rotation degree, max power, filters, etc)? +### Testing +To test the supported effects, use ffbplay from [ffbtools](https://github.com/berarma/ffbtools) and play the included [effect-test.ffb](./effect-test.ffb) file + +## How to set up a base parameters (max rotation degree, max power, filters, etc)? ### MOZA **[Boxflat](https://github.com/Lawstorant/boxflat)** is a Linux Pit House alternative made by [@Lawstorant](https://github.com/Lawstorant) @@ -99,8 +102,9 @@ Then you need to force VRS soft to use hidraw, not SDL, to find devices: ## Known issues with the driver + ### MOZA -- Buttons above 80 simply don't show up. This is a Linux limitation and we're trying to fix that in the upstream +- Current limit of usable buttons is 160 (up from the Linux default of 80). Create an issue if you want this increased further. ## Known issues with the firmware You tell me please diff --git a/dkms.conf b/dkms.conf index 378a2cf..b5f70e4 100644 --- a/dkms.conf +++ b/dkms.conf @@ -1,5 +1,5 @@ PACKAGE_NAME="universal-pidff" -PACKAGE_VERSION="0.0.6" +PACKAGE_VERSION="0.0.8" MAKE[0]="make KVERSION=$kernelver" CLEAN="make clean" BUILT_MODULE_NAME[0]="hid-universal-pidff" diff --git a/effect-test.ffb b/effect-test.ffb new file mode 100644 index 0000000..ae2be52 --- /dev/null +++ b/effect-test.ffb @@ -0,0 +1,91 @@ +00000000 # Constant force left +00000000 > UPLOAD id:-1 dir:16384 type:CONSTANT level:5000 +00000000 < 0 id:0 +00000000 > PLAY 0 1 + +03000000 # Constant force right +03000000 > UPLOAD id:0 dir:16384 type:CONSTANT level:-5000 + +06000000 # Spring +06000000 > REMOVE 0 +06000000 > UPLOAD id:-1 dir:16384 type:SPRING left_coeff:2000 right_coeff:2000 +06000000 < 0 id:0 +06000000 > PLAY 0 1 + +07000000 # Move the wheel yourself to test these next 3 effects +09000000 > STOP 0 + +09000000 # Damper +09000000 > REMOVE 0 +09000000 > UPLOAD id:-1 dir:16384 type:DAMPER left_coeff:32767 right_coeff:32767 +09000000 < 0 id:0 +09000000 > PLAY 0 1 + +12000000 # Friction +12000000 > STOP 0 +12000000 > REMOVE 0 +12000000 > UPLOAD id:-1 dir:16384 type:FRICTION left_coeff:32767 right_coeff:32767 +12000000 < 0 id:0 +12000000 > PLAY 0 1 + +15000000 # Inertia +15000000 > STOP 0 +15000000 > REMOVE 0 +15000000 > UPLOAD id:-1 dir:16384 type:INERTIA left_coeff:32767 right_coeff:32767 +15000000 < 0 id:0 +15000000 > PLAY 0 1 + +18000000 # Periodic sine +18000000 > REMOVE 0 +18000000 > UPLOAD id:-1 dir:16384 type:PERIODIC waveform:SINE period:100 magnitude:9000 +18000000 < 0 id:0 +18000000 > PLAY 0 1 + +21000000 # Periodic square +21000000 > REMOVE 0 +21000000 > UPLOAD id:-1 dir:16384 type:PERIODIC waveform:SQUARE period:100 magnitude:4000 +21000000 < 0 id:0 +21000000 > PLAY 0 1 + +24000000 # Periodic triangle +24000000 > REMOVE 0 +24000000 > UPLOAD id:-1 dir:16384 type:PERIODIC waveform:TRIANGLE period:100 magnitude:9000 +24000000 < 0 id:0 +24000000 > PLAY 0 1 + +27000000 # Periodic saw up +27000000 > REMOVE 0 +27000000 > UPLOAD id:-1 dir:16384 type:PERIODIC waveform:SAW_UP period:100 magnitude:4000 +27000000 < 0 id:0 +27000000 > PLAY 0 1 + +30000000 # Periodic saw down +30000000 > REMOVE 0 +30000000 > UPLOAD id:-1 dir:16384 type:PERIODIC waveform:SAW_DOWN period:100 magnitude:4000 +30000000 < 0 id:0 +30000000 > PLAY 0 1 + +33000000 # Sine constant force emulation left +33000000 > REMOVE 0 +33000000 > UPLOAD id:-1 dir:16384 type:PERIODIC waveform:SINE period:1000 magnitude:0 offset:4000 +33000000 < 0 id:0 +33000000 > PLAY 0 1 + +36000000 # Sine constant force emulation right +36000000 > UPLOAD id:0 dir:16384 type:PERIODIC waveform:SINE period:1000 magnitude:0 offset:-4000 +39000000 > STOP 0 +39000000 > REMOVE 0 + +40000000 # Back to center +40000000 > UPLOAD id:-1 dir:16384 type:FRICTION left_coeff:16000 right_coeff:16000 +40000000 > UPLOAD id:-1 dir:16384 type:SPRING left_coeff:3000 right_coeff:3000 +40000000 < 0 id:0 +40000000 < 1 id:1 +40100000 > PLAY 0 1 +40100000 > PLAY 1 1 +42000000 > STOP 1 +42000000 > STOP 0 +42000000 > REMOVE 1 +42000000 > REMOVE 0 + +42000000 # Test end diff --git a/hid-ids.h b/hid-ids.h index eb8ad95..c8081b2 100644 --- a/hid-ids.h +++ b/hid-ids.h @@ -2,6 +2,7 @@ #ifndef __HID_IDS_H #define __HID_IDS_H +// Moza Racing #define USB_VENDOR_ID_MOZA 0x346e #define USB_DEVICE_ID_MOZA_R3 0x0005 #define USB_DEVICE_ID_MOZA_R5 0x0004 @@ -9,9 +10,20 @@ #define USB_DEVICE_ID_MOZA_R12 0x0006 #define USB_DEVICE_ID_MOZA_R16_R21 0x0000 +// VRS DrivingForce Pro #define USB_VENDOR_ID_VRS 0x0483 #define USB_DEVICE_ID_VRS_DFP 0xa355 + +// Moza Racing FH5 mode +#define USB_DEVICE_ID_MOZA_R3_FH5 0x0015 +#define USB_DEVICE_ID_MOZA_R5_FH5 0x0014 +#define USB_DEVICE_ID_MOZA_R9_FH5 0x0012 +#define USB_DEVICE_ID_MOZA_R12_FH5 0x0016 +#define USB_DEVICE_ID_MOZA_R16_R21_FH5 0x0010 + +// Cammus #define USB_VENDOR_ID_CAMMUS 0x3416 #define USB_DEVICE_ID_CAMMUS_C5 0x0301 +#define USB_DEVICE_ID_CAMMUS_C12 0x0302 #endif diff --git a/hid-pidff-wrapper.c b/hid-pidff-wrapper.c index 6fc5ad9..2c65cb5 100644 --- a/hid-pidff-wrapper.c +++ b/hid-pidff-wrapper.c @@ -4,14 +4,18 @@ * First of all targeting steering wheels and wheelbases * * Copyright (c) 2024 Makarenko Oleg + * Copyright (c) 2024 Tomasz Pakuła */ #include #include #include +#include #include "hid-ids.h" #include "hid-pidff.h" +#define JOY_RANGE (BTN_DEAD - BTN_JOYSTICK + 1) + static const struct hid_device_id pidff_wheel_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R3), .driver_data = PIDFF_QUIRK_FIX_WHEEL_DIRECTION }, @@ -23,12 +27,24 @@ static const struct hid_device_id pidff_wheel_devices[] = { .driver_data = PIDFF_QUIRK_FIX_WHEEL_DIRECTION }, { HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R16_R21), .driver_data = PIDFF_QUIRK_FIX_WHEEL_DIRECTION }, - { HID_USB_DEVICE(USB_VENDOR_ID_VRS, USB_DEVICE_ID_VRS_DFP), + { HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R3_FH5), + .driver_data = PIDFF_QUIRK_FIX_WHEEL_DIRECTION }, + { HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R5_FH5), + .driver_data = PIDFF_QUIRK_FIX_WHEEL_DIRECTION }, + { HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R9_FH5), + .driver_data = PIDFF_QUIRK_FIX_WHEEL_DIRECTION }, + { HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R12_FH5), + .driver_data = PIDFF_QUIRK_FIX_WHEEL_DIRECTION }, + { HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R16_R21_FH5), + .driver_data = PIDFF_QUIRK_FIX_WHEEL_DIRECTION }, + { HID_USB_DEVICE(USB_VENDOR_ID_CAMMUS, USB_DEVICE_ID_CAMMUS_C5), + .driver_data = PIDFF_QUIRK_NO_DELAY_EFFECT }, + { HID_USB_DEVICE(USB_VENDOR_ID_CAMMUS, USB_DEVICE_ID_CAMMUS_C12), + .driver_data = PIDFF_QUIRK_NO_DELAY_EFFECT }, + { HID_USB_DEVICE(USB_VENDOR_ID_VRS, USB_DEVICE_ID_VRS_DFP), .driver_data = PIDFF_QUIRK_NO_DELAY_EFFECT | PIDFF_QUIRK_NO_STRICT_PID_CONTROL | PIDFF_QUIRK_NO_PID_PARAM_BLOCK_OFFSET }, - { HID_USB_DEVICE(USB_VENDOR_ID_CAMMUS, USB_DEVICE_ID_CAMMUS_C5), - .driver_data = PIDFF_QUIRK_NO_DELAY_EFFECT }, { } }; MODULE_DEVICE_TABLE(hid, pidff_wheel_devices); @@ -54,6 +70,36 @@ static u8 *universal_pidff_report_fixup(struct hid_device *hdev, __u8 *rdesc, return rdesc; } +/* + * Map buttons manually to extend the default joystick buttn limit + */ +static int universal_pidff_input_mapping(struct hid_device *hdev, struct hid_input *hi, + struct hid_field *field, struct hid_usage *usage, + unsigned long **bit, int *max) +{ + // Let the default behavior handle mapping if usage is not a button + if ((usage->hid & HID_USAGE_PAGE) != HID_UP_BUTTON) + return 0; + + int button = ((usage->hid - 1) & HID_USAGE); + int code = button + BTN_JOYSTICK; + + // Detect the end of JOYSTICK buttons range + // KEY_NEXT_FAVORITE = 0x270 + if (code > BTN_DEAD) + code = button + KEY_NEXT_FAVORITE - JOY_RANGE; + + // Map overflowing buttons to KEY_RESERVED for the upcoming new input event + // It will handle button presses differently and won't depend on defined + // ranges. KEY_RESERVED usage is needed for the button to not be ignored. + if (code > KEY_MAX) + code = KEY_RESERVED; + + hid_map_usage(hi, usage, bit, max, EV_KEY, code); + hid_dbg(hdev, "Button %d: usage %d", button, code); + return 1; +} + /* * Check if the device is PID and initialize it @@ -89,17 +135,30 @@ err: static int universal_pidff_input_configured(struct hid_device *hdev, struct hid_input *hidinput) { - // Remove fuzz and deadzone + // Remove fuzz and deadzone from the wheel axis struct input_dev *input = hidinput->input; input_set_abs_params(input, ABS_X, input->absinfo[ABS_X].minimum, input->absinfo[ABS_X].maximum, 0, 0); + // Decrease fuzz and deadzone on additional axes + // Default Linux values are 255 for fuzz and 4096 for flat (deadzone) + int axis; + for (axis = ABS_Y; axis <= ABS_BRAKE; axis++) { + if (!test_bit(axis, input->absbit)) + continue; + + input_set_abs_params(input, axis, + input->absinfo[axis].minimum, + input->absinfo[axis].maximum, 8, 0); + } + return 0; } static struct hid_driver universal_pidff = { .name = "hid-universal-pidff", .id_table = pidff_wheel_devices, + .input_mapping = universal_pidff_input_mapping, .probe = universal_pidff_probe, .input_configured = universal_pidff_input_configured, .report_fixup = universal_pidff_report_fixup @@ -107,5 +166,6 @@ static struct hid_driver universal_pidff = { module_hid_driver(universal_pidff); MODULE_AUTHOR("Oleg Makarenko "); +MODULE_AUTHOR("Tomasz Pakuła "); MODULE_DESCRIPTION("Universal HID PIDFF Driver"); MODULE_LICENSE("GPL");