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

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