You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
207 lines
5.6 KiB
207 lines
5.6 KiB
#include <errno.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <linux/uinput.h>
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
#include <signal.h>
|
|
#include <termios.h>
|
|
|
|
//List of button definitons and whatnot
|
|
#define START 0x01
|
|
#define WEST 0x02
|
|
#define EAST 0x08
|
|
#define SOUTH 0x04
|
|
#define DPAD_LEFT 0x10
|
|
#define DPAD_RIGHT 0x20
|
|
#define DPAD_DOWN 0x40
|
|
#define DPAD_UP 0x80
|
|
#define SELECT 0x100
|
|
#define LEFT_TRIGGER 0x200
|
|
#define NORTH 0x400
|
|
#define RIGHT_TRIGGER 0x800
|
|
//#define DEBUG_MODE 0x1337
|
|
//#define CONTROLLER_MODE 0x420
|
|
|
|
//A list that will hold the button offsets in a sequential order
|
|
int buttons_list[] = {
|
|
START,WEST,EAST,SOUTH, // 0 - 3
|
|
DPAD_LEFT,DPAD_RIGHT,DPAD_DOWN,DPAD_UP, // 4 - 7
|
|
SELECT,LEFT_TRIGGER,NORTH,RIGHT_TRIGGER // 8 - 11
|
|
};
|
|
|
|
|
|
#ifdef DEBUG_MODE
|
|
//1-letter names for buttons
|
|
char debug_names[] = "TWESLRDUMZNC";
|
|
#endif
|
|
|
|
//Actual mappings for the buttons, in the same order as in buttons_list
|
|
#ifdef CONTROLLER_MODE
|
|
//Mappings that are binding the controller as a joystick instead of a keyboard
|
|
int mappings[] = {
|
|
BTN_START,BTN_WEST,BTN_EAST,BTN_SOUTH,
|
|
BTN_DPAD_LEFT,BTN_DPAD_RIGHT,BTN_DPAD_DOWN,BTN_DPAD_UP,
|
|
BTN_SELECT,BTN_TL,BTN_NORTH,BTN_TR
|
|
};
|
|
#else
|
|
//Mappings that correspond to a particular subset of keyboard keys
|
|
int mappings[] = {
|
|
KEY_ESC,KEY_A,KEY_D,KEY_S,
|
|
KEY_LEFT,KEY_RIGHT,KEY_DOWN,KEY_UP,
|
|
KEY_X,KEY_Z,KEY_W,KEY_C
|
|
};
|
|
#endif
|
|
|
|
|
|
int input;
|
|
int uinput_fd;
|
|
|
|
//a bit of stolen code to make things work
|
|
void emit(int fd, int type, int code, int val) {
|
|
struct input_event ie;
|
|
|
|
ie.type = type;
|
|
ie.code = code;
|
|
ie.value = val;
|
|
/* timestamp values below are ignored */
|
|
ie.time.tv_sec = 0;
|
|
ie.time.tv_usec = 0;
|
|
|
|
write(fd, &ie, sizeof(ie));
|
|
}
|
|
|
|
void bye(int signum) {
|
|
//wait some more just because we want all the events that are happening to happen before we close everything.
|
|
sleep(1);
|
|
printf("Exit signal received - destroying the uinput device.\n");
|
|
close(input);
|
|
ioctl(uinput_fd, UI_DEV_DESTROY);
|
|
sleep(1);
|
|
close(uinput_fd);
|
|
exit(0);
|
|
};
|
|
|
|
int set_interface_attribs(int fd, int speed, int parity) {
|
|
struct termios tty;
|
|
if (tcgetattr(fd, &tty) != 0) {
|
|
printf("Error %d from tcget",errno);
|
|
return -1;
|
|
}
|
|
|
|
cfsetospeed(&tty, speed);
|
|
cfsetispeed(&tty, speed);
|
|
tty.c_lflag = 0;
|
|
tty.c_cflag |= CRTSCTS | CS8 | CLOCAL | CREAD;
|
|
tty.c_iflag = IGNPAR;
|
|
tty.c_oflag = 0;
|
|
tty.c_cc[VMIN] = 1;
|
|
tty.c_cc[VTIME] = 0;
|
|
tcflush(fd, TCIFLUSH);
|
|
if (tcsetattr(fd, TCSANOW, &tty) != 0) {
|
|
printf("Error %d when setting up tty", errno);
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int set_blocking(int fd, int should_block) {
|
|
struct termios tty;
|
|
memset (&tty, 0, sizeof(tty));
|
|
if(tcgetattr(fd, &tty) != 0) {
|
|
printf("Error %d from tcget", errno);
|
|
return -1;
|
|
}
|
|
tty.c_cc[VMIN] = should_block ? 1 : 0;
|
|
tty.c_cc[VTIME] = 0;
|
|
|
|
if (tcsetattr(fd, TCSANOW, &tty) != 0) {
|
|
printf("Error %d from tcset", errno);
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int main(int argc, char* argv[]) {
|
|
if (argc < 2) {
|
|
printf("Usage: driver <input device>\n");
|
|
return 1;
|
|
}
|
|
|
|
//Open tty device for reading
|
|
input = open(argv[1], O_RDWR | O_NOCTTY | O_SYNC);
|
|
if (!input) {
|
|
printf("Unable to open device %s for reading: %s\n",argv[1],strerror(errno));
|
|
return errno;
|
|
}
|
|
set_interface_attribs(input, B9600, 0);
|
|
set_blocking(input, 1);
|
|
|
|
//Create uinput configuration struct and open /dev/uinput
|
|
struct uinput_setup usetup;
|
|
uinput_fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK);
|
|
|
|
//Add this to gracefully close uinput_fd and input
|
|
signal(SIGINT, bye);
|
|
|
|
ioctl(uinput_fd, UI_SET_EVBIT, EV_KEY);
|
|
for (int k = 0; k < 12; k++) {
|
|
ioctl(uinput_fd, UI_SET_KEYBIT, mappings[k]);
|
|
}
|
|
|
|
//Clear struct, set vendor and product.
|
|
memset(&usetup, 0, sizeof(usetup));
|
|
usetup.id.bustype = BUS_USB;
|
|
usetup.id.vendor = 0x041e;
|
|
usetup.id.product = 0x1003;
|
|
strcpy(usetup.name,"Macrohard YBox 2pi LPT2USB controller");
|
|
|
|
//Call setup
|
|
if (ioctl(uinput_fd, UI_DEV_SETUP, &usetup)) {
|
|
perror("UI_DEV_SETUP");
|
|
printf("Note: This might have been the result of not running the program as root\n");
|
|
return 1;
|
|
}
|
|
if (ioctl(uinput_fd, UI_DEV_CREATE)) {
|
|
perror("UI_DEV_CREATE");
|
|
return 1;
|
|
}
|
|
|
|
//Wait for some time so that uinput has time to setup stuff
|
|
sleep(1);
|
|
short unsigned int buffer[2];
|
|
short unsigned int prev_state = 0x0;
|
|
short unsigned int changes = 0x0;
|
|
short unsigned int current_state = 0x0;
|
|
//Main loop
|
|
while(1) {
|
|
read(input, buffer, 2);
|
|
current_state = ~buffer[0];
|
|
changes = prev_state ^ current_state;
|
|
if (changes != 0) {
|
|
#ifdef DEBUG_MODE
|
|
printf("State hash: %u\n",current_state);
|
|
printf("Recieved message: %u\n",buffer[0]);
|
|
#endif
|
|
for (int k = 0; k < 12; k++) {
|
|
if (changes & buttons_list[k]) {
|
|
emit(uinput_fd, EV_KEY, mappings[k], (current_state & buttons_list[k]) > 0);
|
|
emit(uinput_fd, EV_SYN, SYN_REPORT, 0);
|
|
#ifdef DEBUG_MODE
|
|
printf("Internal key name: %c\n",debug_names[k]);
|
|
printf("Key state: %u\n",(current_state & buttons_list[k]) > 0);
|
|
printf("Key mapping: %u\n",mappings[k]);
|
|
#endif
|
|
}
|
|
}
|
|
#ifdef DEBUG_MODE
|
|
printf("-------\n");
|
|
fflush(stdout);
|
|
#endif
|
|
}
|
|
prev_state = current_state;
|
|
}
|
|
//haha what a loser can't even get here because while true do loop
|
|
return 0;
|
|
}
|