mirror of https://github.com/nirenjan/libx52.git
Create workflow to build kernel module
This workflow runs only if there is a change to the kernel_module path. Consequently, commits that only impact the kernel_module will be ignored for the standard userspace driver build. This commit also updates the CodeQL workflow to only run on a scheduled basis and on pull requests, but not on every push, since this is a fairly slow script. Finally, this commit also removes the obsolete kernel module sources, since they are no longer maintained, and it also provides a hook for Github actions to pick up and execute the kernel workflow.pull/26/head
parent
d3c55da89d
commit
4388eceec0
|
@ -0,0 +1,4 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# Install dependencies to build kernel modules on Ubuntu runners
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y linux-headers-$(uname -r)
|
|
@ -5,6 +5,8 @@ on:
|
||||||
branches:
|
branches:
|
||||||
- '*'
|
- '*'
|
||||||
- '!gh-pages'
|
- '!gh-pages'
|
||||||
|
paths-ignore:
|
||||||
|
- 'kernel_module/**'
|
||||||
pull_request:
|
pull_request:
|
||||||
branches: [ master ]
|
branches: [ master ]
|
||||||
|
|
||||||
|
|
|
@ -1,17 +1,14 @@
|
||||||
name: "CodeQL"
|
name: "CodeQL"
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
|
||||||
branches: ['*', '!gh-pages']
|
|
||||||
pull_request:
|
pull_request:
|
||||||
# The branches below must be a subset of the branches above
|
# The branches below must be a subset of the branches above
|
||||||
branches: [master]
|
branches: [master]
|
||||||
schedule:
|
schedule:
|
||||||
- cron: '0 7 * * 1'
|
- cron: '30 7 * * 1,3,5'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
analyse:
|
analyse:
|
||||||
if: "!(contains(github.event.head_commit.message, '[ci skip]') || contains(github.event.head_commit.message, '[skip ci]'))"
|
|
||||||
name: Analyse
|
name: Analyse
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
name: Kernel Module
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ '*' ]
|
||||||
|
paths:
|
||||||
|
- 'kernel_module/**'
|
||||||
|
pull_request:
|
||||||
|
branches: [ master ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
if: "!(contains(github.event.head_commit.message, '[ci skip]') || contains(github.event.head_commit.message, '[skip ci]'))"
|
||||||
|
name: ${{ matrix.os }}
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: ['ubuntu-16.04', 'ubuntu-18.04', 'ubuntu-20.04']
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Install kernel dependencies
|
||||||
|
run: ./.github/scripts/install-kernel-dependencies.sh
|
||||||
|
|
||||||
|
- name: Build kernel module
|
||||||
|
run: |
|
||||||
|
cd kernel_module
|
||||||
|
make
|
|
@ -2,6 +2,7 @@ Saitek X52Pro joystick driver for Linux
|
||||||
=======================================
|
=======================================
|
||||||
|
|
||||||

|

|
||||||
|

|
||||||

|

|
||||||
[](https://gitter.im/x52pro-linux/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
[](https://gitter.im/x52pro-linux/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||||
|
|
||||||
|
|
|
@ -1,600 +0,0 @@
|
||||||
/*
|
|
||||||
* Saitek X52 Pro HOTAS driver
|
|
||||||
*
|
|
||||||
* Copyright (C) 2012 Nirenjan Krishnan (nirenjan@nirenjan.org)
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU General Public License as
|
|
||||||
* published by the Free Software Foundation, version 2.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: GPL-2.0-only
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifdef CONFIG_USB_DEBUG
|
|
||||||
#define DEBUG 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <linux/kernel.h>
|
|
||||||
#include <linux/errno.h>
|
|
||||||
#include <linux/init.h>
|
|
||||||
#include <linux/slab.h>
|
|
||||||
#include <linux/module.h>
|
|
||||||
#include <linux/usb.h>
|
|
||||||
#include <linux/input.h>
|
|
||||||
#include <linux/usb/input.h>
|
|
||||||
|
|
||||||
#include "x52joy_commands.h"
|
|
||||||
#include "x52joy_common.h"
|
|
||||||
|
|
||||||
#define DRIVER_AUTHOR "Nirenjan Krishnan, nirenjan@gmail.com"
|
|
||||||
#define DRIVER_DESC "Saitek X52Pro HOTAS Driver"
|
|
||||||
#define DRIVER_VERSION "1.0"
|
|
||||||
|
|
||||||
static const struct x52_device {
|
|
||||||
u16 idVendor;
|
|
||||||
u16 idProduct;
|
|
||||||
char *name;
|
|
||||||
u8 type;
|
|
||||||
u8 flags;
|
|
||||||
} x52_devices[] = {
|
|
||||||
{
|
|
||||||
VENDOR_ID_SAITEK, PRODUCT_ID_X52_PRO,
|
|
||||||
"Saitek X52 Pro Flight Control System", X52TYPE_X52PRO,
|
|
||||||
X52FLAGS_SUPPORTS_MFD | X52FLAGS_SUPPORTS_LED
|
|
||||||
},
|
|
||||||
{ /* Terminating entry */
|
|
||||||
0x0000, 0x0000, "Unknown X52", X52TYPE_UNKNOWN, 0
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
/* list of devices that work with this driver */
|
|
||||||
static struct usb_device_id id_table[] = {
|
|
||||||
{ USB_DEVICE(VENDOR_ID_SAITEK, PRODUCT_ID_X52_PRO) },
|
|
||||||
/*
|
|
||||||
* Future versions of this driver may support the original
|
|
||||||
* X52 HOTAS joystick, but for now, only the X52 Pro is
|
|
||||||
* supported.
|
|
||||||
*/
|
|
||||||
{ },
|
|
||||||
};
|
|
||||||
MODULE_DEVICE_TABLE (usb, id_table);
|
|
||||||
|
|
||||||
#define CHECK_RETURN(ret, cnt) do { \
|
|
||||||
if (ret) {\
|
|
||||||
return ret;\
|
|
||||||
} else {\
|
|
||||||
return cnt;\
|
|
||||||
}\
|
|
||||||
} while(0)
|
|
||||||
|
|
||||||
/**********************************************************************
|
|
||||||
* MFD Line manipulation functions
|
|
||||||
*********************************************************************/
|
|
||||||
static ssize_t show_text_line(struct device *dev, char *buf, u8 line)
|
|
||||||
{
|
|
||||||
struct usb_interface *intf = to_usb_interface(dev);
|
|
||||||
struct x52_joy *joy = usb_get_intfdata(intf);
|
|
||||||
|
|
||||||
line--; /* Convert to 0-based line number */
|
|
||||||
|
|
||||||
if (joy->feat_mfd) {
|
|
||||||
return sprintf(buf, "%s\n", joy->line[line].text);
|
|
||||||
} else {
|
|
||||||
sprintf(buf, "\n");
|
|
||||||
return -EOPNOTSUPP;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static ssize_t set_text_line(struct device *dev, const char *buf,
|
|
||||||
size_t count, u8 line)
|
|
||||||
{
|
|
||||||
struct usb_interface *intf = to_usb_interface(dev);
|
|
||||||
struct x52_joy *joy = usb_get_intfdata(intf);
|
|
||||||
u16 i;
|
|
||||||
u16 length;
|
|
||||||
int retval;
|
|
||||||
|
|
||||||
if (!joy->feat_mfd) {
|
|
||||||
return -EOPNOTSUPP;
|
|
||||||
}
|
|
||||||
|
|
||||||
line--; /* Convert to 0-based line number */
|
|
||||||
|
|
||||||
/* Copy the string from src to dst, upto 16 characters max */
|
|
||||||
for (i = 0, length = 0; i < X52_MFD_LINE_SIZE && i < count; i++, length++) {
|
|
||||||
joy->line[line].text[i] = buf[i];
|
|
||||||
}
|
|
||||||
joy->line[line].length = length;
|
|
||||||
|
|
||||||
/* Append empty bytes until the destination is full */
|
|
||||||
for ( ; i < X52_MFD_LINE_SIZE; i++) {
|
|
||||||
/* The X52 pro MFD uses space characters as empty characters */
|
|
||||||
joy->line[line].text[i] = 32;
|
|
||||||
}
|
|
||||||
|
|
||||||
retval = set_text(joy, line);
|
|
||||||
|
|
||||||
CHECK_RETURN(retval, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#define show_set_text(no) \
|
|
||||||
static ssize_t show_text_line##no(struct device *dev, struct device_attribute *attr, char *buf) \
|
|
||||||
{ \
|
|
||||||
return show_text_line(dev, buf, no); \
|
|
||||||
} \
|
|
||||||
static ssize_t set_text_line##no(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
|
|
||||||
{ \
|
|
||||||
return set_text_line(dev, buf, count, no); \
|
|
||||||
} \
|
|
||||||
static DEVICE_ATTR(mfd_line##no, S_IWUSR | S_IWGRP | S_IRUGO, show_text_line##no, set_text_line##no);
|
|
||||||
|
|
||||||
show_set_text(1);
|
|
||||||
show_set_text(2);
|
|
||||||
show_set_text(3);
|
|
||||||
|
|
||||||
/**********************************************************************
|
|
||||||
* Brightness manipulation functions
|
|
||||||
*********************************************************************/
|
|
||||||
#define mfd 0
|
|
||||||
#define led 1
|
|
||||||
|
|
||||||
static int to_hex(const char c)
|
|
||||||
{
|
|
||||||
/* Converts a single character to hex */
|
|
||||||
if (c >= '0' && c <= '9') {
|
|
||||||
return (c - '0');
|
|
||||||
} else if (c >= 'A' && c <= 'F') {
|
|
||||||
return (c - 'A' + 10);
|
|
||||||
} else if (c >= 'a' && c <= 'f') {
|
|
||||||
return (c - 'a' + 10);
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static ssize_t set_x52_brightness(struct device *dev, const char *buf,
|
|
||||||
size_t count, u8 target)
|
|
||||||
{
|
|
||||||
u16 bri;
|
|
||||||
u16 ch;
|
|
||||||
int retval;
|
|
||||||
struct usb_interface *intf = to_usb_interface(dev);
|
|
||||||
struct x52_joy *joy = usb_get_intfdata(intf);
|
|
||||||
|
|
||||||
if (target >= 2 || count != 4 || buf[0] != '0' ||
|
|
||||||
((buf[1] | 0x20) != 'x')) {
|
|
||||||
/* Just some sanity checking */
|
|
||||||
return -EOPNOTSUPP;
|
|
||||||
}
|
|
||||||
|
|
||||||
bri = 0;
|
|
||||||
ch = to_hex(buf[2]);
|
|
||||||
if (ch >= 0) {
|
|
||||||
bri |= ch;
|
|
||||||
bri <<= 4;
|
|
||||||
} else {
|
|
||||||
return -EOPNOTSUPP;
|
|
||||||
}
|
|
||||||
ch = to_hex(buf[3]);
|
|
||||||
if (ch >= 0) {
|
|
||||||
bri |= ch;
|
|
||||||
} else {
|
|
||||||
return -EOPNOTSUPP;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bri > 0x80) {
|
|
||||||
return -EOPNOTSUPP;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (target == mfd) {
|
|
||||||
ch = X52_MFD_BRIGHTNESS;
|
|
||||||
joy->bri_mfd = bri;
|
|
||||||
} else {
|
|
||||||
ch = X52_LED_BRIGHTNESS;
|
|
||||||
joy->bri_led = bri;
|
|
||||||
}
|
|
||||||
|
|
||||||
retval = set_brightness(joy, target);
|
|
||||||
|
|
||||||
CHECK_RETURN(retval, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ssize_t show_brightness(struct device *dev, char *buf, u8 target)
|
|
||||||
{
|
|
||||||
struct usb_interface *intf = to_usb_interface(dev);
|
|
||||||
struct x52_joy *joy = usb_get_intfdata(intf);
|
|
||||||
|
|
||||||
if (target == mfd) {
|
|
||||||
if (joy->feat_mfd) {
|
|
||||||
return sprintf(buf, "0x%02x\n", joy->bri_mfd);
|
|
||||||
}
|
|
||||||
} else if (target == led) {
|
|
||||||
if (joy->feat_led) {
|
|
||||||
return sprintf(buf, "0x%02x\n", joy->bri_led);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sprintf(buf, "\n");
|
|
||||||
return -EOPNOTSUPP;
|
|
||||||
}
|
|
||||||
|
|
||||||
static ssize_t show_bri_mfd (struct device *dev, struct device_attribute *attr, char *buf)
|
|
||||||
{
|
|
||||||
return show_brightness(dev, buf, mfd);
|
|
||||||
}
|
|
||||||
static ssize_t set_bri_mfd (struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
|
|
||||||
{
|
|
||||||
return set_x52_brightness(dev, buf, count, mfd);
|
|
||||||
}
|
|
||||||
static ssize_t show_bri_led (struct device *dev, struct device_attribute *attr, char *buf)
|
|
||||||
{
|
|
||||||
return show_brightness(dev, buf, led);
|
|
||||||
}
|
|
||||||
static ssize_t set_bri_led (struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
|
|
||||||
{
|
|
||||||
return set_x52_brightness(dev, buf, count, led);
|
|
||||||
}
|
|
||||||
static DEVICE_ATTR(bri_mfd, S_IWUSR | S_IWGRP | S_IRUGO, show_bri_mfd, set_bri_mfd);
|
|
||||||
static DEVICE_ATTR(bri_led, S_IWUSR | S_IWGRP | S_IRUGO, show_bri_led, set_bri_led);
|
|
||||||
|
|
||||||
#undef mfd
|
|
||||||
#undef led
|
|
||||||
|
|
||||||
/**********************************************************************
|
|
||||||
* LED manipulation functions
|
|
||||||
*********************************************************************/
|
|
||||||
|
|
||||||
#define fire X52_LED_FIRE
|
|
||||||
#define a_red X52_LED_A_RED
|
|
||||||
#define a_green X52_LED_A_GREEN
|
|
||||||
#define b_red X52_LED_B_RED
|
|
||||||
#define b_green X52_LED_B_GREEN
|
|
||||||
#define d_red X52_LED_D_RED
|
|
||||||
#define d_green X52_LED_D_GREEN
|
|
||||||
#define e_red X52_LED_E_RED
|
|
||||||
#define e_green X52_LED_E_GREEN
|
|
||||||
#define t1_red X52_LED_T1_RED
|
|
||||||
#define t1_green X52_LED_T1_GREEN
|
|
||||||
#define t2_red X52_LED_T2_RED
|
|
||||||
#define t2_green X52_LED_T2_GREEN
|
|
||||||
#define t3_red X52_LED_T3_RED
|
|
||||||
#define t3_green X52_LED_T3_GREEN
|
|
||||||
#define pov_red X52_LED_POV_RED
|
|
||||||
#define pov_green X52_LED_POV_GREEN
|
|
||||||
#define i_red X52_LED_I_RED
|
|
||||||
#define i_green X52_LED_I_GREEN
|
|
||||||
#define throttle X52_LED_THROTTLE
|
|
||||||
|
|
||||||
static ssize_t set_x52_led(struct device *dev, const char *buf,
|
|
||||||
size_t count, u8 target)
|
|
||||||
{
|
|
||||||
u8 status;
|
|
||||||
int retval;
|
|
||||||
struct usb_interface *intf = to_usb_interface(dev);
|
|
||||||
struct x52_joy *joy = usb_get_intfdata(intf);
|
|
||||||
|
|
||||||
if (target > X52_LED_THROTTLE || count < 1 || buf[0] < '0' ||
|
|
||||||
buf[0] > '1') {
|
|
||||||
/* Just some sanity checking */
|
|
||||||
return -EOPNOTSUPP;
|
|
||||||
}
|
|
||||||
|
|
||||||
status = buf[0] - '0';
|
|
||||||
|
|
||||||
if (status) {
|
|
||||||
joy->led_status |= (1 << target);
|
|
||||||
} else {
|
|
||||||
joy->led_status &= ~(1 << target);
|
|
||||||
}
|
|
||||||
|
|
||||||
retval = set_led(joy, target);
|
|
||||||
|
|
||||||
CHECK_RETURN(retval, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ssize_t show_led(struct device *dev, struct device_attribute *attr,
|
|
||||||
char *buf)
|
|
||||||
{
|
|
||||||
struct usb_interface *intf = to_usb_interface(dev);
|
|
||||||
struct x52_joy *joy = usb_get_intfdata(intf);
|
|
||||||
|
|
||||||
if (joy->feat_led) {
|
|
||||||
return sprintf(buf, "0x%08x\n", joy->led_status);
|
|
||||||
}
|
|
||||||
|
|
||||||
sprintf(buf, "\n");
|
|
||||||
return -EOPNOTSUPP;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define show_set_led(no) \
|
|
||||||
static ssize_t set_led_##no(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
|
|
||||||
{ \
|
|
||||||
return set_x52_led(dev, buf, count, no); \
|
|
||||||
} \
|
|
||||||
static DEVICE_ATTR(led_##no, S_IWUSR | S_IWGRP | S_IRUGO, show_led, set_led_##no);
|
|
||||||
|
|
||||||
show_set_led(fire);
|
|
||||||
show_set_led(a_red);
|
|
||||||
show_set_led(a_green);
|
|
||||||
show_set_led(b_red);
|
|
||||||
show_set_led(b_green);
|
|
||||||
show_set_led(d_red);
|
|
||||||
show_set_led(d_green);
|
|
||||||
show_set_led(e_red);
|
|
||||||
show_set_led(e_green);
|
|
||||||
show_set_led(t1_red);
|
|
||||||
show_set_led(t1_green);
|
|
||||||
show_set_led(t2_red);
|
|
||||||
show_set_led(t2_green);
|
|
||||||
show_set_led(t3_red);
|
|
||||||
show_set_led(t3_green);
|
|
||||||
show_set_led(pov_red);
|
|
||||||
show_set_led(pov_green);
|
|
||||||
show_set_led(i_red);
|
|
||||||
show_set_led(i_green);
|
|
||||||
show_set_led(throttle);
|
|
||||||
|
|
||||||
/**********************************************************************
|
|
||||||
* Blink manipulation functions
|
|
||||||
*********************************************************************/
|
|
||||||
static ssize_t show_blink(struct device *dev, struct device_attribute *attr,
|
|
||||||
char *buf)
|
|
||||||
{
|
|
||||||
struct usb_interface *intf = to_usb_interface(dev);
|
|
||||||
struct x52_joy *joy = usb_get_intfdata(intf);
|
|
||||||
|
|
||||||
if (joy->feat_led) {
|
|
||||||
return sprintf(buf, "%d\n", joy->blink_led);
|
|
||||||
} else {
|
|
||||||
sprintf(buf, "\n");
|
|
||||||
return -EOPNOTSUPP;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static ssize_t set_x52_blink(struct device *dev, struct device_attribute *attr,
|
|
||||||
const char *buf, size_t count)
|
|
||||||
{
|
|
||||||
struct usb_interface *intf = to_usb_interface(dev);
|
|
||||||
struct x52_joy *joy = usb_get_intfdata(intf);
|
|
||||||
int retval;
|
|
||||||
|
|
||||||
if (!joy->feat_led) {
|
|
||||||
return -EOPNOTSUPP;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (count < 1 || buf[0] < '0' || buf[1] > '1') {
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
joy->blink_led = buf[0] - '0';
|
|
||||||
|
|
||||||
retval = set_blink(joy);
|
|
||||||
|
|
||||||
CHECK_RETURN(retval, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static DEVICE_ATTR(led_blink, S_IWUSR | S_IWGRP | S_IRUGO, show_blink, set_x52_blink);
|
|
||||||
|
|
||||||
/**********************************************************************
|
|
||||||
* X52 driver functions
|
|
||||||
*********************************************************************/
|
|
||||||
static int x52_probe(struct usb_interface *intf,
|
|
||||||
const struct usb_device_id *id)
|
|
||||||
{
|
|
||||||
struct usb_device *udev = interface_to_usbdev(intf);
|
|
||||||
struct x52_joy *joy = NULL;
|
|
||||||
struct input_dev *idev = NULL;
|
|
||||||
struct usb_endpoint_descriptor *ep_irq_in;
|
|
||||||
int retval = -ENOMEM;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; x52_devices[i].idVendor; i++) {
|
|
||||||
if ((le16_to_cpu(udev->descriptor.idVendor) == x52_devices[i].idVendor) &&
|
|
||||||
(le16_to_cpu(udev->descriptor.idProduct) == x52_devices[i].idProduct)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
joy = kzalloc(sizeof(*joy), GFP_KERNEL);
|
|
||||||
if (joy == NULL) {
|
|
||||||
dev_err(&intf->dev, "Out of memory: Cannot create joystick\n");
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
joy->type = x52_devices[i].type;
|
|
||||||
|
|
||||||
idev = input_allocate_device();
|
|
||||||
if (idev == NULL) {
|
|
||||||
dev_err(&intf->dev, "Out of memory: Cannot create input\n");
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
joy->idata = usb_alloc_coherent(udev, X52_PACKET_LEN, GFP_KERNEL,
|
|
||||||
&joy->idata_dma);
|
|
||||||
if (!joy->idata) {
|
|
||||||
dev_err(&intf->dev, "Out of memory: Cannot alloc coherent buffer\n");
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
joy->irq_in = usb_alloc_urb(0, GFP_KERNEL);
|
|
||||||
if (!joy->irq_in) {
|
|
||||||
dev_err(&intf->dev, "Out of memory: Cannot alloc IRQ URB\n");
|
|
||||||
goto error1;
|
|
||||||
}
|
|
||||||
|
|
||||||
joy->udev = usb_get_dev(udev);
|
|
||||||
|
|
||||||
joy->idev = idev;
|
|
||||||
usb_make_path(udev, joy->phys, sizeof(joy->phys));
|
|
||||||
strlcat(joy->phys, "/input0", sizeof(joy->phys));
|
|
||||||
|
|
||||||
idev->name = x52_devices[i].name;
|
|
||||||
idev->phys = joy->phys;
|
|
||||||
usb_to_input_id(udev, &idev->id);
|
|
||||||
idev->dev.parent = &intf->dev;
|
|
||||||
|
|
||||||
input_set_drvdata(idev, joy);
|
|
||||||
|
|
||||||
idev->open = x52_open;
|
|
||||||
idev->close = x52_close;
|
|
||||||
|
|
||||||
x52_setup_input(idev);
|
|
||||||
|
|
||||||
ep_irq_in = &intf->cur_altsetting->endpoint[0].desc;
|
|
||||||
usb_fill_int_urb(joy->irq_in, udev,
|
|
||||||
usb_rcvintpipe(udev, ep_irq_in->bEndpointAddress),
|
|
||||||
joy->idata, X52_PACKET_LEN, x52_irq_handler,
|
|
||||||
joy, ep_irq_in->bInterval);
|
|
||||||
joy->irq_in->transfer_dma = joy->idata_dma;
|
|
||||||
joy->irq_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
|
|
||||||
|
|
||||||
retval = input_register_device(joy->idev);
|
|
||||||
if (retval) {
|
|
||||||
goto error2;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set the feature bits */
|
|
||||||
joy->feat_mfd = !!(x52_devices[i].flags & X52FLAGS_SUPPORTS_MFD);
|
|
||||||
joy->feat_led = !!(x52_devices[i].flags & X52FLAGS_SUPPORTS_LED);
|
|
||||||
|
|
||||||
usb_set_intfdata(intf, joy);
|
|
||||||
|
|
||||||
if (joy->feat_mfd) {
|
|
||||||
device_create_file(&intf->dev, &dev_attr_mfd_line1);
|
|
||||||
device_create_file(&intf->dev, &dev_attr_mfd_line2);
|
|
||||||
device_create_file(&intf->dev, &dev_attr_mfd_line3);
|
|
||||||
|
|
||||||
device_create_file(&intf->dev, &dev_attr_bri_mfd);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (joy->feat_led) {
|
|
||||||
device_create_file(&intf->dev, &dev_attr_bri_led);
|
|
||||||
|
|
||||||
device_create_file(&intf->dev, &dev_attr_led_fire);
|
|
||||||
device_create_file(&intf->dev, &dev_attr_led_a_red);
|
|
||||||
device_create_file(&intf->dev, &dev_attr_led_a_green);
|
|
||||||
device_create_file(&intf->dev, &dev_attr_led_b_red);
|
|
||||||
device_create_file(&intf->dev, &dev_attr_led_b_green);
|
|
||||||
device_create_file(&intf->dev, &dev_attr_led_d_red);
|
|
||||||
device_create_file(&intf->dev, &dev_attr_led_d_green);
|
|
||||||
device_create_file(&intf->dev, &dev_attr_led_e_red);
|
|
||||||
device_create_file(&intf->dev, &dev_attr_led_e_green);
|
|
||||||
device_create_file(&intf->dev, &dev_attr_led_t1_red);
|
|
||||||
device_create_file(&intf->dev, &dev_attr_led_t1_green);
|
|
||||||
device_create_file(&intf->dev, &dev_attr_led_t2_red);
|
|
||||||
device_create_file(&intf->dev, &dev_attr_led_t2_green);
|
|
||||||
device_create_file(&intf->dev, &dev_attr_led_t3_red);
|
|
||||||
device_create_file(&intf->dev, &dev_attr_led_t3_green);
|
|
||||||
device_create_file(&intf->dev, &dev_attr_led_pov_red);
|
|
||||||
device_create_file(&intf->dev, &dev_attr_led_pov_green);
|
|
||||||
device_create_file(&intf->dev, &dev_attr_led_i_red);
|
|
||||||
device_create_file(&intf->dev, &dev_attr_led_i_green);
|
|
||||||
device_create_file(&intf->dev, &dev_attr_led_throttle);
|
|
||||||
|
|
||||||
device_create_file(&intf->dev, &dev_attr_led_blink);
|
|
||||||
}
|
|
||||||
|
|
||||||
try_module_get(THIS_MODULE);
|
|
||||||
|
|
||||||
dev_info(&intf->dev, "X52 device now attached\n");
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
error2:
|
|
||||||
usb_free_urb(joy->irq_in);
|
|
||||||
error1:
|
|
||||||
usb_free_coherent(udev, X52_PACKET_LEN, joy->idata, joy->idata_dma);
|
|
||||||
error:
|
|
||||||
input_free_device(idev);
|
|
||||||
kfree(joy);
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void x52_disconnect(struct usb_interface *intf)
|
|
||||||
{
|
|
||||||
struct x52_joy *joy;
|
|
||||||
|
|
||||||
joy = usb_get_intfdata(intf);
|
|
||||||
usb_set_intfdata(intf, NULL);
|
|
||||||
|
|
||||||
usb_kill_urb(joy->irq_in);
|
|
||||||
usb_free_urb(joy->irq_in);
|
|
||||||
usb_free_coherent(joy->udev, X52_PACKET_LEN, joy->idata, joy->idata_dma);
|
|
||||||
input_free_device(joy->idev);
|
|
||||||
|
|
||||||
if (joy->feat_mfd) {
|
|
||||||
device_remove_file(&intf->dev, &dev_attr_mfd_line1);
|
|
||||||
device_remove_file(&intf->dev, &dev_attr_mfd_line2);
|
|
||||||
device_remove_file(&intf->dev, &dev_attr_mfd_line3);
|
|
||||||
|
|
||||||
device_remove_file(&intf->dev, &dev_attr_bri_mfd);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (joy->feat_led) {
|
|
||||||
device_remove_file(&intf->dev, &dev_attr_bri_led);
|
|
||||||
|
|
||||||
device_remove_file(&intf->dev, &dev_attr_led_fire);
|
|
||||||
device_remove_file(&intf->dev, &dev_attr_led_a_red);
|
|
||||||
device_remove_file(&intf->dev, &dev_attr_led_a_green);
|
|
||||||
device_remove_file(&intf->dev, &dev_attr_led_b_red);
|
|
||||||
device_remove_file(&intf->dev, &dev_attr_led_b_green);
|
|
||||||
device_remove_file(&intf->dev, &dev_attr_led_d_red);
|
|
||||||
device_remove_file(&intf->dev, &dev_attr_led_d_green);
|
|
||||||
device_remove_file(&intf->dev, &dev_attr_led_e_red);
|
|
||||||
device_remove_file(&intf->dev, &dev_attr_led_e_green);
|
|
||||||
device_remove_file(&intf->dev, &dev_attr_led_t1_red);
|
|
||||||
device_remove_file(&intf->dev, &dev_attr_led_t1_green);
|
|
||||||
device_remove_file(&intf->dev, &dev_attr_led_t2_red);
|
|
||||||
device_remove_file(&intf->dev, &dev_attr_led_t2_green);
|
|
||||||
device_remove_file(&intf->dev, &dev_attr_led_t3_red);
|
|
||||||
device_remove_file(&intf->dev, &dev_attr_led_t3_green);
|
|
||||||
device_remove_file(&intf->dev, &dev_attr_led_pov_red);
|
|
||||||
device_remove_file(&intf->dev, &dev_attr_led_pov_green);
|
|
||||||
device_remove_file(&intf->dev, &dev_attr_led_i_red);
|
|
||||||
device_remove_file(&intf->dev, &dev_attr_led_i_green);
|
|
||||||
device_remove_file(&intf->dev, &dev_attr_led_throttle);
|
|
||||||
|
|
||||||
device_remove_file(&intf->dev, &dev_attr_led_blink);
|
|
||||||
}
|
|
||||||
|
|
||||||
usb_put_dev(joy->udev);
|
|
||||||
kfree(joy);
|
|
||||||
|
|
||||||
module_put(THIS_MODULE);
|
|
||||||
|
|
||||||
dev_info(&intf->dev, "X52 device now disconnected\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct usb_driver x52_driver = {
|
|
||||||
.name = "saitek_x52",
|
|
||||||
.probe = x52_probe,
|
|
||||||
.disconnect = x52_disconnect,
|
|
||||||
.id_table = id_table,
|
|
||||||
};
|
|
||||||
|
|
||||||
static int __init x52_init(void)
|
|
||||||
{
|
|
||||||
int retval = 0;
|
|
||||||
|
|
||||||
retval = usb_register(&x52_driver);
|
|
||||||
if (retval) {
|
|
||||||
pr_err("usb_register failed (errno=%d)\n", retval);
|
|
||||||
}
|
|
||||||
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void __exit x52_exit(void)
|
|
||||||
{
|
|
||||||
usb_deregister(&x52_driver);
|
|
||||||
}
|
|
||||||
|
|
||||||
module_init (x52_init);
|
|
||||||
module_exit (x52_exit);
|
|
||||||
|
|
||||||
MODULE_AUTHOR(DRIVER_AUTHOR);
|
|
||||||
MODULE_DESCRIPTION(DRIVER_DESC);
|
|
||||||
MODULE_VERSION(DRIVER_VERSION);
|
|
||||||
MODULE_LICENSE("GPL v2");
|
|
||||||
|
|
|
@ -1,266 +0,0 @@
|
||||||
/*
|
|
||||||
* Saitek X52 Pro HOTAS driver
|
|
||||||
*
|
|
||||||
* Copyright (C) 2012 Nirenjan Krishnan (nirenjan@nirenjan.org)
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU General Public License as
|
|
||||||
* published by the Free Software Foundation, version 2.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: GPL-2.0-only
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifdef CONFIG_USB_DEBUG
|
|
||||||
#define DEBUG 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <linux/kernel.h>
|
|
||||||
#include <linux/errno.h>
|
|
||||||
#include <linux/init.h>
|
|
||||||
#include <linux/slab.h>
|
|
||||||
#include <linux/module.h>
|
|
||||||
#include <linux/usb.h>
|
|
||||||
|
|
||||||
#include "x52joy_commands.h"
|
|
||||||
#include "x52joy_common.h"
|
|
||||||
|
|
||||||
/**********************************************************************
|
|
||||||
* MFD Line manipulation functions
|
|
||||||
*********************************************************************/
|
|
||||||
static const u8 line_cmd[X52_MFD_LINES] = {
|
|
||||||
X52_MFD_LINE1,
|
|
||||||
X52_MFD_LINE2,
|
|
||||||
X52_MFD_LINE3,
|
|
||||||
};
|
|
||||||
|
|
||||||
int set_text(struct x52_joy *joy, u8 line_no)
|
|
||||||
{
|
|
||||||
u16 i;
|
|
||||||
u16 ch;
|
|
||||||
u16 length;
|
|
||||||
char *text_ptr;
|
|
||||||
int retval;
|
|
||||||
|
|
||||||
if (!joy || line_no >= X52_MFD_LINES) {
|
|
||||||
/* Just some sanity checking */
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Clear the line first */
|
|
||||||
retval = usb_control_msg(joy->udev,
|
|
||||||
usb_sndctrlpipe(joy->udev, 0),
|
|
||||||
X52_VENDOR_REQUEST,
|
|
||||||
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
|
|
||||||
0x00,
|
|
||||||
line_cmd[line_no] | X52_MFD_CLEAR_LINE,
|
|
||||||
NULL, 0, 1000);
|
|
||||||
if (retval) {
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
length = joy->line[line_no].length;
|
|
||||||
|
|
||||||
for (i = 0; i < X52_MFD_LINE_SIZE && i < length; i+= 2) {
|
|
||||||
text_ptr = &joy->line[line_no].text[i];
|
|
||||||
if (length - i > 1) {
|
|
||||||
ch = *(u16 *)text_ptr;
|
|
||||||
} else {
|
|
||||||
ch = (*text_ptr) + (0x20 << 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
retval = usb_control_msg(joy->udev,
|
|
||||||
usb_sndctrlpipe(joy->udev, 0),
|
|
||||||
X52_VENDOR_REQUEST,
|
|
||||||
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
|
|
||||||
ch,
|
|
||||||
line_cmd[line_no] | X52_MFD_WRITE_LINE,
|
|
||||||
NULL, 0, 1000);
|
|
||||||
if (retval) {
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**********************************************************************
|
|
||||||
* Brightness manipulation functions
|
|
||||||
*********************************************************************/
|
|
||||||
int set_brightness(struct x52_joy *joy, u8 target)
|
|
||||||
{
|
|
||||||
u16 bri;
|
|
||||||
u8 ch;
|
|
||||||
int retval;
|
|
||||||
|
|
||||||
if (!joy || target > 1) {
|
|
||||||
/* Just some sanity checking */
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (target == 0) { // MFD
|
|
||||||
ch = X52_MFD_BRIGHTNESS;
|
|
||||||
bri = joy->bri_mfd;
|
|
||||||
} else { // LED
|
|
||||||
ch = X52_LED_BRIGHTNESS;
|
|
||||||
bri = joy->bri_led;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bri > 0x80) {
|
|
||||||
return -EOPNOTSUPP;
|
|
||||||
}
|
|
||||||
|
|
||||||
retval = usb_control_msg(joy->udev,
|
|
||||||
usb_sndctrlpipe(joy->udev, 0),
|
|
||||||
X52_VENDOR_REQUEST,
|
|
||||||
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
|
|
||||||
bri, ch,
|
|
||||||
NULL, 0, 1000);
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**********************************************************************
|
|
||||||
* LED manipulation functions
|
|
||||||
*********************************************************************/
|
|
||||||
int set_led(struct x52_joy *joy, u8 target)
|
|
||||||
{
|
|
||||||
int retval;
|
|
||||||
u8 status;
|
|
||||||
|
|
||||||
if (!joy || target > X52_LED_THROTTLE) {
|
|
||||||
/* Just some sanity checking */
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
status = (u8)((joy->led_status >> target) & 1);
|
|
||||||
|
|
||||||
retval = usb_control_msg(joy->udev,
|
|
||||||
usb_sndctrlpipe(joy->udev, 0),
|
|
||||||
X52_VENDOR_REQUEST,
|
|
||||||
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
|
|
||||||
target << 8 | status, X52_LED,
|
|
||||||
NULL, 0, 1000);
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**********************************************************************
|
|
||||||
* Date manipulation functions
|
|
||||||
*********************************************************************/
|
|
||||||
int set_date(struct x52_joy *joy)
|
|
||||||
{
|
|
||||||
int retval;
|
|
||||||
u16 ddmm;
|
|
||||||
u16 yy;
|
|
||||||
|
|
||||||
if (!joy) {
|
|
||||||
/* Just some sanity checking */
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The X52 Pro MFD expects the date to be stored as DD-MM-YY.
|
|
||||||
* However, by tweaking the USB control messages, we can display
|
|
||||||
* in any format we choose.
|
|
||||||
*/
|
|
||||||
if (joy->date.format >= x52_mfd_format_max) {
|
|
||||||
return -EOPNOTSUPP;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (joy->date.format) {
|
|
||||||
case x52_mfd_format_yymmdd:
|
|
||||||
yy = joy->date.day;
|
|
||||||
ddmm = (joy->date.year << 8) | joy->date.month;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case x52_mfd_format_mmddyy:
|
|
||||||
yy = joy->date.year;
|
|
||||||
ddmm = (joy->date.day << 8) | joy->date.month;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case x52_mfd_format_ddmmyy:
|
|
||||||
yy = joy->date.year;
|
|
||||||
ddmm = (joy->date.month << 8) | joy->date.day;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return -EOPNOTSUPP;
|
|
||||||
}
|
|
||||||
|
|
||||||
retval = usb_control_msg(joy->udev,
|
|
||||||
usb_sndctrlpipe(joy->udev, 0),
|
|
||||||
X52_VENDOR_REQUEST,
|
|
||||||
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
|
|
||||||
ddmm, X52_DATE_DDMM,
|
|
||||||
NULL, 0, 1000);
|
|
||||||
retval = usb_control_msg(joy->udev,
|
|
||||||
usb_sndctrlpipe(joy->udev, 0),
|
|
||||||
X52_VENDOR_REQUEST,
|
|
||||||
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
|
|
||||||
yy, X52_DATE_YEAR,
|
|
||||||
NULL, 0, 1000);
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**********************************************************************
|
|
||||||
* Shift manipulation functions
|
|
||||||
*********************************************************************/
|
|
||||||
int set_shift(struct x52_joy *joy)
|
|
||||||
{
|
|
||||||
int retval;
|
|
||||||
int val;
|
|
||||||
|
|
||||||
if (!joy) {
|
|
||||||
/* Just some sanity checking */
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!joy->feat_mfd) {
|
|
||||||
return -EOPNOTSUPP;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (joy->shift_ind) {
|
|
||||||
val = X52_SHIFT_ON;
|
|
||||||
} else {
|
|
||||||
val = X52_SHIFT_OFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
retval = usb_control_msg(joy->udev,
|
|
||||||
usb_sndctrlpipe(joy->udev, 0),
|
|
||||||
X52_VENDOR_REQUEST,
|
|
||||||
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
|
|
||||||
val, X52_SHIFT_INDICATOR,
|
|
||||||
NULL, 0, 1000);
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**********************************************************************
|
|
||||||
* Blink manipulation functions
|
|
||||||
*********************************************************************/
|
|
||||||
int set_blink(struct x52_joy *joy)
|
|
||||||
{
|
|
||||||
int retval;
|
|
||||||
int val;
|
|
||||||
|
|
||||||
if (!joy) {
|
|
||||||
/* Just some sanity checking */
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!joy->feat_led) {
|
|
||||||
return -EOPNOTSUPP;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (joy->blink_led) {
|
|
||||||
val = X52_BLINK_ON;
|
|
||||||
} else {
|
|
||||||
val = X52_BLINK_OFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
retval = usb_control_msg(joy->udev,
|
|
||||||
usb_sndctrlpipe(joy->udev, 0),
|
|
||||||
X52_VENDOR_REQUEST,
|
|
||||||
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
|
|
||||||
val, X52_BLINK_INDICATOR,
|
|
||||||
NULL, 0, 1000);
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,76 +0,0 @@
|
||||||
/*
|
|
||||||
* Saitek X52 Pro HOTAS driver
|
|
||||||
*
|
|
||||||
* Copyright (C) 2012 Nirenjan Krishnan (nirenjan@nirenjan.org)
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU General Public License as
|
|
||||||
* published by the Free Software Foundation, version 2.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: GPL-2.0-only
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef X52JOY_COMMANDS_H
|
|
||||||
#define X52JOY_COMMANDS_H
|
|
||||||
|
|
||||||
/* X52 vendor API commands */
|
|
||||||
/* Vendor request - all commands must have this request ID */
|
|
||||||
#define X52_VENDOR_REQUEST 0x91
|
|
||||||
|
|
||||||
/* MFD Text commands */
|
|
||||||
#define X52_MFD_CLEAR_LINE 0x08
|
|
||||||
#define X52_MFD_WRITE_LINE 0x00
|
|
||||||
|
|
||||||
#define X52_MFD_LINE1 0xd1
|
|
||||||
#define X52_MFD_LINE2 0xd2
|
|
||||||
#define X52_MFD_LINE3 0xd4
|
|
||||||
|
|
||||||
/* Brightness commands */
|
|
||||||
#define X52_MFD_BRIGHTNESS 0xb1
|
|
||||||
#define X52_LED_BRIGHTNESS 0xb2
|
|
||||||
|
|
||||||
/* LED set commands */
|
|
||||||
#define X52_LED 0xb8
|
|
||||||
|
|
||||||
/* Time commands */
|
|
||||||
#define X52_TIME_CLOCK1 0xc0
|
|
||||||
#define X52_OFFS_CLOCK2 0xc1
|
|
||||||
#define X52_OFFS_CLOCK3 0xc2
|
|
||||||
|
|
||||||
/* Date commands */
|
|
||||||
#define X52_DATE_DDMM 0xc4
|
|
||||||
#define X52_DATE_YEAR 0xc8
|
|
||||||
|
|
||||||
/* Shift indicator on MFD */
|
|
||||||
#define X52_SHIFT_INDICATOR 0xfd
|
|
||||||
#define X52_SHIFT_ON 0x51
|
|
||||||
#define X52_SHIFT_OFF 0x50
|
|
||||||
|
|
||||||
/* Blink throttle & POV LED */
|
|
||||||
#define X52_BLINK_INDICATOR 0xb4
|
|
||||||
#define X52_BLINK_ON 0x51
|
|
||||||
#define X52_BLINK_OFF 0x50
|
|
||||||
|
|
||||||
/* LED indices */
|
|
||||||
#define X52_LED_FIRE 0x01
|
|
||||||
#define X52_LED_A_RED 0x02
|
|
||||||
#define X52_LED_A_GREEN 0x03
|
|
||||||
#define X52_LED_B_RED 0x04
|
|
||||||
#define X52_LED_B_GREEN 0x05
|
|
||||||
#define X52_LED_D_RED 0x06
|
|
||||||
#define X52_LED_D_GREEN 0x07
|
|
||||||
#define X52_LED_E_RED 0x08
|
|
||||||
#define X52_LED_E_GREEN 0x09
|
|
||||||
#define X52_LED_T1_RED 0x0a
|
|
||||||
#define X52_LED_T1_GREEN 0x0b
|
|
||||||
#define X52_LED_T2_RED 0x0c
|
|
||||||
#define X52_LED_T2_GREEN 0x0d
|
|
||||||
#define X52_LED_T3_RED 0x0e
|
|
||||||
#define X52_LED_T3_GREEN 0x0f
|
|
||||||
#define X52_LED_POV_RED 0x10
|
|
||||||
#define X52_LED_POV_GREEN 0x11
|
|
||||||
#define X52_LED_I_RED 0x12
|
|
||||||
#define X52_LED_I_GREEN 0x13
|
|
||||||
#define X52_LED_THROTTLE 0x14
|
|
||||||
|
|
||||||
#endif /* !defined X52JOY_COMMANDS_H */
|
|
|
@ -1,80 +0,0 @@
|
||||||
/*
|
|
||||||
* Saitek X52 Pro HOTAS driver
|
|
||||||
*
|
|
||||||
* Copyright (C) 2012 Nirenjan Krishnan (nirenjan@nirenjan.org)
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU General Public License as
|
|
||||||
* published by the Free Software Foundation, version 2.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: GPL-2.0-only
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef X52JOY_COMMON_H
|
|
||||||
#define X52JOY_COMMON_H
|
|
||||||
|
|
||||||
#include <linux/usb.h>
|
|
||||||
#include <linux/input.h>
|
|
||||||
|
|
||||||
#include "x52joy_map.h"
|
|
||||||
|
|
||||||
struct x52_joy {
|
|
||||||
struct usb_device *udev;
|
|
||||||
struct urb *irq_in;
|
|
||||||
unsigned char *idata;
|
|
||||||
dma_addr_t idata_dma;
|
|
||||||
struct input_dev *idev;
|
|
||||||
char phys[64];
|
|
||||||
|
|
||||||
u32 led_status;
|
|
||||||
struct x52_mfd_line line[X52_MFD_LINES];
|
|
||||||
struct x52_mfd_date date;
|
|
||||||
struct x52_mfd_time time;
|
|
||||||
struct x52_mfd_offs time_offs2;
|
|
||||||
struct x52_mfd_offs time_offs3;
|
|
||||||
|
|
||||||
u8 type;
|
|
||||||
u8 bri_mfd;
|
|
||||||
u8 bri_led;
|
|
||||||
|
|
||||||
u8 shift_ind:1;
|
|
||||||
u8 blink_led:1;
|
|
||||||
u8 clutch_mode:1;
|
|
||||||
|
|
||||||
u8 shift_state_enabled:1;
|
|
||||||
u8 clock_enabled:1;
|
|
||||||
u8 clutch_enabled:1;
|
|
||||||
u8 clutch_latched:1;
|
|
||||||
u8 :1;
|
|
||||||
|
|
||||||
u8 feat_mfd:1;
|
|
||||||
u8 feat_led:1;
|
|
||||||
u8 debug:1;
|
|
||||||
u8 :5;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define X52_PACKET_LEN 16
|
|
||||||
|
|
||||||
#define X52TYPE_X52 1
|
|
||||||
#define X52TYPE_X52PRO 2
|
|
||||||
#define X52TYPE_UNKNOWN 0
|
|
||||||
|
|
||||||
#define VENDOR_ID_SAITEK 0x06a3
|
|
||||||
#define PRODUCT_ID_X52_PRO 0x0762
|
|
||||||
|
|
||||||
#define X52FLAGS_SUPPORTS_MFD (1 << 0)
|
|
||||||
#define X52FLAGS_SUPPORTS_LED (1 << 1)
|
|
||||||
|
|
||||||
int set_text(struct x52_joy *joy, u8 line_no);
|
|
||||||
int set_brightness(struct x52_joy *joy, u8 target);
|
|
||||||
int set_led(struct x52_joy *joy, u8 target);
|
|
||||||
int set_date(struct x52_joy *joy);
|
|
||||||
int set_shift(struct x52_joy *joy);
|
|
||||||
int set_blink(struct x52_joy *joy);
|
|
||||||
|
|
||||||
void x52_irq_handler(struct urb *urb);
|
|
||||||
void x52_setup_input(struct input_dev *idev);
|
|
||||||
int x52_open (struct input_dev *idev);
|
|
||||||
void x52_close (struct input_dev *idev);
|
|
||||||
|
|
||||||
#endif /* !defined X52JOY_COMMON_H */
|
|
|
@ -1,243 +0,0 @@
|
||||||
/*
|
|
||||||
* Saitek X52 Pro HOTAS driver
|
|
||||||
*
|
|
||||||
* Copyright (C) 2012 Nirenjan Krishnan (nirenjan@nirenjan.org)
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU General Public License as
|
|
||||||
* published by the Free Software Foundation, version 2.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: GPL-2.0-only
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifdef CONFIG_USB_DEBUG
|
|
||||||
#define DEBUG 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <linux/input.h>
|
|
||||||
#include <linux/usb/input.h>
|
|
||||||
|
|
||||||
#include "x52joy_commands.h"
|
|
||||||
#include "x52joy_common.h"
|
|
||||||
|
|
||||||
#define X52PRO_X_SHIFT 0
|
|
||||||
#define X52PRO_X_MASK 0x3ff
|
|
||||||
#define X52PRO_Y_SHIFT 10
|
|
||||||
#define X52PRO_Y_MASK 0x3ff
|
|
||||||
#define X52PRO_RZ_SHIFT 20
|
|
||||||
#define X52PRO_RZ_MASK 0x3ff
|
|
||||||
|
|
||||||
static void x52pro_decode_urb(struct x52_joy *joy, unsigned char *data)
|
|
||||||
{
|
|
||||||
struct input_dev *idev = joy->idev;
|
|
||||||
u32 stick_axis = data[3];
|
|
||||||
stick_axis = (stick_axis << 8) | data[2];
|
|
||||||
stick_axis = (stick_axis << 8) | data[1];
|
|
||||||
stick_axis = (stick_axis << 8) | data[0];
|
|
||||||
|
|
||||||
input_report_key(idev, BTN_TRIGGER_HAPPY1, data[8] & 0x01);
|
|
||||||
input_report_key(idev, BTN_TRIGGER_HAPPY2, data[8] & 0x02);
|
|
||||||
input_report_key(idev, BTN_TRIGGER_HAPPY3, data[8] & 0x04);
|
|
||||||
input_report_key(idev, BTN_TRIGGER_HAPPY4, data[8] & 0x08);
|
|
||||||
input_report_key(idev, BTN_TRIGGER_HAPPY5, data[8] & 0x10);
|
|
||||||
input_report_key(idev, BTN_TRIGGER_HAPPY6, data[8] & 0x20);
|
|
||||||
input_report_key(idev, BTN_TRIGGER_HAPPY7, data[8] & 0x40);
|
|
||||||
input_report_key(idev, BTN_TRIGGER_HAPPY8, data[8] & 0x80);
|
|
||||||
|
|
||||||
input_report_key(idev, BTN_TRIGGER_HAPPY9, data[9] & 0x01);
|
|
||||||
input_report_key(idev, BTN_TRIGGER_HAPPY10, data[9] & 0x02);
|
|
||||||
input_report_key(idev, BTN_TRIGGER_HAPPY11, data[9] & 0x04);
|
|
||||||
input_report_key(idev, BTN_TRIGGER_HAPPY12, data[9] & 0x08);
|
|
||||||
input_report_key(idev, BTN_TRIGGER_HAPPY13, data[9] & 0x10);
|
|
||||||
input_report_key(idev, BTN_TRIGGER_HAPPY14, data[9] & 0x20);
|
|
||||||
input_report_key(idev, BTN_TRIGGER_HAPPY15, data[9] & 0x40);
|
|
||||||
input_report_key(idev, BTN_TRIGGER_HAPPY16, data[9] & 0x80);
|
|
||||||
|
|
||||||
input_report_key(idev, BTN_TRIGGER_HAPPY17, data[10] & 0x01);
|
|
||||||
input_report_key(idev, BTN_TRIGGER_HAPPY18, data[10] & 0x02);
|
|
||||||
input_report_key(idev, BTN_TRIGGER_HAPPY19, data[10] & 0x04);
|
|
||||||
input_report_key(idev, BTN_TRIGGER_HAPPY20, data[10] & 0x08);
|
|
||||||
input_report_key(idev, BTN_TRIGGER_HAPPY21, data[10] & 0x10);
|
|
||||||
input_report_key(idev, BTN_TRIGGER_HAPPY22, data[10] & 0x20);
|
|
||||||
input_report_key(idev, BTN_TRIGGER_HAPPY23, data[10] & 0x40);
|
|
||||||
input_report_key(idev, BTN_TRIGGER_HAPPY24, data[10] & 0x80);
|
|
||||||
|
|
||||||
input_report_key(idev, BTN_TRIGGER_HAPPY25, data[11] & 0x01);
|
|
||||||
input_report_key(idev, BTN_TRIGGER_HAPPY26, data[11] & 0x02);
|
|
||||||
input_report_key(idev, BTN_TRIGGER_HAPPY27, data[11] & 0x04);
|
|
||||||
input_report_key(idev, BTN_TRIGGER_HAPPY28, data[11] & 0x08);
|
|
||||||
input_report_key(idev, BTN_TRIGGER_HAPPY29, data[11] & 0x10);
|
|
||||||
input_report_key(idev, BTN_TRIGGER_HAPPY30, data[11] & 0x20);
|
|
||||||
input_report_key(idev, BTN_TRIGGER_HAPPY31, data[11] & 0x40);
|
|
||||||
input_report_key(idev, BTN_TRIGGER_HAPPY32, data[11] & 0x80);
|
|
||||||
|
|
||||||
input_report_key(idev, BTN_TRIGGER_HAPPY33, data[12] & 0x01);
|
|
||||||
input_report_key(idev, BTN_TRIGGER_HAPPY34, data[12] & 0x02);
|
|
||||||
input_report_key(idev, BTN_TRIGGER_HAPPY35, data[12] & 0x04);
|
|
||||||
input_report_key(idev, BTN_TRIGGER_HAPPY36, data[12] & 0x08);
|
|
||||||
input_report_key(idev, BTN_TRIGGER_HAPPY37, data[12] & 0x10);
|
|
||||||
input_report_key(idev, BTN_TRIGGER_HAPPY38, data[12] & 0x20);
|
|
||||||
input_report_key(idev, BTN_TRIGGER_HAPPY39, data[12] & 0x40);
|
|
||||||
|
|
||||||
input_report_abs(idev, ABS_X,
|
|
||||||
(stick_axis >> X52PRO_X_SHIFT) & X52PRO_X_MASK);
|
|
||||||
input_report_abs(idev, ABS_Y,
|
|
||||||
(stick_axis >> X52PRO_Y_SHIFT) & X52PRO_Y_MASK);
|
|
||||||
input_report_abs(idev, ABS_RZ,
|
|
||||||
(stick_axis >> X52PRO_RZ_SHIFT) & X52PRO_RZ_MASK);
|
|
||||||
|
|
||||||
input_report_abs(idev, ABS_THROTTLE, data[4]);
|
|
||||||
input_report_abs(idev, ABS_RX, data[5]);
|
|
||||||
input_report_abs(idev, ABS_RY, data[6]);
|
|
||||||
input_report_abs(idev, ABS_Z, data[7]);
|
|
||||||
|
|
||||||
input_report_abs(idev, ABS_TILT_X, data[14] & 0xF);
|
|
||||||
input_report_abs(idev, ABS_TILT_Y, data[14] >> 4);
|
|
||||||
|
|
||||||
switch(data[13]) {
|
|
||||||
case 0x00:
|
|
||||||
input_report_abs(idev, ABS_HAT0X, 0);
|
|
||||||
input_report_abs(idev, ABS_HAT0Y, 0);
|
|
||||||
break;
|
|
||||||
case 0x10:
|
|
||||||
input_report_abs(idev, ABS_HAT0X, 0);
|
|
||||||
input_report_abs(idev, ABS_HAT0Y, -1);
|
|
||||||
break;
|
|
||||||
case 0x20:
|
|
||||||
input_report_abs(idev, ABS_HAT0X, 1);
|
|
||||||
input_report_abs(idev, ABS_HAT0Y, -1);
|
|
||||||
break;
|
|
||||||
case 0x30:
|
|
||||||
input_report_abs(idev, ABS_HAT0X, 1);
|
|
||||||
input_report_abs(idev, ABS_HAT0Y, 0);
|
|
||||||
break;
|
|
||||||
case 0x40:
|
|
||||||
input_report_abs(idev, ABS_HAT0X, 1);
|
|
||||||
input_report_abs(idev, ABS_HAT0Y, 1);
|
|
||||||
break;
|
|
||||||
case 0x50:
|
|
||||||
input_report_abs(idev, ABS_HAT0X, 0);
|
|
||||||
input_report_abs(idev, ABS_HAT0Y, 1);
|
|
||||||
break;
|
|
||||||
case 0x60:
|
|
||||||
input_report_abs(idev, ABS_HAT0X, -1);
|
|
||||||
input_report_abs(idev, ABS_HAT0Y, 1);
|
|
||||||
break;
|
|
||||||
case 0x70:
|
|
||||||
input_report_abs(idev, ABS_HAT0X, -1);
|
|
||||||
input_report_abs(idev, ABS_HAT0Y, 0);
|
|
||||||
break;
|
|
||||||
case 0x80:
|
|
||||||
input_report_abs(idev, ABS_HAT0X, -1);
|
|
||||||
input_report_abs(idev, ABS_HAT0Y, -1);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
input_sync(idev);
|
|
||||||
}
|
|
||||||
|
|
||||||
void x52_irq_handler(struct urb *urb)
|
|
||||||
{
|
|
||||||
struct x52_joy *joy = urb->context;
|
|
||||||
int retval, status;
|
|
||||||
|
|
||||||
status = urb->status;
|
|
||||||
|
|
||||||
switch (status) {
|
|
||||||
case 0:
|
|
||||||
/* success */
|
|
||||||
break;
|
|
||||||
case -ECONNRESET:
|
|
||||||
case -ENOENT:
|
|
||||||
case -ESHUTDOWN:
|
|
||||||
/* This URB is terminated, clean up */
|
|
||||||
dev_dbg(joy->idev->dev.parent,
|
|
||||||
"%s - URB shutting down with status: %d",
|
|
||||||
__func__, status);
|
|
||||||
return;
|
|
||||||
default:
|
|
||||||
dev_dbg(joy->idev->dev.parent,
|
|
||||||
"%s - nonzero URB status received: %d",
|
|
||||||
__func__, status);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (joy->type) {
|
|
||||||
case X52TYPE_X52PRO:
|
|
||||||
x52pro_decode_urb(joy, joy->idata);
|
|
||||||
break;
|
|
||||||
case X52TYPE_X52:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
error:
|
|
||||||
retval = usb_submit_urb(urb, GFP_ATOMIC);
|
|
||||||
if (retval)
|
|
||||||
dev_err(joy->idev->dev.parent,
|
|
||||||
"%s - usb_submit_urb failed with result %d",
|
|
||||||
__func__, retval);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void x52_setup_input(struct input_dev *idev)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (!idev) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Enable event inputs.
|
|
||||||
*
|
|
||||||
* EV_KEY for buttons (and keyboard events in the future)
|
|
||||||
* EV_ABS for the axis
|
|
||||||
* EV_REL for future mouse support by the mouse stick
|
|
||||||
*/
|
|
||||||
idev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
|
|
||||||
|
|
||||||
/* For now, map the buttons directly */
|
|
||||||
for (i = BTN_TRIGGER_HAPPY1; i <= BTN_TRIGGER_HAPPY39; i++) {
|
|
||||||
__set_bit(i, idev->keybit);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Map the axes */
|
|
||||||
input_set_abs_params(idev, ABS_X, 0, 1023, 0, 0);
|
|
||||||
input_set_abs_params(idev, ABS_Y, 0, 1023, 0, 0);
|
|
||||||
input_set_abs_params(idev, ABS_RZ, 0, 1023, 0, 0);
|
|
||||||
|
|
||||||
input_set_abs_params(idev, ABS_THROTTLE, 0, 255, 0, 0);
|
|
||||||
input_set_abs_params(idev, ABS_RX, 0, 255, 0, 0);
|
|
||||||
input_set_abs_params(idev, ABS_RY, 0, 255, 0, 0);
|
|
||||||
input_set_abs_params(idev, ABS_Z, 0, 255, 0, 0);
|
|
||||||
|
|
||||||
/* Mouse stick */
|
|
||||||
input_set_abs_params(idev, ABS_TILT_X, 0, 15, 0, 0);
|
|
||||||
input_set_abs_params(idev, ABS_TILT_Y, 0, 15, 0, 0);
|
|
||||||
|
|
||||||
/* Hat switch */
|
|
||||||
input_set_abs_params(idev, ABS_HAT0X, -1, 1, 0, 0);
|
|
||||||
input_set_abs_params(idev, ABS_HAT0Y, -1, 1, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
int x52_open (struct input_dev *idev)
|
|
||||||
{
|
|
||||||
struct x52_joy *joy = input_get_drvdata(idev);
|
|
||||||
|
|
||||||
joy->irq_in->dev = joy->udev;
|
|
||||||
if (usb_submit_urb(joy->irq_in, GFP_KERNEL)) {
|
|
||||||
return -EIO;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void x52_close (struct input_dev *idev)
|
|
||||||
{
|
|
||||||
struct x52_joy *joy = input_get_drvdata(idev);
|
|
||||||
|
|
||||||
usb_kill_urb(joy->irq_in);
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,190 +0,0 @@
|
||||||
/*
|
|
||||||
* Saitek X52 Pro HOTAS driver
|
|
||||||
*
|
|
||||||
* Copyright (C) 2012 Nirenjan Krishnan (nirenjan@nirenjan.org)
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU General Public License as
|
|
||||||
* published by the Free Software Foundation, version 2.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: GPL-2.0-only
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef X52JOY_MAP_H
|
|
||||||
#define X52JOY_MAP_H
|
|
||||||
|
|
||||||
#include <linux/usb.h>
|
|
||||||
|
|
||||||
/**********************************************************************
|
|
||||||
* X52 enumerations
|
|
||||||
*********************************************************************/
|
|
||||||
enum x52_button {
|
|
||||||
x52_button_trigger1, /* Trigger primary */
|
|
||||||
x52_button_launch, /* Launch/Fire */
|
|
||||||
x52_button_a,
|
|
||||||
x52_button_b,
|
|
||||||
x52_button_c,
|
|
||||||
x52_button_pinkie, /* Pinkie shift switch */
|
|
||||||
|
|
||||||
x52_button_d, /* D and E buttons are */
|
|
||||||
x52_button_e, /* on the throttle */
|
|
||||||
|
|
||||||
x52_button_t1_up, /* Toggle 1 up/down */
|
|
||||||
x52_button_t1_dn,
|
|
||||||
x52_button_t2_up, /* Toggle 2 up/down */
|
|
||||||
x52_button_t2_dn,
|
|
||||||
x52_button_t3_up, /* Toggle 3 up/down */
|
|
||||||
x52_button_t3_dn,
|
|
||||||
x52_button_trigger2, /* Trigger secondary */
|
|
||||||
|
|
||||||
x52_button_mouse_left,
|
|
||||||
x52_button_mouse_scroll_dn, // Down & up are from the POV of
|
|
||||||
x52_button_mouse_scroll_up, // the user
|
|
||||||
x52_button_mouse_right,
|
|
||||||
|
|
||||||
x52_button_stick_pov_N, // These two POVs should really
|
|
||||||
x52_button_stick_pov_E, // be represented by hats, but
|
|
||||||
x52_button_stick_pov_S, // the joystick reports them as
|
|
||||||
x52_button_stick_pov_W, // button presses.
|
|
||||||
|
|
||||||
x52_button_throttle_pov_N, // For the throttle, N, E, S, W
|
|
||||||
x52_button_throttle_pov_E, // are taken if you look at it
|
|
||||||
x52_button_throttle_pov_S, // from the position of the user
|
|
||||||
x52_button_throttle_pov_W, // NOT from the rear of the throttle
|
|
||||||
|
|
||||||
x52_button_mode_select_1, // The mode selection switch is not
|
|
||||||
x52_button_mode_select_2, // a push button but a selector -
|
|
||||||
x52_button_mode_select_3, // only one can be active at a time
|
|
||||||
|
|
||||||
x52_button_clutch,
|
|
||||||
x52_button_function,
|
|
||||||
x52_button_start_stop,
|
|
||||||
x52_button_reset,
|
|
||||||
x52_button_pg_up,
|
|
||||||
x52_button_pg_dn,
|
|
||||||
x52_button_up,
|
|
||||||
x52_button_dn,
|
|
||||||
x52_button_select,
|
|
||||||
|
|
||||||
x52_button_max
|
|
||||||
};
|
|
||||||
|
|
||||||
enum x52_axis {
|
|
||||||
x52_axis_x, /* Stick X axis */
|
|
||||||
x52_axis_y, /* Stick Y axis */
|
|
||||||
x52_axis_rz, /* Stick twist axis */
|
|
||||||
|
|
||||||
x52_axis_z, /* Throttle axis */
|
|
||||||
x52_axis_rx, /* Rotary X axis */
|
|
||||||
x52_axis_ry, /* Rotary Y axis */
|
|
||||||
x52_axis_slider, /* Slider axis */
|
|
||||||
|
|
||||||
x52_axis_mouse_x, /* Mouse stick X axis */
|
|
||||||
x52_axis_mouse_y, /* Mouse stick Y axis */
|
|
||||||
|
|
||||||
x52_axis_max
|
|
||||||
};
|
|
||||||
|
|
||||||
/**********************************************************************
|
|
||||||
* X52 joystick settings
|
|
||||||
*********************************************************************/
|
|
||||||
/* Deadzone settings - no response if value ... */
|
|
||||||
struct x52_axis_deadzone {
|
|
||||||
u16 dead_lo; /* value < dead_lo */
|
|
||||||
u16 dead_hi; /* value > dead_hi */
|
|
||||||
|
|
||||||
u16 dead_fuzz; /* dead_fuzz > 0 && */
|
|
||||||
u16 dead_flat; /* flat - fuzz < value < flat + fuzz */
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The X52 MFD supports the following:
|
|
||||||
* - 3 lines of 16 characters each
|
|
||||||
* - Clock with HH:MM
|
|
||||||
* - Date with YYMMDD (IIRC)
|
|
||||||
*/
|
|
||||||
#define X52_MFD_LINE_SIZE 16
|
|
||||||
#define X52_MFD_LINES 3
|
|
||||||
|
|
||||||
struct x52_mfd_line {
|
|
||||||
u8 text[X52_MFD_LINE_SIZE];
|
|
||||||
u8 length;
|
|
||||||
};
|
|
||||||
|
|
||||||
enum x52_mfd_date_format {
|
|
||||||
x52_mfd_format_yymmdd, /* YY-MM-DD */
|
|
||||||
x52_mfd_format_mmddyy, /* MM-DD-YY */
|
|
||||||
x52_mfd_format_ddmmyy, /* DD-MM-YY */
|
|
||||||
x52_mfd_format_max,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct x52_mfd_date {
|
|
||||||
u8 year;
|
|
||||||
u8 month;
|
|
||||||
u8 day;
|
|
||||||
u8 format; /* See format enum */
|
|
||||||
};
|
|
||||||
|
|
||||||
struct x52_mfd_time {
|
|
||||||
u8 hour;
|
|
||||||
u8 minute;
|
|
||||||
u8 h24; /* 24 hour format if 1 */
|
|
||||||
};
|
|
||||||
|
|
||||||
struct x52_mfd_offs {
|
|
||||||
u8 min_off; /* Minute offset from clock 0 */
|
|
||||||
u8 neg_off; /* Negative offset if 1 */
|
|
||||||
u8 h24; /* 24 hour format if 1 */
|
|
||||||
};
|
|
||||||
|
|
||||||
/**********************************************************************
|
|
||||||
* X52 mappings
|
|
||||||
*********************************************************************/
|
|
||||||
/*
|
|
||||||
* Modes to map
|
|
||||||
*
|
|
||||||
* Right now, the module supports only 6 modes, listed as follows:
|
|
||||||
* - Mode 1
|
|
||||||
* - Mode 2
|
|
||||||
* - Mode 3
|
|
||||||
* - Mode 1 + Pinkie
|
|
||||||
* - Mode 2 + Pinkie
|
|
||||||
* - Mode 3 + Pinkie
|
|
||||||
* The last 3 modes use the pinkie switch as a shift selector.
|
|
||||||
*/
|
|
||||||
enum x52_map_modes {
|
|
||||||
x52_map_mode1,
|
|
||||||
x52_map_mode2,
|
|
||||||
x52_map_mode3,
|
|
||||||
x52_map_mode1shift,
|
|
||||||
x52_map_mode2shift,
|
|
||||||
x52_map_mode3shift,
|
|
||||||
x52_map_max
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Structure to map joystick button input to a keyboard or mouse event */
|
|
||||||
struct x52_event {
|
|
||||||
u16 type;
|
|
||||||
u16 code;
|
|
||||||
s32 value;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This defines the maximum number of keyboard or mouse events that can
|
|
||||||
* be programmed.
|
|
||||||
*/
|
|
||||||
#define X52_MAP_MAX_EVENTS 64
|
|
||||||
|
|
||||||
struct x52_map_event {
|
|
||||||
u8 mode_selector;
|
|
||||||
u8 flags;
|
|
||||||
u8 button_or_axis;
|
|
||||||
u8 fallback;
|
|
||||||
|
|
||||||
u16 range_low;
|
|
||||||
u16 range_high;
|
|
||||||
|
|
||||||
struct x52_event events[X52_MAP_MAX_EVENTS];
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* !defined X52JOY_MAP_H */
|
|
Loading…
Reference in New Issue