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
39 tJoystick_Callback gMouse_Callback;
\r
40 int gMouse_CallbackArg;
\r
41 int giMouse_AxisLimits[2];
\r
43 int giMouse_Cycle = 0; // IRQ Position
\r
44 Uint8 gaMouse_Bytes[4] = {0,0,0,0};
\r
45 // - Driver definition
\r
46 tDevFS_Driver gMouse_DriverStruct = {
\r
49 .NumACLs = 1, .ACLs = &gVFS_ACL_EveryoneRX,
\r
50 .Read = PS2Mouse_Read, .IOCtl = PS2Mouse_IOCtl
\r
55 int PS2Mouse_Install(char **Arguments)
\r
58 gMouse_Axies = (void*)&gMouse_FileData[1];
\r
59 gMouse_Buttons = (void*)&gMouse_Axies[NUM_AXIES];
\r
61 // Initialise Mouse Controller
\r
62 IRQ_AddHandler(12, PS2Mouse_IRQ); // Set IRQ
\r
63 giMouse_Cycle = 0; // Set Current Cycle position
\r
64 PS2Mouse_Enable(); // Enable the mouse
\r
66 DevFS_AddDevice(&gMouse_DriverStruct);
\r
68 return MODULE_ERR_OK;
\r
71 /* Handle Mouse Interrupt
\r
73 void PS2Mouse_IRQ(int Num)
\r
76 int d[2], d_accel[2];
\r
79 // Gather mouse data
\r
80 gaMouse_Bytes[giMouse_Cycle] = inb(0x60);
\r
81 LOG("gaMouse_Bytes[%i] = 0x%02x", gMouse_Axies[0].MaxValue);
\r
82 // - If bit 3 of the first byte is not set, it's not a valid packet?
\r
83 if(giMouse_Cycle == 0 && !(gaMouse_Bytes[0] & 0x08) )
\r
86 if(giMouse_Cycle < 3)
\r
91 // Actual Processing (once we have all bytes)
\r
92 flags = gaMouse_Bytes[0];
\r
94 LOG("flags = 0x%x", flags);
\r
96 // Check for X/Y Overflow
\r
97 if(flags & 0xC0) return;
\r
99 // Calculate dX and dY
\r
100 d[0] = gaMouse_Bytes[1]; if(flags & 0x10) d[0] = -(256-d[0]); // x
\r
101 d[1] = gaMouse_Bytes[2]; if(flags & 0x20) d[1] = -(256-d[1]); // y
\r
102 d[1] = -d[1]; // Y is negated
\r
103 LOG("RAW dx=%i, dy=%i\n", d[0], d[1]);
\r
105 // TODO: Apply a form of curve to the mouse movement (dx*log(dx), dx^k?)
\r
106 // TODO: Independent sensitivities?
\r
107 // TODO: Disable acceleration via a flag?
\r
108 d_accel[0] = d[0]*giMouse_Sensitivity;
\r
109 d_accel[1] = d[1]*giMouse_Sensitivity;
\r
111 // Set Buttons (Primary)
\r
112 for( i = 0; i < 3; i ++ )
\r
114 Uint8 newVal = (flags & (1 << i)) ? 0xFF : 0;
\r
115 if(newVal != gMouse_Buttons[i]) {
\r
116 if( gMouse_Callback )
\r
117 gMouse_Callback(gMouse_CallbackArg, 0, i, newVal - gMouse_Buttons[i]);
\r
118 gMouse_Buttons[i] = newVal;
\r
122 // Update X and Y Positions
\r
123 for( i = 0; i < 2; i ++ )
\r
125 Sint16 newCursor = 0;
\r
126 if( giMouse_AxisLimits[i] )
\r
127 newCursor = MIN( MAX(0, gMouse_Axies[i].CursorPos + d_accel[i]), giMouse_AxisLimits[i] );;
\r
129 if( gMouse_Callback )
\r
131 if(giMouse_AxisLimits[i] && gMouse_Axies[i].CursorPos != newCursor)
\r
132 gMouse_Callback(gMouse_CallbackArg, 1, i, newCursor - gMouse_Axies[i].CursorPos);
\r
133 if(!giMouse_AxisLimits[i] && gMouse_Axies[i].CurValue != d_accel[i])
\r
134 gMouse_Callback(gMouse_CallbackArg, 1, i, d_accel[i] - gMouse_Axies[i].CurValue);
\r
137 gMouse_Axies[i].CurValue = d_accel[i];
\r
138 gMouse_Axies[i].CursorPos = newCursor;
\r
141 // Log_Debug("PS2Mouse", "gMouse_Buttons = {0x%x,0x%x,0x%x}, gMouse_Axies={%i,%i}",
\r
142 // gMouse_Buttons[0], gMouse_Buttons[1], gMouse_Buttons[2],
\r
143 // gMouse_Axies[0].CursorPos, gMouse_Axies[1].CursorPos);
\r
145 VFS_MarkAvaliable(&gMouse_DriverStruct.RootNode, 1);
\r
148 /* Read mouse state (coordinates)
\r
150 Uint64 PS2Mouse_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
\r
152 if(Offset > sizeof(gMouse_FileData)) return 0;
\r
153 if(Length > sizeof(gMouse_FileData)) Length = sizeof(gMouse_FileData);
\r
154 if(Offset + Length > sizeof(gMouse_FileData)) Length = sizeof(gMouse_FileData) - Offset;
\r
156 memcpy(Buffer, &gMouse_FileData[Offset], Length);
\r
158 VFS_MarkAvaliable(Node, 0);
\r
162 static const char *csaIOCtls[] = {DRV_IOCTLNAMES, DRV_JOY_IOCTLNAMES, NULL};
\r
163 /* Handle messages to the device
\r
165 int PS2Mouse_IOCtl(tVFS_Node *Node, int ID, void *Data)
\r
167 tJoystick_NumValue *info = Data;
\r
171 BASE_IOCTLS(DRV_TYPE_JOYSTICK, "PS2Mouse", 0x100, csaIOCtls);
\r
173 case JOY_IOCTL_SETCALLBACK: // TODO: Implement
\r
176 case JOY_IOCTL_SETCALLBACKARG: // TODO: Implement
\r
179 case JOY_IOCTL_GETSETAXISLIMIT:
\r
180 if(!info) return 0;
\r
181 if(info->Num < 0 || info->Num >= 2) return 0;
\r
182 if(info->Value != -1)
\r
183 giMouse_AxisLimits[info->Num] = info->Value;
\r
184 return giMouse_AxisLimits[info->Num];
\r
186 case JOY_IOCTL_GETSETAXISPOSITION:
\r
187 if(!info) return 0;
\r
188 if(info->Num < 0 || info->Num >= 2) return 0;
\r
189 if(info->Value != -1)
\r
190 gMouse_Axies[info->Num].CursorPos = info->Value;
\r
191 return gMouse_Axies[info->Num].CursorPos;
\r
193 case JOY_IOCTL_GETSETAXISFLAGS:
\r
196 case JOY_IOCTL_GETSETBUTTONFLAGS:
\r
204 //== Internal Functions ==
\r
205 static inline void mouseOut64(Uint8 data)
\r
207 int timeout=100000;
\r
208 while( timeout-- && inb(0x64) & 2 ); // Wait for Flag to clear
\r
209 outb(0x64, data); // Send Command
\r
211 static inline void mouseOut60(Uint8 data)
\r
213 int timeout=100000;
\r
214 while( timeout-- && inb(0x64) & 2 ); // Wait for Flag to clear
\r
215 outb(0x60, data); // Send Command
\r
217 static inline Uint8 mouseIn60(void)
\r
219 int timeout=100000;
\r
220 while( timeout-- && (inb(0x64) & 1) == 0); // Wait for Flag to set
\r
223 static inline void mouseSendCommand(Uint8 cmd)
\r
229 void PS2Mouse_Enable(void)
\r
232 Log_Log("PS2Mouse", "Enabling Mouse...");
\r
237 // Enable AUX PS/2 (Compaq Status Byte)
\r
238 mouseOut64(0x20); // Send Command
\r
239 status = mouseIn60(); // Get Status
\r
240 status &= ~0x20; // Clear "Disable Mouse Clock"
\r
241 status |= 0x02; // Set IRQ12 Enable
\r
242 mouseOut64(0x60); // Send Command
\r
243 mouseOut60(status); // Set Status
\r
245 //mouseSendCommand(0xF6); // Set Default Settings
\r
246 mouseSendCommand(0xF4); // Enable Packets
\r