2 * Acess2 Mouse Driver
\r
8 #include <fs_devfs.h>
\r
9 #include <tpl_drv_common.h>
\r
10 #include <tpl_drv_joystick.h>
\r
12 static inline int MIN(int a, int b) { return (a < b) ? a : b; }
\r
13 static inline int MAX(int a, int b) { return (a > b) ? a : b; }
\r
16 #define NUM_AXIES 2 // X+Y
\r
17 #define NUM_BUTTONS 5 // Left, Right, Scroll Click, Scroll Up, Scroll Down
\r
18 #define PS2_IO_PORT 0x60
\r
22 int PS2Mouse_Install(char **Arguments);
\r
23 void PS2Mouse_IRQ(int Num);
\r
24 static void mouseSendCommand(Uint8 cmd);
\r
25 void PS2Mouse_Enable();
\r
27 Uint64 PS2Mouse_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
\r
28 int PS2Mouse_IOCtl(tVFS_Node *Node, int ID, void *Data);
\r
32 int giMouse_Sensitivity = 1;
\r
33 int giMouse_MaxX = 640, giMouse_MaxY = 480;
\r
35 Uint8 gMouse_FileData[sizeof(tJoystick_FileHeader) + NUM_AXIES*sizeof(tJoystick_Axis) + NUM_BUTTONS];
\r
36 tJoystick_FileHeader *gMouse_FileHeader = (void *)gMouse_FileData;
\r
37 tJoystick_Axis *gMouse_Axies;
\r
38 Uint8 *gMouse_Buttons;
\r
40 int giMouse_Cycle = 0; // IRQ Position
\r
41 Uint8 gaMouse_Bytes[4] = {0,0,0,0};
\r
42 // - Driver definition
\r
43 tDevFS_Driver gMouse_DriverStruct = {
\r
46 .NumACLs = 1, .ACLs = &gVFS_ACL_EveryoneRX,
\r
47 .Read = PS2Mouse_Read, .IOCtl = PS2Mouse_IOCtl
\r
52 int PS2Mouse_Install(char **Arguments)
\r
55 gMouse_Axies = (void*)&gMouse_FileData[1];
\r
56 gMouse_Buttons = (void*)&gMouse_Axies[NUM_AXIES];
\r
58 // Initialise Mouse Controller
\r
59 IRQ_AddHandler(12, PS2Mouse_IRQ); // Set IRQ
\r
60 giMouse_Cycle = 0; // Set Current Cycle position
\r
61 PS2Mouse_Enable(); // Enable the mouse
\r
63 DevFS_AddDevice(&gMouse_DriverStruct);
\r
65 return MODULE_ERR_OK;
\r
68 /* Handle Mouse Interrupt
\r
70 void PS2Mouse_IRQ(int Num)
\r
74 int dx_accel, dy_accel;
\r
77 // Gather mouse data
\r
78 gaMouse_Bytes[giMouse_Cycle] = inb(0x60);
\r
79 LOG("gaMouse_Bytes[%i] = 0x%02x", gMouse_Axies[0].MaxValue);
\r
80 // - If bit 3 of the first byte is not set, it's not a valid packet?
\r
81 if(giMouse_Cycle == 0 && !(gaMouse_Bytes[0] & 0x08) )
\r
84 if(giMouse_Cycle < 3)
\r
89 // Actual Processing (once we have all bytes)
\r
90 flags = gaMouse_Bytes[0];
\r
92 LOG("flags = 0x%x", flags);
\r
94 // Check for X/Y Overflow
\r
95 if(flags & 0xC0) return;
\r
97 // Calculate dX and dY
\r
98 dx = gaMouse_Bytes[1]; if(flags & 0x10) dx = -(256-dx);
\r
99 dy = gaMouse_Bytes[2]; if(flags & 0x20) dy = -(256-dy);
\r
100 dy = -dy; // Y is negated
\r
101 LOG("RAW dx=%i, dy=%i\n", dx, dy);
\r
103 // TODO: Apply a form of curve to the mouse movement (dx*log(dx), dx^k?)
\r
104 // TODO: Independent sensitivities?
\r
105 // TODO: Disable acceleration via a flag?
\r
106 dx_accel = dx*giMouse_Sensitivity;
\r
107 dy_accel = dy*giMouse_Sensitivity;
\r
109 // Set Buttons (Primary)
\r
110 gMouse_Buttons[0] = (flags & 1) ? 0xFF : 0;
\r
111 gMouse_Buttons[1] = (flags & 2) ? 0xFF : 0;
\r
112 gMouse_Buttons[2] = (flags & 4) ? 0xFF : 0;
\r
114 // Update X and Y Positions
\r
115 gMouse_Axies[0].CurValue = MIN( MAX(gMouse_Axies[0].MinValue, gMouse_Axies[0].CurValue + dx_accel), gMouse_Axies[0].MaxValue );
\r
116 gMouse_Axies[1].CurValue = MIN( MAX(gMouse_Axies[1].MinValue, gMouse_Axies[1].CurValue + dy_accel), gMouse_Axies[1].MaxValue );
\r
119 /* Read mouse state (coordinates)
\r
121 Uint64 PS2Mouse_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
\r
123 if(Offset > sizeof(gMouse_FileData)) return 0;
\r
124 if(Length > sizeof(gMouse_FileData)) Length = sizeof(gMouse_FileData);
\r
125 if(Offset + Length > sizeof(gMouse_FileData)) Length = sizeof(gMouse_FileData) - Offset;
\r
127 memcpy(Buffer, &gMouse_FileData[Offset], Length);
\r
132 static const char *csaIOCtls[] = {DRV_IOCTLNAMES, DRV_JOY_IOCTLNAMES, NULL};
\r
133 /* Handle messages to the device
\r
135 int PS2Mouse_IOCtl(tVFS_Node *Node, int ID, void *Data)
\r
137 tJoystick_NumValue *info = Data;
\r
141 BASE_IOCTLS(DRV_TYPE_JOYSTICK, "PS2Mouse", 0x100, csaIOCtls);
\r
143 case JOY_IOCTL_SETCALLBACK: // TODO: Implement
\r
146 case JOY_IOCTL_SETCALLBACKARG: // TODO: Implement
\r
149 case JOY_IOCTL_GETSETAXISLIMIT:
\r
150 if(!info) return 0;
\r
151 if(info->Num < 0 || info->Num >= 2) return 0;
\r
152 if(info->Value != -1)
\r
153 gMouse_Axies[info->Num].MaxValue = info->Value;
\r
154 return gMouse_Axies[info->Num].MaxValue;
\r
156 case JOY_IOCTL_GETSETAXISPOSITION:
\r
157 if(!info) return 0;
\r
158 if(info->Num < 0 || info->Num >= 2) return 0;
\r
159 if(info->Value != -1)
\r
160 gMouse_Axies[info->Num].CurValue = info->Value;
\r
161 return gMouse_Axies[info->Num].CurValue;
\r
163 case JOY_IOCTL_GETSETAXISFLAGS:
\r
166 case JOY_IOCTL_GETSETBUTTONFLAGS:
\r
174 //== Internal Functions ==
\r
175 static inline void mouseOut64(Uint8 data)
\r
177 int timeout=100000;
\r
178 while( timeout-- && inb(0x64) & 2 ); // Wait for Flag to clear
\r
179 outb(0x64, data); // Send Command
\r
181 static inline void mouseOut60(Uint8 data)
\r
183 int timeout=100000;
\r
184 while( timeout-- && inb(0x64) & 2 ); // Wait for Flag to clear
\r
185 outb(0x60, data); // Send Command
\r
187 static inline Uint8 mouseIn60(void)
\r
189 int timeout=100000;
\r
190 while( timeout-- && (inb(0x64) & 1) == 0); // Wait for Flag to set
\r
193 static inline void mouseSendCommand(Uint8 cmd)
\r
199 void PS2Mouse_Enable(void)
\r
202 Log_Log("PS2Mouse", "Enabling Mouse...");
\r
207 // Enable AUX PS/2 (Compaq Status Byte)
\r
208 mouseOut64(0x20); // Send Command
\r
209 status = mouseIn60(); // Get Status
\r
210 status &= ~0x20; // Clear "Disable Mouse Clock"
\r
211 status |= 0x02; // Set IRQ12 Enable
\r
212 mouseOut64(0x60); // Send Command
\r
213 mouseOut60(status); // Set Status
\r
215 //mouseSendCommand(0xF6); // Set Default Settings
\r
216 mouseSendCommand(0xF4); // Enable Packets
\r