mirror of
https://github.com/medusalix/xone.git
synced 2024-11-25 05:26:13 +00:00
29ec3577e5
See code comments.
207 lines
5.8 KiB
C
207 lines
5.8 KiB
C
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
/*
|
|
* Copyright (C) 2024 Severin von Wnuck-Lipinski <severinvonw@outlook.de>
|
|
*/
|
|
|
|
#include <linux/module.h>
|
|
|
|
#include "common.h"
|
|
#include "../auth/auth.h"
|
|
|
|
#define GIP_GL_NAME "Mad Catz Rock Band 4 Drum Kit"
|
|
|
|
enum gip_glam_button {
|
|
GIP_GL_BTN_MENU = BIT(2),
|
|
GIP_GL_BTN_VIEW = BIT(3),
|
|
GIP_GL_BTN_A = BIT(4),
|
|
GIP_GL_BTN_B = BIT(5),
|
|
/* swapped X and Y buttons */
|
|
GIP_GL_BTN_X = BIT(7),
|
|
GIP_GL_BTN_Y = BIT(6),
|
|
GIP_GL_BTN_DPAD_U = BIT(8),
|
|
GIP_GL_BTN_DPAD_D = BIT(9),
|
|
GIP_GL_BTN_DPAD_L = BIT(10),
|
|
GIP_GL_BTN_DPAD_R = BIT(11),
|
|
GIP_GL_BTN_KICK_1 = BIT(12),
|
|
GIP_GL_BTN_KICK_2 = BIT(13),
|
|
};
|
|
|
|
enum gip_glam_pad {
|
|
GIP_GL_PAD_YELLOW = BIT(0) | BIT(1) | BIT(2),
|
|
GIP_GL_PAD_RED = BIT(4) | BIT(5) | BIT(6),
|
|
GIP_GL_PAD_GREEN = BIT(8) | BIT(9) | BIT(10),
|
|
GIP_GL_PAD_BLUE = BIT(12) | BIT(13) | BIT(14),
|
|
};
|
|
|
|
enum gip_glam_cymbal {
|
|
GIP_GL_CBL_BLUE = BIT(0) | BIT(1) | BIT(2),
|
|
GIP_GL_CBL_YELLOW = BIT(4) | BIT(5) | BIT(6),
|
|
GIP_GL_CBL_GREEN = BIT(12) | BIT(13) | BIT(14),
|
|
};
|
|
|
|
struct gip_glam_pkt_input {
|
|
__le16 buttons;
|
|
__le16 pads;
|
|
__le16 cymbals;
|
|
} __packed;
|
|
|
|
struct gip_glam {
|
|
struct gip_client *client;
|
|
struct gip_battery battery;
|
|
struct gip_input input;
|
|
};
|
|
|
|
static int gip_glam_init_input(struct gip_glam *glam)
|
|
{
|
|
struct input_dev *dev = glam->input.dev;
|
|
int err;
|
|
|
|
input_set_capability(dev, EV_KEY, BTN_MODE);
|
|
input_set_capability(dev, EV_KEY, BTN_START);
|
|
input_set_capability(dev, EV_KEY, BTN_SELECT);
|
|
input_set_capability(dev, EV_KEY, BTN_A);
|
|
input_set_capability(dev, EV_KEY, BTN_B);
|
|
input_set_capability(dev, EV_KEY, BTN_X);
|
|
input_set_capability(dev, EV_KEY, BTN_Y);
|
|
input_set_capability(dev, EV_KEY, BTN_TRIGGER_HAPPY1);
|
|
input_set_capability(dev, EV_KEY, BTN_TRIGGER_HAPPY2);
|
|
input_set_capability(dev, EV_KEY, BTN_TRIGGER_HAPPY3);
|
|
input_set_capability(dev, EV_KEY, BTN_TRIGGER_HAPPY4);
|
|
input_set_capability(dev, EV_KEY, BTN_TRIGGER_HAPPY5);
|
|
input_set_capability(dev, EV_KEY, BTN_TRIGGER_HAPPY6);
|
|
input_set_capability(dev, EV_KEY, BTN_TRIGGER_HAPPY7);
|
|
input_set_capability(dev, EV_KEY, BTN_TRIGGER_HAPPY8);
|
|
input_set_capability(dev, EV_KEY, BTN_TRIGGER_HAPPY9);
|
|
input_set_abs_params(dev, ABS_HAT0X, -1, 1, 0, 0);
|
|
input_set_abs_params(dev, ABS_HAT0Y, -1, 1, 0, 0);
|
|
|
|
err = input_register_device(dev);
|
|
if (err)
|
|
dev_err(&glam->client->dev, "%s: register failed: %d\n",
|
|
__func__, err);
|
|
|
|
return err;
|
|
}
|
|
|
|
static int gip_glam_op_battery(struct gip_client *client,
|
|
enum gip_battery_type type,
|
|
enum gip_battery_level level)
|
|
{
|
|
struct gip_glam *glam = dev_get_drvdata(&client->dev);
|
|
|
|
gip_report_battery(&glam->battery, type, level);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int gip_glam_op_guide_button(struct gip_client *client, bool down)
|
|
{
|
|
struct gip_glam *glam = dev_get_drvdata(&client->dev);
|
|
|
|
input_report_key(glam->input.dev, BTN_MODE, down);
|
|
input_sync(glam->input.dev);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int gip_glam_op_input(struct gip_client *client, void *data, u32 len)
|
|
{
|
|
struct gip_glam *glam = dev_get_drvdata(&client->dev);
|
|
struct gip_glam_pkt_input *pkt = data;
|
|
struct input_dev *dev = glam->input.dev;
|
|
u16 buttons;
|
|
u16 pads;
|
|
u16 cymbals;
|
|
|
|
if (len < sizeof(*pkt))
|
|
return -EINVAL;
|
|
|
|
buttons = le16_to_cpu(pkt->buttons);
|
|
pads = le16_to_cpu(pkt->pads);
|
|
cymbals = le16_to_cpu(pkt->cymbals);
|
|
|
|
input_report_key(dev, BTN_START, buttons & GIP_GL_BTN_MENU);
|
|
input_report_key(dev, BTN_SELECT, buttons & GIP_GL_BTN_VIEW);
|
|
input_report_key(dev, BTN_A, buttons & GIP_GL_BTN_A);
|
|
input_report_key(dev, BTN_B, buttons & GIP_GL_BTN_B);
|
|
input_report_key(dev, BTN_X, buttons & GIP_GL_BTN_X);
|
|
input_report_key(dev, BTN_Y, buttons & GIP_GL_BTN_Y);
|
|
input_report_key(dev, BTN_TRIGGER_HAPPY1, buttons & GIP_GL_BTN_KICK_1);
|
|
input_report_key(dev, BTN_TRIGGER_HAPPY2, buttons & GIP_GL_BTN_KICK_2);
|
|
input_report_key(dev, BTN_TRIGGER_HAPPY3, pads & GIP_GL_PAD_RED);
|
|
input_report_key(dev, BTN_TRIGGER_HAPPY4, pads & GIP_GL_PAD_YELLOW);
|
|
input_report_key(dev, BTN_TRIGGER_HAPPY5, pads & GIP_GL_PAD_BLUE);
|
|
input_report_key(dev, BTN_TRIGGER_HAPPY6, pads & GIP_GL_PAD_GREEN);
|
|
input_report_key(dev, BTN_TRIGGER_HAPPY7, cymbals & GIP_GL_CBL_YELLOW);
|
|
input_report_key(dev, BTN_TRIGGER_HAPPY8, cymbals & GIP_GL_CBL_BLUE);
|
|
input_report_key(dev, BTN_TRIGGER_HAPPY9, cymbals & GIP_GL_CBL_GREEN);
|
|
input_report_abs(dev, ABS_HAT0X, !!(buttons & GIP_GL_BTN_DPAD_R) -
|
|
!!(buttons & GIP_GL_BTN_DPAD_L));
|
|
input_report_abs(dev, ABS_HAT0Y, !!(buttons & GIP_GL_BTN_DPAD_D) -
|
|
!!(buttons & GIP_GL_BTN_DPAD_U));
|
|
input_sync(dev);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int gip_glam_probe(struct gip_client *client)
|
|
{
|
|
struct gip_glam *glam;
|
|
int err;
|
|
|
|
glam = devm_kzalloc(&client->dev, sizeof(*glam), GFP_KERNEL);
|
|
if (!glam)
|
|
return -ENOMEM;
|
|
|
|
glam->client = client;
|
|
|
|
err = gip_set_power_mode(client, GIP_PWR_ON);
|
|
if (err)
|
|
return err;
|
|
|
|
err = gip_init_battery(&glam->battery, client, GIP_GL_NAME);
|
|
if (err)
|
|
return err;
|
|
|
|
/*
|
|
* The Drum Kit sends auth chunks without specifying the
|
|
* acknowledgment option while still expecting an acknowledgment.
|
|
* The Windows driver handles this by sending an acknowledgment
|
|
* after 100 ms when no further chunks are received.
|
|
* We skip the handshake instead, as it is not required.
|
|
*/
|
|
err = gip_auth_send_complete(client);
|
|
if (err)
|
|
return err;
|
|
|
|
err = gip_init_input(&glam->input, client, GIP_GL_NAME);
|
|
if (err)
|
|
return err;
|
|
|
|
err = gip_glam_init_input(glam);
|
|
if (err)
|
|
return err;
|
|
|
|
dev_set_drvdata(&client->dev, glam);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static struct gip_driver gip_glam_driver = {
|
|
.name = "xone-gip-madcatz-glam",
|
|
.class = "MadCatz.Xbox.Drums.Glam",
|
|
.ops = {
|
|
.battery = gip_glam_op_battery,
|
|
.guide_button = gip_glam_op_guide_button,
|
|
.input = gip_glam_op_input,
|
|
},
|
|
.probe = gip_glam_probe,
|
|
};
|
|
module_gip_driver(gip_glam_driver);
|
|
|
|
MODULE_ALIAS("gip:MadCatz.Xbox.Drums.Glam");
|
|
MODULE_AUTHOR("Severin von Wnuck-Lipinski <severinvonw@outlook.de>");
|
|
MODULE_DESCRIPTION("xone GIP Mad Catz Drum Kit driver");
|
|
MODULE_VERSION("#VERSION#");
|
|
MODULE_LICENSE("GPL");
|