Modules/USB - Crash prevention in UHCI, VFS interface for HIDMouse
[tpg/acess2.git] / KernelLand / Modules / USB / HID / mouse.c
1 /*
2  * Acess2 USB Stack HID Driver
3  * - By John Hodge (thePowersGang)
4  *
5  * mouse.c
6  * - USB Mouse driver
7  */
8 #define DEBUG   1
9 #include <acess.h>
10 #include "hid_reports.h"
11 #include <fs_devfs.h>
12 #include <api_drv_joystick.h>
13
14 // === CONSTANTS ===
15 #define MAX_AXIES       3       // X, Y, Scroll
16 #define MAX_BUTTONS     5       // Left, Right, Middle, ...
17 #define FILE_SIZE       (sizeof(tJoystick_FileHeader) + MAX_AXIES*sizeof(tJoystick_Axis) + MAX_BUTTONS)
18
19 // === TYPES ===
20 typedef struct sHID_Mouse       tHID_Mouse;
21
22 struct sHID_Mouse
23 {
24         tHID_Mouse      *Next;
25         tUSB_DataCallback       DataAvail;
26
27         tVFS_Node       Node;
28          int    CollectionDepth;
29         
30         Uint8   FileData[ FILE_SIZE ];
31         tJoystick_FileHeader    *FileHeader;
32         tJoystick_Axis  *Axies;
33         Uint8   *Buttons;
34
35         Uint16  AxisLimits[MAX_AXIES];
36         
37          int    nMappings;
38         struct {
39                 Uint8   Dest;   // 0x00-0x7F = Buttons, 0x80-0xFE = Axies, 0xFF = Ignore
40                 Uint8   BitSize;
41         } *Mappings;
42 };
43
44 // === PROTOTYES ===
45 char    *HID_Mouse_Root_ReadDir(tVFS_Node *Node, int Pos);
46 tVFS_Node       *HID_Mouse_Root_FindDir(tVFS_Node *Node, const char *Name);
47 Uint64  HID_Mouse_Dev_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
48  int    HID_Mouse_Dev_IOCtl(tVFS_Node *Node, int ID, void *Data);
49 void    HID_Mouse_Dev_Reference(tVFS_Node *Node);
50 void    HID_Mouse_Dev_Close(tVFS_Node *Node);
51
52 void    HID_Mouse_DataAvail(tUSBInterface *Dev, int EndPt, int Length, void *Data);
53
54 tHID_ReportCallbacks    *HID_Mouse_Report_Collection(tUSBInterface *Dev, tHID_ReportGlobalState *Global, tHID_ReportLocalState *Local, Uint32 Value);
55 void    HID_Mouse_Report_EndCollection(tUSBInterface *Dev);
56 void    HID_Mouse_Report_Input(tUSBInterface *Dev, tHID_ReportGlobalState *Global, tHID_ReportLocalState *Local, Uint32 Value);
57
58 // === GLOBALS ===
59 tVFS_NodeType   gHID_Mouse_RootNodeType = {
60         .TypeName = "HID Mouse Root",
61         .ReadDir = HID_Mouse_Root_ReadDir,
62         .FindDir = HID_Mouse_Root_FindDir
63 };
64 tVFS_NodeType   gHID_Mouse_DevNodeType = {
65         .TypeName = "HID Mouse Dev",
66         .Read = HID_Mouse_Dev_Read,
67         .IOCtl = HID_Mouse_Dev_IOCtl,
68         .Reference = HID_Mouse_Dev_Reference,
69         .Close = HID_Mouse_Dev_Close,
70 };
71 tDevFS_Driver   gHID_Mouse_DevFS = {
72         .Name = "USBMouse",
73         .RootNode = {.Type = &gHID_Mouse_RootNodeType}
74 };
75 tHID_ReportCallbacks    gHID_Mouse_ReportCBs = {
76         .Collection = HID_Mouse_Report_Collection,
77         .EndCollection = HID_Mouse_Report_EndCollection,
78         .Input = HID_Mouse_Report_Input,
79 };
80 tMutex  glHID_MouseListLock;
81 tHID_Mouse      *gpHID_FirstMouse;
82 tHID_Mouse      *gpHID_LastMouse = (tHID_Mouse*)&gpHID_FirstMouse;
83
84 // === CODE ===
85 // ----------------------------------------------------------------------------
86 // VFS Interface
87 // ----------------------------------------------------------------------------
88 char *HID_Mouse_Root_ReadDir(tVFS_Node *Node, int Pos)
89 {
90         char    data[3];
91         if(Pos < 0 || Pos >= Node->Size)        return NULL;
92         
93         snprintf(data, 3, "%i", Pos);
94         return strdup(data);
95 }
96
97 tVFS_Node *HID_Mouse_Root_FindDir(tVFS_Node *Node, const char *Name)
98 {
99          int    ID;
100          int    ofs;
101         tHID_Mouse      *mouse;
102         
103         if( Name[0] == '\0' )
104                 return NULL;
105         
106         ofs = ParseInt(Name, &ID);
107         if( ofs == 0 || Name[ofs] != '\0' )
108                 return NULL;
109         
110         // Scan list, locate item
111         Mutex_Acquire(&glHID_MouseListLock);
112         for( mouse = gpHID_FirstMouse; mouse && ID --; mouse = mouse->Next ) ;
113         mouse->Node.ReferenceCount ++;  
114         Mutex_Release(&glHID_MouseListLock);
115
116         return &mouse->Node;
117 }
118
119 Uint64 HID_Mouse_Dev_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
120 {
121         tHID_Mouse      *info = Node->ImplPtr;
122         
123         if( Offset > FILE_SIZE )        return 0;
124         
125         if( Length > FILE_SIZE )        Length = FILE_SIZE;
126         if( Offset + Length > FILE_SIZE )       Length = FILE_SIZE - Offset;
127
128         memcpy( Buffer, info->FileData + Offset, Length );
129
130         return Length;
131 }
132
133 static const char *csaDevIOCtls[] = {DRV_IOCTLNAMES, DRV_JOY_IOCTLNAMES, NULL};
134 int HID_Mouse_Dev_IOCtl(tVFS_Node *Node, int ID, void *Data)
135 {
136         switch(ID)
137         {
138         BASE_IOCTLS(DRV_TYPE_JOYSTICK, "USBMouse", 0x050, csaDevIOCtls);
139         }
140         return -1;
141 }
142 void HID_Mouse_Dev_Reference(tVFS_Node *Node)
143 {
144         Node->ReferenceCount ++;
145 }
146 void HID_Mouse_Dev_Close(tVFS_Node *Node)
147 {
148         Node->ReferenceCount --;
149 }
150
151 // ----------------------------------------------------------------------------
152 // Data input / Update
153 // ----------------------------------------------------------------------------
154 Sint32 _ReadBits(void *Data, int Offset, int Length)
155 {
156          int    dest_ofs = 0;
157         Uint32  rv = 0;
158         Uint8   *bytes = (Uint8*)Data + Offset / 8;
159         
160         // Leading byte
161         if( Offset & 7 )
162         {
163                 if( Length < 8 - (Offset & 7) )
164                 {
165                         rv = (*bytes >> Offset) & ((1 << Length)-1);
166                         goto _ext;
167                 }
168                 
169                 rv = (*bytes >> Offset);
170                 
171                 dest_ofs = Offset & 7;
172                 Length -= Offset & 7;
173                 bytes ++;
174         }
175
176         // Body bytes
177         while( Length >= 8 )
178         {
179                 rv |= *bytes << dest_ofs;
180                 dest_ofs += 8;
181                 Length -= 8;
182                 bytes ++;
183         }
184         
185         if( Length )
186         {
187                 rv |= (*bytes & ((1 << Length)-1)) << dest_ofs;
188                 
189         }
190         
191         // Do sign extension
192 _ext:
193         if( rv & (1 << (Length-1)) )
194                 rv |= 0xFFFFFFFF << Length;
195         return rv;
196 }
197
198 void HID_Mouse_DataAvail(tUSBInterface *Dev, int EndPt, int Length, void *Data)
199 {
200         tHID_Mouse      *info;
201          int    ofs;
202         
203         info = USB_GetDeviceDataPtr(Dev);
204         if( !info )     return ;
205
206         Log_Debug("USBMouse", "info = %p", info);       
207         
208         ofs = 0;
209         for( int i = 0; i < info->nMappings; i ++ )
210         {
211                 Sint32  value;
212                 Uint8   dest = info->Mappings[i].Dest;
213
214                 if( ofs + info->Mappings[i].BitSize > Length * 8 )
215                         return ;
216
217                 value = _ReadBits(Data, ofs, info->Mappings[i].BitSize);
218                 ofs += info->Mappings[i].BitSize;
219                 
220                 if( dest == 0xFF )      continue ;
221                 
222                 if( dest & 0x80 )
223                 {
224                         // Axis
225                         info->Axies[ dest & 0x7F ].CurValue = value;
226                 }
227                 else
228                 {
229                         // Button
230                         info->Buttons[ dest & 0x7F ] = (value == 0) ? 0 : 0xFF;
231                 }
232         }
233         
234         // Update axis positions
235         for( int i = 0; i < MAX_AXIES; i ++ )
236         {
237                  int    newpos;
238                 
239                 // TODO: Scaling
240                 newpos = info->Axies[i].CursorPos + info->Axies[i].CurValue;
241                 
242                 if(newpos < 0)  newpos = 0;
243                 if(newpos > info->AxisLimits[i])        newpos = info->AxisLimits[i];
244                 
245                 info->Axies[i].CursorPos = newpos;
246         }
247         Log_Debug("USBMouse", "New Pos (%i,%i,%i)",
248                 info->Axies[0].CursorPos, info->Axies[1].CursorPos, info->Axies[2].CursorPos
249                 );
250 }
251
252 // ----------------------------------------------------------------------------
253 // Device initialisation
254 // ----------------------------------------------------------------------------
255 /**
256  */
257 tHID_ReportCallbacks *HID_Mouse_Report_Collection(
258         tUSBInterface *Dev,
259         tHID_ReportGlobalState *Global, tHID_ReportLocalState *Local,
260         Uint32 Value
261         )
262 {
263         tHID_Mouse      *info;
264
265         info = USB_GetDeviceDataPtr(Dev);
266         if( !info )
267         {
268                 // New device!
269                 info = calloc( sizeof(tHID_Mouse), 1 );
270                 info->DataAvail = HID_Mouse_DataAvail;
271                 info->Node.ImplPtr = info;
272                 info->Node.Type = &gHID_Mouse_DevNodeType;
273                 
274                 info->FileHeader = (void*)info->FileData;
275                 info->Axies = (void*)(info->FileHeader + 1);
276                 info->Buttons = (void*)(info->Axies + MAX_AXIES);
277         
278                 LOG("Initialised new mouse at %p", info);
279                 
280                 USB_SetDeviceDataPtr(Dev, info);
281         }
282         else
283         {
284                 info->CollectionDepth ++;
285         }
286         
287         return &gHID_Mouse_ReportCBs;
288 }
289
290 void HID_Mouse_Report_EndCollection(tUSBInterface *Dev)
291 {
292         tHID_Mouse      *info;
293
294         info = USB_GetDeviceDataPtr(Dev);       
295         if(!info) {
296                 Log_Error("HID", "HID is not initialised when _AddInput is called");
297                 return ;
298         }
299
300         if( info->CollectionDepth == 0 )
301         {
302                 // Perform final initialisation steps
303                 Mutex_Acquire(&glHID_MouseListLock);
304                 gpHID_LastMouse->Next = info;
305                 gpHID_LastMouse = info;
306                 gHID_Mouse_DevFS.RootNode.Size ++;
307                 Mutex_Release(&glHID_MouseListLock);
308         }
309         else
310         {
311                 info->CollectionDepth --;
312         }
313 }
314
315 void HID_int_AddInput(tUSBInterface *Dev, Uint32 Usage, Uint8 Size, Uint32 Min, Uint32 Max)
316 {
317         Uint8   tag;
318         tHID_Mouse      *info;
319
320         info = USB_GetDeviceDataPtr(Dev);
321         if(!info) {
322                 Log_Error("HID", "HID is not initialised when _AddInput is called");
323                 return ;
324         }
325
326         switch(Usage)
327         {
328         case 0x00010030:        tag = 0x80;     break;  // Generic Desktop - X
329         case 0x00010031:        tag = 0x81;     break;  // Generic Desktop - Y
330         case 0x00010038:        tag = 0x82;     break;  // Generic Desktop - Wheel
331         case 0x00090001:        tag = 0x00;     break;  // Button 1
332         case 0x00090002:        tag = 0x01;     break;  // Button 2
333         case 0x00090003:        tag = 0x02;     break;  // Button 3
334         case 0x00090004:        tag = 0x03;     break;  // Button 4
335         case 0x00090005:        tag = 0x04;     break;  // Button 5
336         default:        tag = 0xFF;     break;
337         }
338         
339         info->nMappings ++;
340         info->Mappings = realloc(info->Mappings, info->nMappings * sizeof(info->Mappings[0]));
341         // TODO: NULL check
342         
343         info->Mappings[ info->nMappings - 1].Dest = tag;
344         info->Mappings[ info->nMappings - 1].BitSize = Size;
345         
346         if( tag != 0xFF && (tag & 0x80) )
347         {
348                 info->Axies[ tag & 0x7F ].MinValue = Min;
349                 info->Axies[ tag & 0x7F ].MaxValue = Max;
350         }
351 }
352
353 void HID_Mouse_Report_Input(
354         tUSBInterface *Dev,
355         tHID_ReportGlobalState *Global, tHID_ReportLocalState *Local,
356         Uint32 Value
357         )
358 {
359         Uint32  usage = 0;
360         for( int i = 0; i < Global->ReportCount; i ++ )
361         {
362                 if( i < Local->Usages.nItems )
363                         usage = Local->Usages.Items[i];
364                 HID_int_AddInput(Dev, usage, Global->ReportSize, Global->LogMin, Global->LogMax);
365         }
366 }
367

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