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

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