mirror of https://github.com/nirenjan/libx52.git
Add initial version of X52pro joystick driver
This is pretty much bare bones code to get a basic sysfs filesystem in place. It has only code to create sysfs files for the 3 MFD lines. Right now, this needs to be enabled by unplugging the joystick, insmod'ing the x52joy.ko module, rmmod'ing the usbhid module and replugging the joystick. We don't yet have a /dev/input/ interface and there's no interrupt message handling yet.pull/3/head
parent
e9bfeb0f02
commit
42642d5905
|
@ -0,0 +1,13 @@
|
|||
# Compiled object files
|
||||
*.ko
|
||||
*.o
|
||||
*.mod.*
|
||||
|
||||
# Module files
|
||||
modules.order
|
||||
Module.symvers
|
||||
.*.cmd
|
||||
.tmp_versions
|
||||
|
||||
# Vim swap files
|
||||
.*.swp
|
|
@ -0,0 +1,9 @@
|
|||
obj-m := x52joy.o
|
||||
KDIR := /lib/modules/$(shell uname -r)/build
|
||||
PWD := $(shell pwd)
|
||||
|
||||
all:
|
||||
$(MAKE) -C $(KDIR) M=$(PWD) modules
|
||||
|
||||
clean:
|
||||
$(MAKE) -C $(KDIR) M=$(PWD) clean
|
|
@ -0,0 +1,225 @@
|
|||
/*
|
||||
* Saitek X52 Pro HOTAS driver - 1.0
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#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>
|
||||
|
||||
#define DRIVER_AUTHOR "Nirenjan Krishnan, nirenjan@gmail.com"
|
||||
#define DRIVER_DESC "Saitek X52Pro HOTAS Driver"
|
||||
|
||||
#define VENDOR_ID_SAITEK 0x06a3
|
||||
#define PRODUCT_ID_X52_PRO 0x0762
|
||||
|
||||
/* 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);
|
||||
|
||||
/*
|
||||
* The X52 MFD supports the following:
|
||||
* - 3 lines of 16 characters each
|
||||
* - Clock with HH:MM
|
||||
* - Date with YYMMDD (IIRC)
|
||||
*/
|
||||
#define DRIVER_LINE_SIZE 256 /* Support upto 256 bytes in the driver */
|
||||
#define X52_MFD_LINE_SIZE 17 /* Add one for null byte */
|
||||
|
||||
struct x52_mfd_line {
|
||||
u8 text[DRIVER_LINE_SIZE];
|
||||
u16 length;
|
||||
u16 current_pos;
|
||||
};
|
||||
|
||||
struct x52_joy {
|
||||
struct usb_device *udev;
|
||||
u32 led_status;
|
||||
struct x52_mfd_line line[3];
|
||||
u8 time_hour;
|
||||
u8 time_min;
|
||||
u16 time_offs2;
|
||||
u16 time_offs3;
|
||||
u8 date_year;
|
||||
u8 date_month;
|
||||
u8 date_day;
|
||||
|
||||
u8 mode_h24:1;
|
||||
u8 feat_mfd:1;
|
||||
u8 feat_led:1;
|
||||
u8 debug:1;
|
||||
};
|
||||
|
||||
/**********************************************************************
|
||||
* MFD Line manipulation functions
|
||||
*********************************************************************/
|
||||
static void set_text(u8 line_no)
|
||||
{
|
||||
/* TODO */
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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;
|
||||
|
||||
if (!joy->feat_mfd) {
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
/* Copy the string from src to dst, upto 16 characters max */
|
||||
for (i = 0, length = 0; i < DRIVER_LINE_SIZE - 1 && i < count; i++, length++) {
|
||||
joy->line[line].text[i] = buf[i];
|
||||
}
|
||||
joy->line[line].length = length;
|
||||
joy->line[line].current_pos = 0;
|
||||
|
||||
/* Append empty bytes until the destination is full */
|
||||
for ( ; i < DRIVER_LINE_SIZE; i++) {
|
||||
/* The X52 pro MFD uses space characters as empty characters */
|
||||
joy->line[line].text[i] = 32;
|
||||
}
|
||||
set_text(line);
|
||||
return 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(line##no, S_IWUGO | S_IRUGO, show_text_line##no, set_text_line##no);
|
||||
|
||||
show_set_text(1);
|
||||
show_set_text(2);
|
||||
show_set_text(3);
|
||||
|
||||
/**********************************************************************
|
||||
* X52 driver functions
|
||||
*********************************************************************/
|
||||
static int x52_probe(struct usb_interface *intf,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
struct usb_device *dev = interface_to_usbdev(intf);
|
||||
struct x52_joy *joy = NULL;
|
||||
int retval = -ENOMEM;
|
||||
|
||||
joy = kmalloc(sizeof(*joy), GFP_KERNEL);
|
||||
if (joy == NULL) {
|
||||
dev_err(&intf->dev, "Out of memory\n");
|
||||
goto error;
|
||||
}
|
||||
memset(joy, 0, sizeof(*joy));
|
||||
|
||||
joy->udev = usb_get_dev(dev);
|
||||
|
||||
/* Set the feature bits */
|
||||
joy->feat_mfd = 1;
|
||||
joy->feat_led = 1;
|
||||
|
||||
usb_set_intfdata(intf, joy);
|
||||
|
||||
device_create_file(&intf->dev, &dev_attr_line1);
|
||||
device_create_file(&intf->dev, &dev_attr_line2);
|
||||
device_create_file(&intf->dev, &dev_attr_line3);
|
||||
|
||||
dev_info(&intf->dev, "X52 device now attached\n");
|
||||
return 0;
|
||||
|
||||
error:
|
||||
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);
|
||||
|
||||
device_remove_file(&intf->dev, &dev_attr_line1);
|
||||
device_remove_file(&intf->dev, &dev_attr_line2);
|
||||
device_remove_file(&intf->dev, &dev_attr_line3);
|
||||
|
||||
usb_put_dev(joy->udev);
|
||||
kfree(joy);
|
||||
|
||||
dev_info(&intf->dev, "X52 device now disconnected\n");
|
||||
}
|
||||
|
||||
static struct usb_driver x52_driver = {
|
||||
.name = "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) {
|
||||
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_LICENSE("GPL v2");
|
||||
|
Loading…
Reference in New Issue