2 * Acess2 Mouse Driver
\r
8 #include <fs_devfs.h>
\r
9 #include <api_drv_common.h>
\r
10 #include <api_drv_joystick.h>
\r
14 #define NUM_AXIES 2 // X+Y
\r
15 #define NUM_BUTTONS 5 // Left, Right, Scroll Click, Scroll Up, Scroll Down
\r
19 int PS2Mouse_Install(char **Arguments);
\r
20 void PS2Mouse_HandleInterrupt(Uint8 InputByte);
\r
22 Uint64 PS2Mouse_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
\r
23 int PS2Mouse_IOCtl(tVFS_Node *Node, int ID, void *Data);
\r
26 void (*gpMouse_EnableFcn)(void);
\r
28 int giMouse_Sensitivity = 1;
\r
29 int giMouse_MaxX = 640, giMouse_MaxY = 480;
\r
31 Uint8 gMouse_FileData[sizeof(tJoystick_FileHeader) + NUM_AXIES*sizeof(tJoystick_Axis) + NUM_BUTTONS];
\r
32 tJoystick_FileHeader *gMouse_FileHeader = (void *)gMouse_FileData;
\r
33 tJoystick_Axis *gMouse_Axies;
\r
34 Uint8 *gMouse_Buttons;
\r
35 tJoystick_Callback gMouse_Callback;
\r
36 int gMouse_CallbackArg;
\r
37 int giMouse_AxisLimits[2];
\r
39 int giMouse_Cycle = 0; // IRQ Position
\r
40 Uint8 gaMouse_Bytes[4] = {0,0,0,0};
\r
41 // - Driver definition
\r
42 tVFS_NodeType gMouse_NodeType = {
\r
43 .Read = PS2Mouse_Read,
\r
44 .IOCtl = PS2Mouse_IOCtl
\r
46 tDevFS_Driver gMouse_DriverStruct = {
\r
49 .NumACLs = 1, .ACLs = &gVFS_ACL_EveryoneRX,
\r
50 .Type = &gMouse_NodeType
\r
55 int PS2Mouse_Install(char **Arguments)
\r
60 gMouse_Axies = (void*)&gMouse_FileData[4];
\r
61 gMouse_Buttons = (void*)&gMouse_Axies[NUM_AXIES];
\r
63 gMouse_FileHeader->NAxies = 2; gMouse_FileHeader->NButtons = 3;
\r
64 gMouse_Axies[0].MinValue = -10; gMouse_Axies[0].MaxValue = 10;
\r
65 gMouse_Axies[1].MinValue = -10; gMouse_Axies[1].MaxValue = 10;
\r
67 // Initialise Mouse Controller
\r
68 giMouse_Cycle = 0; // Set Current Cycle position
\r
69 gpMouse_EnableFcn();
\r
71 DevFS_AddDevice(&gMouse_DriverStruct);
\r
73 return MODULE_ERR_OK;
\r
76 /* Handle Mouse Interrupt
\r
78 void PS2Mouse_HandleInterrupt(Uint8 InputByte)
\r
81 int d[2], d_accel[2];
\r
84 // Gather mouse data
\r
85 gaMouse_Bytes[giMouse_Cycle] = InputByte;
\r
86 LOG("gaMouse_Bytes[%i] = 0x%02x", gMouse_Axies[0].MaxValue);
\r
87 // - If bit 3 of the first byte is not set, it's not a valid packet?
\r
88 if(giMouse_Cycle == 0 && !(gaMouse_Bytes[0] & 0x08) )
\r
91 if(giMouse_Cycle < 3)
\r
96 // Actual Processing (once we have all bytes)
\r
97 flags = gaMouse_Bytes[0];
\r
99 LOG("flags = 0x%x", flags);
\r
101 // Check for X/Y Overflow
\r
102 if(flags & 0xC0) return;
\r
104 // Calculate dX and dY
\r
105 d[0] = gaMouse_Bytes[1]; if(flags & 0x10) d[0] = -(256-d[0]); // x
\r
106 d[1] = gaMouse_Bytes[2]; if(flags & 0x20) d[1] = -(256-d[1]); // y
\r
107 d[1] = -d[1]; // Y is negated
\r
108 LOG("RAW dx=%i, dy=%i\n", d[0], d[1]);
\r
110 // TODO: Apply a form of curve to the mouse movement (dx*log(dx), dx^k?)
\r
111 // TODO: Independent sensitivities?
\r
112 // TODO: Disable acceleration via a flag?
\r
113 d_accel[0] = d[0]*giMouse_Sensitivity;
\r
114 d_accel[1] = d[1]*giMouse_Sensitivity;
\r
116 // Set Buttons (Primary)
\r
117 for( i = 0; i < 3; i ++ )
\r
119 Uint8 newVal = (flags & (1 << i)) ? 0xFF : 0;
\r
120 if(newVal != gMouse_Buttons[i]) {
\r
121 if( gMouse_Callback )
\r
122 gMouse_Callback(gMouse_CallbackArg, 0, i, newVal - gMouse_Buttons[i]);
\r
123 gMouse_Buttons[i] = newVal;
\r
127 // Update X and Y Positions
\r
128 for( i = 0; i < 2; i ++ )
\r
130 Sint16 newCursor = 0;
\r
131 if( giMouse_AxisLimits[i] )
\r
132 newCursor = MIN( MAX(0, gMouse_Axies[i].CursorPos + d_accel[i]), giMouse_AxisLimits[i] );;
\r
134 if( gMouse_Callback )
\r
136 if(giMouse_AxisLimits[i] && gMouse_Axies[i].CursorPos != newCursor)
\r
137 gMouse_Callback(gMouse_CallbackArg, 1, i, newCursor - gMouse_Axies[i].CursorPos);
\r
138 if(!giMouse_AxisLimits[i] && gMouse_Axies[i].CurValue != d_accel[i])
\r
139 gMouse_Callback(gMouse_CallbackArg, 1, i, d_accel[i] - gMouse_Axies[i].CurValue);
\r
142 gMouse_Axies[i].CurValue = d_accel[i];
\r
143 gMouse_Axies[i].CursorPos = newCursor;
\r
146 // Log("Mouse at %ix%i", gMouse_Axies[0].CursorPos, gMouse_Axies[1].CursorPos);
\r
148 VFS_MarkAvaliable(&gMouse_DriverStruct.RootNode, 1);
\r
151 /* Read mouse state (coordinates)
\r
153 Uint64 PS2Mouse_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
\r
155 if(Offset > sizeof(gMouse_FileData)) return 0;
\r
156 if(Length > sizeof(gMouse_FileData)) Length = sizeof(gMouse_FileData);
\r
157 if(Offset + Length > sizeof(gMouse_FileData)) Length = sizeof(gMouse_FileData) - Offset;
\r
159 memcpy(Buffer, &gMouse_FileData[Offset], Length);
\r
161 VFS_MarkAvaliable(Node, 0);
\r
165 static const char *csaIOCtls[] = {DRV_IOCTLNAMES, DRV_JOY_IOCTLNAMES, NULL};
\r
166 /* Handle messages to the device
\r
168 int PS2Mouse_IOCtl(tVFS_Node *Node, int ID, void *Data)
\r
170 tJoystick_NumValue *info = Data;
\r
174 BASE_IOCTLS(DRV_TYPE_JOYSTICK, "PS2Mouse", 0x100, csaIOCtls);
\r
176 case JOY_IOCTL_SETCALLBACK: // TODO: Implement
\r
179 case JOY_IOCTL_SETCALLBACKARG: // TODO: Implement
\r
182 case JOY_IOCTL_GETSETAXISLIMIT:
\r
183 if(!info) return 0;
\r
184 if(info->Num < 0 || info->Num >= 2) return 0;
\r
185 if(info->Value != -1)
\r
186 giMouse_AxisLimits[info->Num] = info->Value;
\r
187 return giMouse_AxisLimits[info->Num];
\r
189 case JOY_IOCTL_GETSETAXISPOSITION:
\r
190 if(!info) return 0;
\r
191 if(info->Num < 0 || info->Num >= 2) return 0;
\r
192 if(info->Value != -1)
\r
193 gMouse_Axies[info->Num].CursorPos = info->Value;
\r
194 return gMouse_Axies[info->Num].CursorPos;
\r
196 case JOY_IOCTL_GETSETAXISFLAGS:
\r
199 case JOY_IOCTL_GETSETBUTTONFLAGS:
\r