A project to connect a genesis controller to USB via an Arduino board.
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

2 years ago
  1. #include <errno.h>
  2. #include <string.h>
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <linux/uinput.h>
  6. #include <fcntl.h>
  7. #include <unistd.h>
  8. #include <signal.h>
  9. #include <termios.h>
  10. //List of button definitons and whatnot
  11. #define START 0x01
  12. #define WEST 0x02
  13. #define EAST 0x08
  14. #define SOUTH 0x04
  15. #define DPAD_LEFT 0x10
  16. #define DPAD_RIGHT 0x20
  17. #define DPAD_DOWN 0x40
  18. #define DPAD_UP 0x80
  19. #define SELECT 0x100
  20. #define LEFT_TRIGGER 0x200
  21. #define NORTH 0x400
  22. #define RIGHT_TRIGGER 0x800
  23. //#define DEBUG_MODE 0x1337
  24. //#define CONTROLLER_MODE 0x420
  25. //A list that will hold the button offsets in a sequential order
  26. int buttons_list[] = {
  27. START,WEST,EAST,SOUTH, // 0 - 3
  28. DPAD_LEFT,DPAD_RIGHT,DPAD_DOWN,DPAD_UP, // 4 - 7
  29. SELECT,LEFT_TRIGGER,NORTH,RIGHT_TRIGGER // 8 - 11
  30. };
  31. #ifdef DEBUG_MODE
  32. //1-letter names for buttons
  33. char debug_names[] = "TWESLRDUMZNC";
  34. #endif
  35. //Actual mappings for the buttons, in the same order as in buttons_list
  36. #ifdef CONTROLLER_MODE
  37. //Mappings that are binding the controller as a joystick instead of a keyboard
  38. int mappings[] = {
  39. BTN_START,BTN_WEST,BTN_EAST,BTN_SOUTH,
  40. BTN_DPAD_LEFT,BTN_DPAD_RIGHT,BTN_DPAD_DOWN,BTN_DPAD_UP,
  41. BTN_SELECT,BTN_TL,BTN_NORTH,BTN_TR
  42. };
  43. #else
  44. //Mappings that correspond to a particular subset of keyboard keys
  45. int mappings[] = {
  46. KEY_ESC,KEY_A,KEY_D,KEY_S,
  47. KEY_LEFT,KEY_RIGHT,KEY_DOWN,KEY_UP,
  48. KEY_X,KEY_Z,KEY_W,KEY_C
  49. };
  50. #endif
  51. int input;
  52. int uinput_fd;
  53. //a bit of stolen code to make things work
  54. void emit(int fd, int type, int code, int val) {
  55. struct input_event ie;
  56. ie.type = type;
  57. ie.code = code;
  58. ie.value = val;
  59. /* timestamp values below are ignored */
  60. ie.time.tv_sec = 0;
  61. ie.time.tv_usec = 0;
  62. write(fd, &ie, sizeof(ie));
  63. }
  64. void bye(int signum) {
  65. //wait some more just because we want all the events that are happening to happen before we close everything.
  66. sleep(1);
  67. printf("Exit signal received - destroying the uinput device.\n");
  68. close(input);
  69. ioctl(uinput_fd, UI_DEV_DESTROY);
  70. sleep(1);
  71. close(uinput_fd);
  72. exit(0);
  73. };
  74. int set_interface_attribs(int fd, int speed, int parity) {
  75. struct termios tty;
  76. if (tcgetattr(fd, &tty) != 0) {
  77. printf("Error %d from tcget",errno);
  78. return -1;
  79. }
  80. cfsetospeed(&tty, speed);
  81. cfsetispeed(&tty, speed);
  82. tty.c_lflag = 0;
  83. tty.c_cflag |= CRTSCTS | CS8 | CLOCAL | CREAD;
  84. tty.c_iflag = IGNPAR;
  85. tty.c_oflag = 0;
  86. tty.c_cc[VMIN] = 1;
  87. tty.c_cc[VTIME] = 0;
  88. tcflush(fd, TCIFLUSH);
  89. if (tcsetattr(fd, TCSANOW, &tty) != 0) {
  90. printf("Error %d when setting up tty", errno);
  91. return -1;
  92. }
  93. return 0;
  94. }
  95. int set_blocking(int fd, int should_block) {
  96. struct termios tty;
  97. memset (&tty, 0, sizeof(tty));
  98. if(tcgetattr(fd, &tty) != 0) {
  99. printf("Error %d from tcget", errno);
  100. return -1;
  101. }
  102. tty.c_cc[VMIN] = should_block ? 1 : 0;
  103. tty.c_cc[VTIME] = 0;
  104. if (tcsetattr(fd, TCSANOW, &tty) != 0) {
  105. printf("Error %d from tcset", errno);
  106. return -1;
  107. }
  108. return 0;
  109. }
  110. int main(int argc, char* argv[]) {
  111. if (argc < 2) {
  112. printf("Usage: driver <input device>\n");
  113. return 1;
  114. }
  115. //Open tty device for reading
  116. input = open(argv[1], O_RDWR | O_NOCTTY | O_SYNC);
  117. if (!input) {
  118. printf("Unable to open device %s for reading: %s\n",argv[1],strerror(errno));
  119. return errno;
  120. }
  121. set_interface_attribs(input, B9600, 0);
  122. set_blocking(input, 1);
  123. //Create uinput configuration struct and open /dev/uinput
  124. struct uinput_setup usetup;
  125. uinput_fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK);
  126. //Add this to gracefully close uinput_fd and input
  127. signal(SIGINT, bye);
  128. ioctl(uinput_fd, UI_SET_EVBIT, EV_KEY);
  129. for (int k = 0; k < 12; k++) {
  130. ioctl(uinput_fd, UI_SET_KEYBIT, mappings[k]);
  131. }
  132. //Clear struct, set vendor and product.
  133. memset(&usetup, 0, sizeof(usetup));
  134. usetup.id.bustype = BUS_USB;
  135. usetup.id.vendor = 0x041e;
  136. usetup.id.product = 0x1003;
  137. strcpy(usetup.name,"Macrohard YBox 2pi LPT2USB controller");
  138. //Call setup
  139. if (ioctl(uinput_fd, UI_DEV_SETUP, &usetup)) {
  140. perror("UI_DEV_SETUP");
  141. printf("Note: This might have been the result of not running the program as root\n");
  142. return 1;
  143. }
  144. if (ioctl(uinput_fd, UI_DEV_CREATE)) {
  145. perror("UI_DEV_CREATE");
  146. return 1;
  147. }
  148. //Wait for some time so that uinput has time to setup stuff
  149. sleep(1);
  150. short unsigned int buffer[2];
  151. short unsigned int prev_state = 0x0;
  152. short unsigned int changes = 0x0;
  153. short unsigned int current_state = 0x0;
  154. //Main loop
  155. while(1) {
  156. read(input, buffer, 2);
  157. current_state = ~buffer[0];
  158. changes = prev_state ^ current_state;
  159. if (changes != 0) {
  160. #ifdef DEBUG_MODE
  161. printf("State hash: %u\n",current_state);
  162. printf("Recieved message: %u\n",buffer[0]);
  163. #endif
  164. for (int k = 0; k < 12; k++) {
  165. if (changes & buttons_list[k]) {
  166. emit(uinput_fd, EV_KEY, mappings[k], (current_state & buttons_list[k]) > 0);
  167. emit(uinput_fd, EV_SYN, SYN_REPORT, 0);
  168. #ifdef DEBUG_MODE
  169. printf("Internal key name: %c\n",debug_names[k]);
  170. printf("Key state: %u\n",(current_state & buttons_list[k]) > 0);
  171. printf("Key mapping: %u\n",mappings[k]);
  172. #endif
  173. }
  174. }
  175. #ifdef DEBUG_MODE
  176. printf("-------\n");
  177. fflush(stdout);
  178. #endif
  179. }
  180. prev_state = current_state;
  181. }
  182. //haha what a loser can't even get here because while true do loop
  183. return 0;
  184. }