--- /dev/null
+/*\r
+ * Acess2 Mouse Driver\r
+ */\r
+#define DEBUG 0\r
+#include <acess.h>\r
+#include <modules.h>\r
+#include <vfs.h>\r
+#include <fs_devfs.h>\r
+#include <api_drv_common.h>\r
+#include <api_drv_joystick.h>\r
+#include "common.h"\r
+\r
+// == CONSTANTS ==\r
+#define NUM_AXIES 2 // X+Y\r
+#define NUM_BUTTONS 5 // Left, Right, Scroll Click, Scroll Up, Scroll Down\r
+\r
+// == PROTOTYPES ==\r
+// - Internal -\r
+ int PS2Mouse_Install(char **Arguments);\r
+void PS2Mouse_HandleInterrupt(Uint8 InputByte);\r
+// - Filesystem -\r
+Uint64 PS2Mouse_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);\r
+int PS2Mouse_IOCtl(tVFS_Node *Node, int ID, void *Data);\r
+\r
+// == GLOBALS ==\r
+void (*gpMouse_EnableFcn)(void);\r
+// - Settings\r
+ int giMouse_Sensitivity = 1;\r
+ int giMouse_MaxX = 640, giMouse_MaxY = 480;\r
+// - File Data\r
+Uint8 gMouse_FileData[sizeof(tJoystick_FileHeader) + NUM_AXIES*sizeof(tJoystick_Axis) + NUM_BUTTONS];\r
+tJoystick_FileHeader *gMouse_FileHeader = (void *)gMouse_FileData;\r
+tJoystick_Axis *gMouse_Axies;\r
+Uint8 *gMouse_Buttons;\r
+tJoystick_Callback gMouse_Callback;\r
+ int gMouse_CallbackArg;\r
+ int giMouse_AxisLimits[2];\r
+// - Internal State\r
+ int giMouse_Cycle = 0; // IRQ Position\r
+Uint8 gaMouse_Bytes[4] = {0,0,0,0};\r
+// - Driver definition\r
+tVFS_NodeType gMouse_NodeType = {\r
+ .Read = PS2Mouse_Read,\r
+ .IOCtl = PS2Mouse_IOCtl\r
+};\r
+tDevFS_Driver gMouse_DriverStruct = {\r
+ NULL, "PS2Mouse",\r
+ {\r
+ .NumACLs = 1, .ACLs = &gVFS_ACL_EveryoneRX,\r
+ .Type = &gMouse_NodeType\r
+ }\r
+};\r
+\r
+// == CODE ==\r
+int PS2Mouse_Install(char **Arguments)\r
+{\r
+ \r
+\r
+ // Set up variables\r
+ gMouse_Axies = (void*)&gMouse_FileData[4];\r
+ gMouse_Buttons = (void*)&gMouse_Axies[NUM_AXIES];\r
+\r
+ gMouse_FileHeader->NAxies = 2; gMouse_FileHeader->NButtons = 3;\r
+ gMouse_Axies[0].MinValue = -10; gMouse_Axies[0].MaxValue = 10;\r
+ gMouse_Axies[1].MinValue = -10; gMouse_Axies[1].MaxValue = 10;\r
+ \r
+ // Initialise Mouse Controller\r
+ giMouse_Cycle = 0; // Set Current Cycle position\r
+ gpMouse_EnableFcn();\r
+ \r
+ DevFS_AddDevice(&gMouse_DriverStruct);\r
+ \r
+ return MODULE_ERR_OK;\r
+}\r
+\r
+/* Handle Mouse Interrupt\r
+ */\r
+void PS2Mouse_HandleInterrupt(Uint8 InputByte)\r
+{\r
+ Uint8 flags;\r
+ int d[2], d_accel[2];\r
+ int i;\r
+ \r
+ // Gather mouse data\r
+ gaMouse_Bytes[giMouse_Cycle] = InputByte;\r
+ LOG("gaMouse_Bytes[%i] = 0x%02x", gMouse_Axies[0].MaxValue);\r
+ // - If bit 3 of the first byte is not set, it's not a valid packet?\r
+ if(giMouse_Cycle == 0 && !(gaMouse_Bytes[0] & 0x08) )\r
+ return ;\r
+ giMouse_Cycle++;\r
+ if(giMouse_Cycle < 3)\r
+ return ;\r
+\r
+ giMouse_Cycle = 0;\r
+\r
+ // Actual Processing (once we have all bytes) \r
+ flags = gaMouse_Bytes[0];\r
+\r
+ LOG("flags = 0x%x", flags);\r
+ \r
+ // Check for X/Y Overflow\r
+ if(flags & 0xC0) return;\r
+ \r
+ // Calculate dX and dY\r
+ d[0] = gaMouse_Bytes[1]; if(flags & 0x10) d[0] = -(256-d[0]); // x\r
+ d[1] = gaMouse_Bytes[2]; if(flags & 0x20) d[1] = -(256-d[1]); // y\r
+ d[1] = -d[1]; // Y is negated\r
+ LOG("RAW dx=%i, dy=%i\n", d[0], d[1]);\r
+ // Apply scaling\r
+ // TODO: Apply a form of curve to the mouse movement (dx*log(dx), dx^k?)\r
+ // TODO: Independent sensitivities?\r
+ // TODO: Disable acceleration via a flag?\r
+ d_accel[0] = d[0]*giMouse_Sensitivity;\r
+ d_accel[1] = d[1]*giMouse_Sensitivity;\r
+ \r
+ // Set Buttons (Primary)\r
+ for( i = 0; i < 3; i ++ )\r
+ {\r
+ Uint8 newVal = (flags & (1 << i)) ? 0xFF : 0;\r
+ if(newVal != gMouse_Buttons[i]) {\r
+ if( gMouse_Callback )\r
+ gMouse_Callback(gMouse_CallbackArg, 0, i, newVal - gMouse_Buttons[i]);\r
+ gMouse_Buttons[i] = newVal;\r
+ }\r
+ }\r
+ \r
+ // Update X and Y Positions\r
+ for( i = 0; i < 2; i ++ )\r
+ {\r
+ Sint16 newCursor = 0;\r
+ if( giMouse_AxisLimits[i] )\r
+ newCursor = MIN( MAX(0, gMouse_Axies[i].CursorPos + d_accel[i]), giMouse_AxisLimits[i] );;\r
+ \r
+ if( gMouse_Callback )\r
+ {\r
+ if(giMouse_AxisLimits[i] && gMouse_Axies[i].CursorPos != newCursor)\r
+ gMouse_Callback(gMouse_CallbackArg, 1, i, newCursor - gMouse_Axies[i].CursorPos);\r
+ if(!giMouse_AxisLimits[i] && gMouse_Axies[i].CurValue != d_accel[i])\r
+ gMouse_Callback(gMouse_CallbackArg, 1, i, d_accel[i] - gMouse_Axies[i].CurValue);\r
+ }\r
+ \r
+ gMouse_Axies[i].CurValue = d_accel[i];\r
+ gMouse_Axies[i].CursorPos = newCursor;\r
+ }\r
+\r
+// Log("Mouse at %ix%i", gMouse_Axies[0].CursorPos, gMouse_Axies[1].CursorPos);\r
+ \r
+ VFS_MarkAvaliable(&gMouse_DriverStruct.RootNode, 1);\r
+}\r
+\r
+/* Read mouse state (coordinates)\r
+ */\r
+Uint64 PS2Mouse_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)\r
+{\r
+ if(Offset > sizeof(gMouse_FileData)) return 0;\r
+ if(Length > sizeof(gMouse_FileData)) Length = sizeof(gMouse_FileData);\r
+ if(Offset + Length > sizeof(gMouse_FileData)) Length = sizeof(gMouse_FileData) - Offset;\r
+\r
+ memcpy(Buffer, &gMouse_FileData[Offset], Length);\r
+ \r
+ VFS_MarkAvaliable(Node, 0);\r
+ return Length;\r
+}\r
+\r
+static const char *csaIOCtls[] = {DRV_IOCTLNAMES, DRV_JOY_IOCTLNAMES, NULL};\r
+/* Handle messages to the device\r
+ */\r
+int PS2Mouse_IOCtl(tVFS_Node *Node, int ID, void *Data)\r
+{\r
+ tJoystick_NumValue *info = Data;\r
+\r
+ switch(ID)\r
+ {\r
+ BASE_IOCTLS(DRV_TYPE_JOYSTICK, "PS2Mouse", 0x100, csaIOCtls);\r
+\r
+ case JOY_IOCTL_SETCALLBACK: // TODO: Implement\r
+ return -1;\r
+ \r
+ case JOY_IOCTL_SETCALLBACKARG: // TODO: Implement\r
+ return -1;\r
+ \r
+ case JOY_IOCTL_GETSETAXISLIMIT:\r
+ if(!info) return 0;\r
+ if(info->Num < 0 || info->Num >= 2) return 0;\r
+ if(info->Value != -1)\r
+ giMouse_AxisLimits[info->Num] = info->Value;\r
+ return giMouse_AxisLimits[info->Num];\r
+ \r
+ case JOY_IOCTL_GETSETAXISPOSITION:\r
+ if(!info) return 0;\r
+ if(info->Num < 0 || info->Num >= 2) return 0;\r
+ if(info->Value != -1)\r
+ gMouse_Axies[info->Num].CursorPos = info->Value;\r
+ return gMouse_Axies[info->Num].CursorPos;\r
+\r
+ case JOY_IOCTL_GETSETAXISFLAGS:\r
+ return -1;\r
+ \r
+ case JOY_IOCTL_GETSETBUTTONFLAGS:\r
+ return -1;\r
+\r
+ default:\r
+ return 0;\r
+ }\r
+}\r
+\r