162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  HID driver for Xin-Mo devices, currently only the Dual Arcade controller.
462306a36Sopenharmony_ci *  Fixes the negative axis event values (the devices sends -2) to match the
562306a36Sopenharmony_ci *  logical axis minimum of the HID report descriptor (the report announces
662306a36Sopenharmony_ci *  -1). It is needed because hid-input discards out of bounds values.
762306a36Sopenharmony_ci *  (This module is based on "hid-saitek" and "hid-lg".)
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci *  Copyright (c) 2013 Olivier Scherler
1062306a36Sopenharmony_ci */
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci/*
1362306a36Sopenharmony_ci */
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#include <linux/device.h>
1662306a36Sopenharmony_ci#include <linux/hid.h>
1762306a36Sopenharmony_ci#include <linux/module.h>
1862306a36Sopenharmony_ci#include <linux/kernel.h>
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#include "hid-ids.h"
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci/*
2362306a36Sopenharmony_ci * Fix negative events that are out of bounds.
2462306a36Sopenharmony_ci */
2562306a36Sopenharmony_cistatic int xinmo_event(struct hid_device *hdev, struct hid_field *field,
2662306a36Sopenharmony_ci		struct hid_usage *usage, __s32 value)
2762306a36Sopenharmony_ci{
2862306a36Sopenharmony_ci	switch (usage->code) {
2962306a36Sopenharmony_ci	case ABS_X:
3062306a36Sopenharmony_ci	case ABS_Y:
3162306a36Sopenharmony_ci	case ABS_Z:
3262306a36Sopenharmony_ci	case ABS_RX:
3362306a36Sopenharmony_ci		if (value < -1) {
3462306a36Sopenharmony_ci			input_event(field->hidinput->input, usage->type,
3562306a36Sopenharmony_ci				usage->code, -1);
3662306a36Sopenharmony_ci			return 1;
3762306a36Sopenharmony_ci		}
3862306a36Sopenharmony_ci		break;
3962306a36Sopenharmony_ci	}
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci	return 0;
4262306a36Sopenharmony_ci}
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_cistatic const struct hid_device_id xinmo_devices[] = {
4562306a36Sopenharmony_ci	{ HID_USB_DEVICE(USB_VENDOR_ID_XIN_MO, USB_DEVICE_ID_XIN_MO_DUAL_ARCADE) },
4662306a36Sopenharmony_ci	{ HID_USB_DEVICE(USB_VENDOR_ID_XIN_MO, USB_DEVICE_ID_THT_2P_ARCADE) },
4762306a36Sopenharmony_ci	{ }
4862306a36Sopenharmony_ci};
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ciMODULE_DEVICE_TABLE(hid, xinmo_devices);
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_cistatic struct hid_driver xinmo_driver = {
5362306a36Sopenharmony_ci	.name = "xinmo",
5462306a36Sopenharmony_ci	.id_table = xinmo_devices,
5562306a36Sopenharmony_ci	.event = xinmo_event
5662306a36Sopenharmony_ci};
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_cimodule_hid_driver(xinmo_driver);
5962306a36Sopenharmony_ciMODULE_LICENSE("GPL");
60