Modules/USB - Untested updates to USB mouse support
[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
18 // === TYPES ===
19 typedef struct sHID_Mouse       tHID_Mouse;
20
21 struct sHID_Mouse
22 {
23         tHID_Mouse      *Next;
24         tUSB_DataCallback       DataAvail;
25
26         tVFS_Node       Node;
27          int    CollectionDepth;
28         
29         Uint8   FileData[ sizeof(tJoystick_FileHeader) + MAX_AXIES*sizeof(tJoystick_Axis) + MAX_BUTTONS ];
30         tJoystick_FileHeader    *FileHeader;
31         tJoystick_Axis  *Axies;
32         Uint8   *Buttons;
33
34         Uint16  AxisLimits[MAX_AXIES];
35         
36          int    nMappings;
37         struct {
38                 Uint8   Dest;   // 0x00-0x7F = Buttons, 0x80-0xFE = Axies, 0xFF = Ignore
39                 Uint8   BitSize;
40         } *Mappings;
41 };
42
43 // === PROTOTYES ===
44 void    HID_Mouse_DataAvail(tUSBInterface *Dev, int EndPt, int Length, void *Data);
45 tHID_ReportCallbacks    *HID_Mouse_Report_Collection(tUSBInterface *Dev, tHID_ReportGlobalState *Global, tHID_ReportLocalState *Local, Uint32 Value);
46 void    HID_Mouse_Report_EndCollection(tUSBInterface *Dev);
47 void    HID_Mouse_Report_Input(tUSBInterface *Dev, tHID_ReportGlobalState *Global, tHID_ReportLocalState *Local, Uint32 Value);
48
49 // === GLOBALS ===
50 tVFS_NodeType   gHID_Mouse_RootNodeType = {
51         .TypeName = "HID Mouse Root"
52 };
53 tVFS_NodeType   gHID_Mouse_DevNodeType = {
54         .TypeName = "HID Mouse Dev"
55 };
56 tDevFS_Driver   gHID_Mouse_DevFS = {
57         .Name = "USBMouse",
58         .RootNode = {.Type = &gHID_Mouse_RootNodeType}
59 };
60 tHID_ReportCallbacks    gHID_Mouse_ReportCBs = {
61         .Collection = HID_Mouse_Report_Collection,
62         .EndCollection = HID_Mouse_Report_EndCollection,
63         .Input = HID_Mouse_Report_Input,
64 };
65 tHID_Mouse      *gpHID_FirstMouse;
66 tHID_Mouse      *gpHID_LastMouse = (tHID_Mouse*)&gpHID_FirstMouse;
67
68 // === CODE ===
69 // ----------------------------------------------------------------------------
70 // VFS Interface
71 // ----------------------------------------------------------------------------
72
73 // ----------------------------------------------------------------------------
74 // Data input / Update
75 // ----------------------------------------------------------------------------
76 Sint32 _ReadBits(void *Data, int Offset, int Length)
77 {
78          int    dest_ofs = 0;
79         Uint32  rv = 0;
80         Uint8   *bytes = (Uint8*)Data + Offset / 8;
81         
82         // Leading byte
83         if( Offset & 7 )
84         {
85                 if( Length < 8 - (Offset & 7) )
86                 {
87                         rv = (*bytes >> Offset) & ((1 << Length)-1);
88                         goto _ext;
89                 }
90                 
91                 rv = (*bytes >> Offset);
92                 
93                 dest_ofs = Offset & 7;
94                 Length -= Offset & 7;
95                 bytes ++;
96         }
97
98         // Body bytes
99         while( Length >= 8 )
100         {
101                 rv |= *bytes << dest_ofs;
102                 dest_ofs += 8;
103                 Length -= 8;
104                 bytes ++;
105         }
106         
107         if( Length )
108         {
109                 rv |= (*bytes & ((1 << Length)-1)) << dest_ofs;
110                 
111         }
112         
113         // Do sign extension
114 _ext:
115         if( rv & (1 << (Length-1)) )
116                 rv |= 0xFFFFFFFF << Length;
117         return rv;
118 }
119
120 void HID_Mouse_DataAvail(tUSBInterface *Dev, int EndPt, int Length, void *Data)
121 {
122         tHID_Mouse      *info;
123          int    ofs;
124         
125         info = USB_GetDeviceDataPtr(Dev);
126         if( !info )     return ;
127         
128         
129         ofs = 0;
130         for( int i = 0; i < info->nMappings; i ++ )
131         {
132                 Sint32  value;
133                 Uint8   dest = info->Mappings[i].Dest;
134
135                 if( ofs + info->Mappings[i].BitSize > Length * 8 )
136                         return ;
137
138                 value = _ReadBits(Data, ofs, info->Mappings[i].BitSize);
139                 ofs += info->Mappings[i].BitSize;
140                 
141                 if( dest == 0xFF )      continue ;
142                 
143                 if( dest & 0x80 )
144                 {
145                         // Axis
146                         info->Axies[ dest & 0x7F ].CurValue = value;
147                 }
148                 else
149                 {
150                         // Button
151                         info->Buttons[ dest & 0x7F ] = (value == 0) ? 0 : 0xFF;
152                 }
153         }
154         
155         // Update axis positions
156         for( int i = 0; i < MAX_AXIES; i ++ )
157         {
158                  int    newpos;
159                 
160                 // TODO: Scaling
161                 newpos = info->Axies[i].CursorPos + info->Axies[i].CurValue;
162                 
163                 if(newpos < 0)  newpos = 0;
164                 if(newpos > info->AxisLimits[i])        newpos = info->AxisLimits[i];
165                 
166                 info->Axies[i].CursorPos = newpos;
167         }
168         Log_Debug("USBMouse", "New Pos (%i,%i,%i)",
169                 info->Axies[0].CursorPos, info->Axies[1].CursorPos, info->Axies[2].CursorPos
170                 );
171 }
172
173 // ----------------------------------------------------------------------------
174 // Device initialisation
175 // ----------------------------------------------------------------------------
176 /**
177  */
178 tHID_ReportCallbacks *HID_Mouse_Report_Collection(
179         tUSBInterface *Dev,
180         tHID_ReportGlobalState *Global, tHID_ReportLocalState *Local,
181         Uint32 Value
182         )
183 {
184         tHID_Mouse      *info;
185
186         info = USB_GetDeviceDataPtr(Dev);
187         if( !info )
188         {
189                 // New device!
190                 info = calloc( sizeof(tHID_Mouse), 1 );
191                 info->DataAvail = HID_Mouse_DataAvail;
192                 info->Node.Type = &gHID_Mouse_DevNodeType;
193                 
194                 info->FileHeader = (void*)info->FileData;
195                 info->Axies = (void*)(info->FileHeader + 1);
196                 info->Buttons = (void*)(info->Axies + MAX_AXIES);
197                 
198                 USB_SetDeviceDataPtr(Dev, info);
199         }
200         else
201         {
202                 info->CollectionDepth ++;
203         }
204         
205         return &gHID_Mouse_ReportCBs;
206 }
207
208 void HID_Mouse_Report_EndCollection(tUSBInterface *Dev)
209 {
210         tHID_Mouse      *info;
211
212         info = USB_GetDeviceDataPtr(Dev);       
213         if(!info) {
214                 Log_Error("HID", "HID is not initialised when _AddInput is called");
215                 return ;
216         }
217
218         if( info->CollectionDepth == 0 )
219         {
220                 // TODO: Do final cleanup on device
221                 gpHID_LastMouse->Next = info;
222                 gpHID_LastMouse = info;
223         }
224         else
225         {
226                 info->CollectionDepth --;
227         }
228 }
229
230 void HID_int_AddInput(tUSBInterface *Dev, Uint32 Usage, Uint8 Size, Uint32 Min, Uint32 Max)
231 {
232         Uint8   tag;
233         tHID_Mouse      *info;
234
235         info = USB_GetDeviceDataPtr(Dev);
236         if(!info) {
237                 Log_Error("HID", "HID is not initialised when _AddInput is called");
238                 return ;
239         }
240
241         switch(Usage)
242         {
243         case 0x00010030:        tag = 0x80;     break;  // Generic Desktop - X
244         case 0x00010031:        tag = 0x81;     break;  // Generic Desktop - Y
245         case 0x00010038:        tag = 0x82;     break;  // Generic Desktop - Wheel
246         case 0x00090001:        tag = 0x00;     break;  // Button 1
247         case 0x00090002:        tag = 0x01;     break;  // Button 2
248         case 0x00090003:        tag = 0x02;     break;  // Button 3
249         case 0x00090004:        tag = 0x03;     break;  // Button 4
250         case 0x00090005:        tag = 0x04;     break;  // Button 5
251         default:        tag = 0xFF;     break;
252         }
253         
254         info->nMappings ++;
255         info->Mappings = realloc(info->Mappings, info->nMappings * sizeof(info->Mappings[0]));
256         // TODO: NULL check
257         
258         info->Mappings[ info->nMappings - 1].Dest = tag;
259         info->Mappings[ info->nMappings - 1].BitSize = Size;
260         
261         if( tag != 0xFF && (tag & 0x80) )
262         {
263                 info->Axies[ tag & 0x7F ].MinValue = Min;
264                 info->Axies[ tag & 0x7F ].MaxValue = Max;
265         }
266 }
267
268 void HID_Mouse_Report_Input(
269         tUSBInterface *Dev,
270         tHID_ReportGlobalState *Global, tHID_ReportLocalState *Local,
271         Uint32 Value
272         )
273 {
274         Uint32  usage = 0;
275         for( int i = 0; i < Global->ReportCount; i ++ )
276         {
277                 if( i < Local->Usages.nItems )
278                         usage = Local->Usages.Items[i];
279                 HID_int_AddInput(Dev, usage, Global->ReportSize, Global->LogMin, Global->LogMax);
280         }
281 }
282

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