f67c8b15a5e70b86dd09c7a752a095c527662cde
[tpg/acess2.git] / Modules / Input / PS2KbMouse / ps2mouse.c
1 /*\r
2  * Acess2 Mouse Driver\r
3  */\r
4 #define DEBUG   0\r
5 #include <acess.h>\r
6 #include <modules.h>\r
7 #include <vfs.h>\r
8 #include <fs_devfs.h>\r
9 #include <tpl_drv_common.h>\r
10 #include <tpl_drv_joystick.h>\r
11 \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
14 \r
15 // == CONSTANTS ==\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
19 \r
20 // == PROTOTYPES ==\r
21 // - Internal -\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
26 // - Filesystem -\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
29 \r
30 // == GLOBALS ==\r
31 // - Settings\r
32  int    giMouse_Sensitivity = 1;\r
33  int    giMouse_MaxX = 640, giMouse_MaxY = 480;\r
34 // - File Data\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
42 // - Internal State\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
47         NULL, "PS2Mouse",\r
48         {\r
49         .NumACLs = 1, .ACLs = &gVFS_ACL_EveryoneRX,\r
50         .Read = PS2Mouse_Read, .IOCtl = PS2Mouse_IOCtl\r
51         }\r
52 };\r
53 \r
54 // == CODE ==\r
55 int PS2Mouse_Install(char **Arguments)\r
56 {\r
57         // Set up variables\r
58         gMouse_Axies = (void*)&gMouse_FileData[1];\r
59         gMouse_Buttons = (void*)&gMouse_Axies[NUM_AXIES];\r
60         \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
65         \r
66         DevFS_AddDevice(&gMouse_DriverStruct);\r
67         \r
68         return MODULE_ERR_OK;\r
69 }\r
70 \r
71 /* Handle Mouse Interrupt\r
72  */\r
73 void PS2Mouse_IRQ(int Num)\r
74 {\r
75         Uint8   flags;\r
76          int    d[2], d_accel[2];\r
77          int    i;\r
78         \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
84                 return ;\r
85         giMouse_Cycle++;\r
86         if(giMouse_Cycle < 3)\r
87                 return ;\r
88 \r
89         giMouse_Cycle = 0;\r
90 \r
91         // Actual Processing (once we have all bytes)   \r
92         flags = gaMouse_Bytes[0];\r
93 \r
94         LOG("flags = 0x%x", flags);\r
95         \r
96         // Check for X/Y Overflow\r
97         if(flags & 0xC0)        return;\r
98                 \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
104         // Apply scaling\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
110         \r
111         // Set Buttons (Primary)\r
112         for( i = 0; i < 3; i ++ )\r
113         {\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
119                 }\r
120         }\r
121         \r
122         // Update X and Y Positions\r
123         for( i = 0; i < 2; i ++ )\r
124         {\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
128                 \r
129                 if( gMouse_Callback )\r
130                 {\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
135                 }\r
136                 \r
137                 gMouse_Axies[i].CurValue = d_accel[i];\r
138                 gMouse_Axies[i].CursorPos = newCursor;\r
139         }\r
140         \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
144         \r
145         VFS_MarkAvaliable(&gMouse_DriverStruct.RootNode, 1);\r
146 }\r
147 \r
148 /* Read mouse state (coordinates)\r
149  */\r
150 Uint64 PS2Mouse_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)\r
151 {\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
155 \r
156         memcpy(Buffer, &gMouse_FileData[Offset], Length);\r
157         \r
158         VFS_MarkAvaliable(Node, 0);\r
159         return Length;\r
160 }\r
161 \r
162 static const char *csaIOCtls[] = {DRV_IOCTLNAMES, DRV_JOY_IOCTLNAMES, NULL};\r
163 /* Handle messages to the device\r
164  */\r
165 int PS2Mouse_IOCtl(tVFS_Node *Node, int ID, void *Data)\r
166 {\r
167         tJoystick_NumValue      *info = Data;\r
168 \r
169         switch(ID)\r
170         {\r
171         BASE_IOCTLS(DRV_TYPE_JOYSTICK, "PS2Mouse", 0x100, csaIOCtls);\r
172 \r
173         case JOY_IOCTL_SETCALLBACK:     // TODO: Implement\r
174                 return -1;\r
175         \r
176         case JOY_IOCTL_SETCALLBACKARG:  // TODO: Implement\r
177                 return -1;\r
178         \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
185         \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
192 \r
193         case JOY_IOCTL_GETSETAXISFLAGS:\r
194                 return -1;\r
195         \r
196         case JOY_IOCTL_GETSETBUTTONFLAGS:\r
197                 return -1;\r
198 \r
199         default:\r
200                 return 0;\r
201         }\r
202 }\r
203 \r
204 //== Internal Functions ==\r
205 static inline void mouseOut64(Uint8 data)\r
206 {\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
210 }\r
211 static inline void mouseOut60(Uint8 data)\r
212 {\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
216 }\r
217 static inline Uint8 mouseIn60(void)\r
218 {\r
219         int timeout=100000;\r
220         while( timeout-- && (inb(0x64) & 1) == 0);      // Wait for Flag to set\r
221         return inb(0x60);\r
222 }\r
223 static inline void mouseSendCommand(Uint8 cmd)\r
224 {\r
225         mouseOut64(0xD4);\r
226         mouseOut60(cmd);\r
227 }\r
228 \r
229 void PS2Mouse_Enable(void)\r
230 {\r
231         Uint8   status;\r
232         Log_Log("PS2Mouse", "Enabling Mouse...");\r
233         \r
234         // Enable AUX PS/2\r
235         mouseOut64(0xA8);\r
236         \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
244         \r
245         //mouseSendCommand(0xF6);       // Set Default Settings\r
246         mouseSendCommand(0xF4); // Enable Packets\r
247 }\r

UCC git Repository :: git.ucc.asn.au