Merge pull request #2 from Lawstorant/main
fix: direction for friction/damper/spring/inertia Added quirks for wheels
This commit is contained in:
18
README.md
18
README.md
@@ -16,8 +16,8 @@ And that's basically it
|
|||||||
1. MOZA R16
|
1. MOZA R16
|
||||||
1. MOZA R21
|
1. MOZA R21
|
||||||
|
|
||||||
### Wheel rims:
|
### Wheel rims (others yet untested):
|
||||||
Not tested
|
1. MOZA RS V2
|
||||||
|
|
||||||
## What works?
|
## What works?
|
||||||
1. FFB (all effects from device descriptor)
|
1. FFB (all effects from device descriptor)
|
||||||
@@ -29,12 +29,14 @@ Not tested
|
|||||||
2. `Firmware Update` function. Use Windows PC or Windows VM at the moment.
|
2. `Firmware Update` function. Use Windows PC or Windows VM at the moment.
|
||||||
3. Setup through MOZA PitHouse even with [some tweaking](#how-to-set-up-a-base-parameters))
|
3. Setup through MOZA PitHouse even with [some tweaking](#how-to-set-up-a-base-parameters))
|
||||||
|
|
||||||
## How to use that driver?
|
## How to use this driver?
|
||||||
You can install it through DKMS or manually.
|
There's an [AUR packege](https://aur.archlinux.org/packages/moza-ff-dkms-git) for Arch Linux maintained by @Lawstorant
|
||||||
|
|
||||||
|
Alternatively, you can install it through DKMS or manually.
|
||||||
### DKMS
|
### DKMS
|
||||||
1. Install `dkms`
|
1. Install `dkms`
|
||||||
2. Clone repository to `/usr/src/moza-ff`
|
2. Clone repository to `/usr/src/moza-ff`
|
||||||
3. Install the module:
|
3. Install the module:
|
||||||
`sudo dkms install /usr/src/moza-ff`
|
`sudo dkms install /usr/src/moza-ff`
|
||||||
4. Update initramfs:
|
4. Update initramfs:
|
||||||
`sudo update-initramfs -u`
|
`sudo update-initramfs -u`
|
||||||
@@ -42,7 +44,7 @@ You can install it through DKMS or manually.
|
|||||||
|
|
||||||
To remove module:
|
To remove module:
|
||||||
`sudo dkms remove moza-ff/<version> --all`
|
`sudo dkms remove moza-ff/<version> --all`
|
||||||
### Manually
|
### Manually
|
||||||
|
|
||||||
1. Install `linux-headers-$(uname -r)`
|
1. Install `linux-headers-$(uname -r)`
|
||||||
2. Clone repository
|
2. Clone repository
|
||||||
@@ -86,8 +88,8 @@ Then you need to force MOZA soft to use hidraw, not SDL, to find devices:
|
|||||||
## Known issues with the driver
|
## Known issues with the driver
|
||||||
1. Firmware update does not work. Please use Windows machine or Windows VM for any firmware updates
|
1. Firmware update does not work. Please use Windows machine or Windows VM for any firmware updates
|
||||||
|
|
||||||
## Known issues with the firmware
|
## Known issues with the firmware
|
||||||
You tell me please
|
You tell me please
|
||||||
|
|
||||||
## DISCLAIMER
|
## DISCLAIMER
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|||||||
16
hid-moza.c
16
hid-moza.c
@@ -9,6 +9,7 @@
|
|||||||
#include <linux/hid.h>
|
#include <linux/hid.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include "hid-moza.h"
|
#include "hid-moza.h"
|
||||||
|
#include "hid-pidff.h"
|
||||||
|
|
||||||
static const struct hid_device_id moza_devices[] = {
|
static const struct hid_device_id moza_devices[] = {
|
||||||
{ HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R3) },
|
{ HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R3) },
|
||||||
@@ -32,8 +33,8 @@ static u8 *moza_report_fixup(struct hid_device *hdev, __u8 *rdesc,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int moza_probe(struct hid_device *hdev,
|
static int moza_probe(struct hid_device *hdev,
|
||||||
const struct hid_device_id *id)
|
const struct hid_device_id *id)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
ret = hid_parse(hdev);
|
ret = hid_parse(hdev);
|
||||||
@@ -48,7 +49,12 @@ static int moza_probe(struct hid_device *hdev,
|
|||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = hid_pidff_init_moza(hdev);
|
/* set PIDFF quirks for moza wheelbases */
|
||||||
|
unsigned quirks = 0;
|
||||||
|
quirks |= PIDFF_QUIRK_FIX_0_INFINITE_LENGTH;
|
||||||
|
quirks |= PIDFF_QUIRK_FIX_WHEEL_DIRECTION;
|
||||||
|
|
||||||
|
ret = hid_pidff_init_with_quirks(hdev, quirks);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
hid_warn(hdev, "Force feedback not supported\n");
|
hid_warn(hdev, "Force feedback not supported\n");
|
||||||
goto err;
|
goto err;
|
||||||
@@ -60,10 +66,10 @@ err:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int moza_input_configured(struct hid_device *hdev,
|
static int moza_input_configured(struct hid_device *hdev,
|
||||||
struct hid_input *hidinput)
|
struct hid_input *hidinput)
|
||||||
{
|
{
|
||||||
struct input_dev *input = hidinput->input;
|
struct input_dev *input = hidinput->input;
|
||||||
input_set_abs_params(input, ABS_X,
|
input_set_abs_params(input, ABS_X,
|
||||||
input->absinfo[ABS_X].minimum, input->absinfo[ABS_X].maximum, 0, 0);
|
input->absinfo[ABS_X].minimum, input->absinfo[ABS_X].maximum, 0, 0);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -10,6 +10,4 @@
|
|||||||
#define USB_DEVICE_ID_MOZA_R16 0x0000
|
#define USB_DEVICE_ID_MOZA_R16 0x0000
|
||||||
#define USB_DEVICE_ID_MOZA_R21 0x0000
|
#define USB_DEVICE_ID_MOZA_R21 0x0000
|
||||||
|
|
||||||
int hid_pidff_init_moza(struct hid_device *hdev);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
64
hid-pidff.c
64
hid-pidff.c
@@ -3,6 +3,8 @@
|
|||||||
* Force feedback driver for USB HID PID compliant devices
|
* Force feedback driver for USB HID PID compliant devices
|
||||||
*
|
*
|
||||||
* Copyright (c) 2005, 2006 Anssi Hannula <anssi.hannula@gmail.com>
|
* Copyright (c) 2005, 2006 Anssi Hannula <anssi.hannula@gmail.com>
|
||||||
|
* Copyright (c) 2024 Makarenko Oleg <oleg@makarenk.ooo>
|
||||||
|
* Copyright (c) 2024 Tomasz Pakuła <tomasz@pakula.org>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -19,6 +21,7 @@
|
|||||||
#include <linux/hid.h>
|
#include <linux/hid.h>
|
||||||
|
|
||||||
//#include "usbhid.h"
|
//#include "usbhid.h"
|
||||||
|
#include "hid-pidff.h"
|
||||||
|
|
||||||
#define PID_EFFECTS_MAX 64
|
#define PID_EFFECTS_MAX 64
|
||||||
|
|
||||||
@@ -184,6 +187,7 @@ struct pidff_device {
|
|||||||
int operation_id[sizeof(pidff_effect_operation_status)];
|
int operation_id[sizeof(pidff_effect_operation_status)];
|
||||||
|
|
||||||
int pid_id[PID_EFFECTS_MAX];
|
int pid_id[PID_EFFECTS_MAX];
|
||||||
|
unsigned quirks;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -297,21 +301,35 @@ static int pidff_needs_set_constant(struct ff_effect *effect,
|
|||||||
static void pidff_set_effect_report(struct pidff_device *pidff,
|
static void pidff_set_effect_report(struct pidff_device *pidff,
|
||||||
struct ff_effect *effect)
|
struct ff_effect *effect)
|
||||||
{
|
{
|
||||||
|
/* check for device quirks */
|
||||||
|
unsigned short direction = effect->direction;
|
||||||
|
unsigned short length = effect->replay.length;
|
||||||
|
|
||||||
|
if (pidff->quirks & PIDFF_QUIRK_FIX_0_INFINITE_LENGTH && length == 0)
|
||||||
|
length = 0xffff;
|
||||||
|
|
||||||
|
if ((effect->type == FF_DAMPER ||
|
||||||
|
effect->type == FF_FRICTION ||
|
||||||
|
effect->type == FF_SPRING ||
|
||||||
|
effect->type == FF_INERTIA) &&
|
||||||
|
pidff->quirks & PIDFF_QUIRK_FIX_WHEEL_DIRECTION)
|
||||||
|
direction = 0x3FFF;
|
||||||
|
|
||||||
pidff->set_effect[PID_EFFECT_BLOCK_INDEX].value[0] =
|
pidff->set_effect[PID_EFFECT_BLOCK_INDEX].value[0] =
|
||||||
pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0];
|
pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0];
|
||||||
pidff->set_effect_type->value[0] =
|
pidff->set_effect_type->value[0] =
|
||||||
pidff->create_new_effect_type->value[0];
|
pidff->create_new_effect_type->value[0];
|
||||||
pidff->set_effect[PID_DURATION].value[0] =
|
pidff->set_effect[PID_DURATION].value[0] = length;
|
||||||
effect->replay.length == 0 ? 0xffff: effect->replay.length;
|
pidff->set_effect[PID_TRIGGER_BUTTON].value[0] =
|
||||||
pidff->set_effect[PID_TRIGGER_BUTTON].value[0] = effect->trigger.button;
|
effect->trigger.button;
|
||||||
pidff->set_effect[PID_TRIGGER_REPEAT_INT].value[0] =
|
pidff->set_effect[PID_TRIGGER_REPEAT_INT].value[0] =
|
||||||
effect->trigger.interval;
|
effect->trigger.interval;
|
||||||
pidff->set_effect[PID_GAIN].value[0] =
|
pidff->set_effect[PID_GAIN].value[0] =
|
||||||
pidff->set_effect[PID_GAIN].field->logical_maximum;
|
pidff->set_effect[PID_GAIN].field->logical_maximum;
|
||||||
pidff->set_effect[PID_DIRECTION_ENABLE].value[0] = 1;
|
pidff->set_effect[PID_DIRECTION_ENABLE].value[0] = 1;
|
||||||
pidff->effect_direction->value[0] =
|
pidff->effect_direction->value[0] =
|
||||||
pidff_rescale(effect->direction, 0xffff,
|
pidff_rescale(direction, 0xffff, pidff->effect_direction);
|
||||||
pidff->effect_direction);
|
|
||||||
pidff->set_effect[PID_START_DELAY].value[0] = effect->replay.delay;
|
pidff->set_effect[PID_START_DELAY].value[0] = effect->replay.delay;
|
||||||
|
|
||||||
hid_hw_request(pidff->hid, pidff->reports[PID_SET_EFFECT],
|
hid_hw_request(pidff->hid, pidff->reports[PID_SET_EFFECT],
|
||||||
@@ -499,12 +517,13 @@ static void pidff_playback_pid(struct pidff_device *pidff, int pid_id, int n)
|
|||||||
} else {
|
} else {
|
||||||
pidff->effect_operation_status->value[0] =
|
pidff->effect_operation_status->value[0] =
|
||||||
pidff->operation_id[PID_EFFECT_START];
|
pidff->operation_id[PID_EFFECT_START];
|
||||||
|
|
||||||
n = clamp(n, pidff->effect_operation[PID_LOOP_COUNT].field->logical_minimum,
|
n = clamp(n, pidff->effect_operation[PID_LOOP_COUNT].field->logical_minimum,
|
||||||
pidff->effect_operation[PID_LOOP_COUNT].field->logical_maximum);
|
pidff->effect_operation[PID_LOOP_COUNT].field->logical_maximum);
|
||||||
pidff->effect_operation[PID_LOOP_COUNT].value[0] = n;
|
pidff->effect_operation[PID_LOOP_COUNT].value[0] = n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hid_dbg(pidff->hid, "Playing effect %d %d times\n", pid_id, n);
|
||||||
hid_hw_request(pidff->hid, pidff->reports[PID_EFFECT_OPERATION],
|
hid_hw_request(pidff->hid, pidff->reports[PID_EFFECT_OPERATION],
|
||||||
HID_REQ_SET_REPORT);
|
HID_REQ_SET_REPORT);
|
||||||
}
|
}
|
||||||
@@ -1231,7 +1250,7 @@ static int pidff_check_autocenter(struct pidff_device *pidff,
|
|||||||
/*
|
/*
|
||||||
* Check if the device is PID and initialize it
|
* Check if the device is PID and initialize it
|
||||||
*/
|
*/
|
||||||
int hid_pidff_init_moza(struct hid_device *hid)
|
int hid_pidff_init(struct hid_device *hid)
|
||||||
{
|
{
|
||||||
struct pidff_device *pidff;
|
struct pidff_device *pidff;
|
||||||
struct hid_input *hidinput = list_entry(hid->inputs.next,
|
struct hid_input *hidinput = list_entry(hid->inputs.next,
|
||||||
@@ -1253,6 +1272,7 @@ int hid_pidff_init_moza(struct hid_device *hid)
|
|||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
pidff->hid = hid;
|
pidff->hid = hid;
|
||||||
|
pidff->quirks = 0;
|
||||||
|
|
||||||
hid_device_io_start(hid);
|
hid_device_io_start(hid);
|
||||||
|
|
||||||
@@ -1318,7 +1338,7 @@ int hid_pidff_init_moza(struct hid_device *hid)
|
|||||||
ff->set_autocenter = pidff_set_autocenter;
|
ff->set_autocenter = pidff_set_autocenter;
|
||||||
ff->playback = pidff_playback;
|
ff->playback = pidff_playback;
|
||||||
|
|
||||||
hid_info(dev, "Force feedback for Moza wheel\n");
|
hid_info(dev, "Force feedback for USB HID PID devices\n");
|
||||||
|
|
||||||
hid_device_io_stop(hid);
|
hid_device_io_stop(hid);
|
||||||
|
|
||||||
@@ -1330,3 +1350,29 @@ int hid_pidff_init_moza(struct hid_device *hid)
|
|||||||
kfree(pidff);
|
kfree(pidff);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if the device is PID and initialize it
|
||||||
|
* Add quirks after initialisation
|
||||||
|
*/
|
||||||
|
int hid_pidff_init_with_quirks(struct hid_device *hid, unsigned quirks)
|
||||||
|
{
|
||||||
|
int error = hid_pidff_init(hid);
|
||||||
|
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
struct hid_input *hidinput = list_entry(hid->inputs.next,
|
||||||
|
struct hid_input, list);
|
||||||
|
struct input_dev *dev = hidinput->input;
|
||||||
|
struct pidff_device *pidff = dev->ff->private;
|
||||||
|
|
||||||
|
/* set quirks on the pidff device */
|
||||||
|
hid_device_io_start(hid);
|
||||||
|
pidff->quirks |= quirks;
|
||||||
|
hid_device_io_stop(hid);
|
||||||
|
|
||||||
|
hid_dbg(dev, "Device quirks: %d\n", pidff->quirks);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|||||||
22
hid-pidff.h
Normal file
22
hid-pidff.h
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
|
#ifndef __HID_PIDFF_H
|
||||||
|
#define __HID_PIDFF_H
|
||||||
|
|
||||||
|
/* PIDFF Quirks to solve issues with certain devices */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Substitute 0 length with 0xffff to resolve issues with
|
||||||
|
* infinite effects coming from windows API
|
||||||
|
*/
|
||||||
|
#define PIDFF_QUIRK_FIX_0_INFINITE_LENGTH BIT(0)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ignore direction for spring/damping/friction/inertia effects
|
||||||
|
* and always set 16384
|
||||||
|
*/
|
||||||
|
#define PIDFF_QUIRK_FIX_WHEEL_DIRECTION BIT(1)
|
||||||
|
|
||||||
|
int hid_pidff_init(struct hid_device *hid);
|
||||||
|
int hid_pidff_init_with_quirks(struct hid_device *hid, unsigned quirks);
|
||||||
|
|
||||||
|
#endif
|
||||||
Reference in New Issue
Block a user