*/\r
enum eTplJoystick_IOCtl {\r
/**\r
- * ioctl(..., struct{int Ident;tJoystickCallback *Callback})\r
+ * ioctl(..., tJoystickCallback *Callback)\r
* \brief Sets the callback\r
* \note Can be called from kernel mode only\r
*\r
JOY_IOCTL_SETCALLBACK = 4,\r
\r
/**\r
- * ioctl(..., struct{int AxisNum;int Value})\r
+ * ioctl(..., int *Argument)\r
+ * \brief Set the argument passed as the first parameter to the callback\r
+ * \note Kernel mode only\r
+ */\r
+ JOY_IOCTL_SETCALLBACKARG,\r
+\r
+ /**\r
+ * ioctl(..., tJoystickNumValue *)\r
* \brief Set maximum value for sJoystick_Axis.CurState\r
* \note If \a Value is equal to -1 (all bits set), the value is not changed\r
*/\r
JOY_IOCTL_GETSETAXISLIMIT,\r
+\r
+ /**\r
+ * ioctl(..., tJoystickNumValue *)\r
+ * \brief Set the value of sJoystick_Axis.CurState\r
+ * \note If \a Value is equal to -1 (all bits set), the value is not changed\r
+ */\r
+ JOY_IOCTL_GETSETAXISPOSITION,\r
\r
/**\r
- * ioctl(..., struct{int AxisNum;int Value})\r
+ * ioctl(..., tJoystickNumValue *)\r
* \brief Set axis flags\r
* \note If \a Value is equal to -1 (all bits set), the value is not changed\r
*/\r
JOY_IOCTL_GETSETAXISFLAGS,\r
\r
/**\r
- * ioctl(..., struct{int ButtonNum;int Value})\r
+ * ioctl(..., tJoystickNumValue *)\r
* \brief Set Button Flags\r
* \note If \a Value is equal to -1 (all bits set), the value is not changed\r
*/\r
JOY_IOCTL_GETSETBUTTONFLAGS,\r
};\r
\r
+#define DRV_JOY_IOCTLNAMES "set_callback", "set_callback_arg", "getset_axis_limit", "getset_axis_position", \\r
+ "getset_axis_flags", "getset_button_flags"\r
+\r
+// === TYPES ===\r
+typedef struct sJoystick_NumValue tJoystick_NumValue;\r
+typedef struct sJoystick_FileHeader tJoystick_FileHeader;\r
+typedef struct sJoystick_Axis tJoystick_Axis;\r
+\r
+/**\r
+ * \brief Number/Value pair for joystick IOCtls\r
+ */\r
+struct sJoystick_NumValue\r
+{\r
+ int Num; //!< Axis/Button number\r
+ int Value; //!< Value (see IOCtl defs for meaning)\r
+};\r
+\r
/**\r
* \brief Callback type for JOY_IOCTL_SETCALLBACK\r
* \param Ident Ident value passed to JOY_IOCTL_SETCALLBACK\r
* \r
*/\r
-typedef void (*tJoystickCallback)(int Ident, int bIsAxis, int Num, int Delta);\r
+typedef void (*tJoystick_Callback)(int Ident, int bIsAxis, int Num, int Delta);\r
\r
/**\r
* \struct sJoystick_FileHeader\r
};\r
\r
/**\r
- * \brief Axis Definition\r
+ * \brief Axis Definition in file data\r
*\r
* Describes the current state of an axis on the joystick.\r
* \a MinValue and \a MaxValue describe the valid range for \a CurValue\r
struct sJoystick_Axis\r
{\r
Sint16 MinValue; //!< Minumum value for \a CurValue\r
- Sint16 MaxValue; //!< Maximum value for \a MaxValue\r
+ Sint16 MaxValue; //!< Maximum value for \a CurValue\r
Sint16 CurValue; //!< Current value (joystick position)\r
Uint16 CurState; //!< Current state (cursor position)\r
};\r
#include <tpl_drv_common.h>\r
#include <tpl_drv_joystick.h>\r
\r
+static inline int MIN(int a, int b) { return (a < b) ? a : b; }\r
+static inline int MAX(int a, int b) { return (a > b) ? a : b; }\r
+\r
// == CONSTANTS ==\r
+#define NUM_AXIES 2 // X+Y\r
+#define NUM_BUTTONS 5 // Left, Right, Scroll Click, Scroll Up, Scroll Down\r
#define PS2_IO_PORT 0x60\r
-#define MOUSE_BUFFER_SIZE (sizeof(t_mouse_fsdata))\r
-#define MOUSE_SENS_BASE 5\r
\r
// == PROTOTYPES ==\r
// - Internal -\r
int PS2Mouse_Install(char **Arguments);\r
void PS2Mouse_IRQ(int Num);\r
static void mouseSendCommand(Uint8 cmd);\r
-static void enableMouse();\r
+void PS2Mouse_Enable();\r
// - Filesystem -\r
-static Uint64 PS2Mouse_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);\r
-static int PS2Mouse_IOCtl(tVFS_Node *Node, int ID, void *Data);\r
-\r
-typedef struct {\r
- int x, y, buttons, unk;\r
-} t_mouse_fsdata;\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
+// - Settings\r
int giMouse_Sensitivity = 1;\r
-t_mouse_fsdata gMouse_Data = {0, 0, 0, 0};\r
- int giMouse_MaxX = 640, giMouse_MaxY = 480;\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
+// - Internal State\r
int giMouse_Cycle = 0; // IRQ Position\r
Uint8 gaMouse_Bytes[4] = {0,0,0,0};\r
+// - Driver definition\r
tDevFS_Driver gMouse_DriverStruct = {\r
- NULL, "ps2mouse",\r
+ NULL, "PS2Mouse",\r
{\r
.NumACLs = 1, .ACLs = &gVFS_ACL_EveryoneRX,\r
.Read = PS2Mouse_Read, .IOCtl = PS2Mouse_IOCtl\r
};\r
\r
// == CODE ==\r
-int Mouse_Install(char **Arguments)\r
+int PS2Mouse_Install(char **Arguments)\r
{\r
+ // Set up variables\r
+ gMouse_Axies = (void*)&gMouse_FileData[1];\r
+ gMouse_Buttons = (void*)&gMouse_Axies[NUM_AXIES];\r
+ \r
// Initialise Mouse Controller\r
IRQ_AddHandler(12, PS2Mouse_IRQ); // Set IRQ\r
giMouse_Cycle = 0; // Set Current Cycle position\r
- enableMouse(); // Enable the mouse\r
+ PS2Mouse_Enable(); // Enable the mouse\r
\r
DevFS_AddDevice(&gMouse_DriverStruct);\r
\r
void PS2Mouse_IRQ(int Num)\r
{\r
Uint8 flags;\r
- int dx, dy;\r
- //int log2x, log2y;\r
+ int dx, dy;\r
+ int dx_accel, dy_accel;\r
+\r
\r
+ // Gather mouse data\r
gaMouse_Bytes[giMouse_Cycle] = inb(0x60);\r
- if(giMouse_Cycle == 0 && !(gaMouse_Bytes[giMouse_Cycle] & 0x8))\r
- return;\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
- giMouse_Cycle = 0;\r
- else\r
- return;\r
- \r
- if(giMouse_Cycle > 0)\r
- return;\r
- \r
- // Read Flags\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
- if(flags & 0xC0) // X/Y Overflow\r
- return;\r
- \r
- #if DEBUG\r
- //LogF(" PS2Mouse_Irq: flags = 0x%x\n", flags);\r
- #endif\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
- dx = (int) ( gaMouse_Bytes[1] | (flags & 0x10 ? ~0x00FF : 0) );\r
- dy = (int) ( gaMouse_Bytes[2] | (flags & 0x20 ? ~0x00FF : 0) );\r
+ dx = gaMouse_Bytes[1]; if(flags & 0x10) dx = -(256-dx);\r
+ dy = gaMouse_Bytes[2]; if(flags & 0x20) dy = -(256-dy);\r
dy = -dy; // Y is negated\r
LOG("RAW dx=%i, dy=%i\n", dx, dy);\r
- dx = dx*MOUSE_SENS_BASE/giMouse_Sensitivity;\r
- dy = dy*MOUSE_SENS_BASE/giMouse_Sensitivity;\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
+ dx_accel = dx*giMouse_Sensitivity;\r
+ dy_accel = dy*giMouse_Sensitivity;\r
\r
- //__asm__ __volatile__ ("bsr %%eax, %%ecx" : "=c" (log2x) : "a" ((Uint)gaMouse_Bytes[1]));\r
- //__asm__ __volatile__ ("bsr %%eax, %%ecx" : "=c" (log2y) : "a" ((Uint)gaMouse_Bytes[2]));\r
- //LogF(" PS2Mouse_Irq: dx=%i, log2x = %i\n", dx, log2x);\r
- //LogF(" PS2Mouse_Irq: dy=%i, log2y = %i\n", dy, log2y);\r
- //dx *= log2x;\r
- //dy *= log2y;\r
- \r
- // Set Buttons\r
- gMouse_Data.buttons = flags & 0x7; //Buttons (3 only)\r
+ // Set Buttons (Primary)\r
+ gMouse_Buttons[0] = (flags & 1) ? 0xFF : 0;\r
+ gMouse_Buttons[1] = (flags & 2) ? 0xFF : 0;\r
+ gMouse_Buttons[2] = (flags & 4) ? 0xFF : 0;\r
\r
// Update X and Y Positions\r
- gMouse_Data.x += (int)dx;\r
- gMouse_Data.y += (int)dy;\r
- \r
- // Constrain Positions\r
- if(gMouse_Data.x < 0) gMouse_Data.x = 0;\r
- if(gMouse_Data.y < 0) gMouse_Data.y = 0;\r
- if(gMouse_Data.x >= giMouse_MaxX) gMouse_Data.x = giMouse_MaxX-1;\r
- if(gMouse_Data.y >= giMouse_MaxY) gMouse_Data.y = giMouse_MaxY-1; \r
+ gMouse_Axies[0].CurValue = MIN( MAX(gMouse_Axies[0].MinValue, gMouse_Axies[0].CurValue + dx_accel), gMouse_Axies[0].MaxValue );\r
+ gMouse_Axies[1].CurValue = MIN( MAX(gMouse_Axies[1].MinValue, gMouse_Axies[1].CurValue + dy_accel), gMouse_Axies[1].MaxValue );\r
}\r
\r
/* Read mouse state (coordinates)\r
*/\r
-static Uint64 PS2Mouse_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)\r
+Uint64 PS2Mouse_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)\r
{\r
- if(Length < MOUSE_BUFFER_SIZE)\r
- return -1;\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_Data, MOUSE_BUFFER_SIZE);\r
+ memcpy(Buffer, &gMouse_FileData[Offset], Length);\r
\r
- return MOUSE_BUFFER_SIZE;\r
+ return Length;\r
}\r
\r
-static const char *csaIOCtls[] = {DRV_IOCTLNAMES, NULL};\r
+static const char *csaIOCtls[] = {DRV_IOCTLNAMES, DRV_JOY_IOCTLNAMES, NULL};\r
/* Handle messages to the device\r
*/\r
-static int PS2Mouse_IOCtl(tVFS_Node *Node, int ID, void *Data)\r
+int PS2Mouse_IOCtl(tVFS_Node *Node, int ID, void *Data)\r
{\r
- struct {\r
- int Num;\r
- int Value;\r
- } *info = Data;\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
- switch(info->Num)\r
- {\r
- case 0: // X\r
- if(info->Value != -1)\r
- giMouse_MaxX = info->Value;\r
- return giMouse_MaxX;\r
- case 1: // Y\r
- if(info->Value != -1)\r
- giMouse_MaxY = info->Value;\r
- return giMouse_MaxY;\r
- }\r
- return 0;\r
- \r
+ if(info->Num < 0 || info->Num >= 2) return 0;\r
+ if(info->Value != -1)\r
+ gMouse_Axies[info->Num].MaxValue = info->Value;\r
+ return gMouse_Axies[info->Num].MaxValue;\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].CurValue = info->Value;\r
+ return gMouse_Axies[info->Num].CurValue;\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
while( timeout-- && inb(0x64) & 2 ); // Wait for Flag to clear\r
outb(0x60, data); // Send Command\r
}\r
-static inline Uint8 mouseIn60()\r
+static inline Uint8 mouseIn60(void)\r
{\r
int timeout=100000;\r
while( timeout-- && (inb(0x64) & 1) == 0); // Wait for Flag to set\r
return inb(0x60);\r
}\r
-static void mouseSendCommand(Uint8 cmd)\r
+static inline void mouseSendCommand(Uint8 cmd)\r
{\r
mouseOut64(0xD4);\r
mouseOut60(cmd);\r
}\r
\r
-static void enableMouse()\r
+void PS2Mouse_Enable(void)\r
{\r
Uint8 status;\r
- Log_Log("PS2 Mouse", "Enabling Mouse...");\r
+ Log_Log("PS2Mouse", "Enabling Mouse...");\r
\r
// Enable AUX PS/2\r
mouseOut64(0xA8);\r
// Enable AUX PS/2 (Compaq Status Byte)\r
mouseOut64(0x20); // Send Command\r
status = mouseIn60(); // Get Status\r
- status &= 0xDF; status |= 0x02; // Alter Flags (Set IRQ12 (2) and Clear Disable Mouse Clock (20))\r
+ status &= ~0x20; // Clear "Disable Mouse Clock"\r
+ status |= 0x02; // Set IRQ12 Enable\r
mouseOut64(0x60); // Send Command\r
mouseOut60(status); // Set Status\r
\r