Modules - Implementing mouse multiplexer
[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 <Input/Mouse/include/mouse.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         tMouse  *Handle;
27
28         // - Report parsing
29          int    nMappings;
30         struct {
31                 Uint8   Dest;   // 0x00-0x7F = Buttons, 0x80-0xFE = Axies, 0xFF = Ignore
32                 Uint8   BitSize;
33         } *Mappings;
34         
35         // - Initialisation only data
36          int    CollectionDepth;
37 };
38
39 // === PROTOTYES ===
40 Sint32  _ReadBits(void *Data, int Offset, int Length);
41 void    HID_Mouse_DataAvail(tUSBInterface *Dev, int EndPt, int Length, void *Data);
42
43 tHID_ReportCallbacks    *HID_Mouse_Report_Collection(tUSBInterface *Dev, tHID_ReportGlobalState *Global, tHID_ReportLocalState *Local, Uint32 Value);
44 void    HID_Mouse_Report_EndCollection(tUSBInterface *Dev);
45 void    HID_Mouse_Report_Input(tUSBInterface *Dev, tHID_ReportGlobalState *Global, tHID_ReportLocalState *Local, Uint32 Value);
46
47 // === GLOBALS ===
48 tHID_ReportCallbacks    gHID_Mouse_ReportCBs = {
49         .Collection = HID_Mouse_Report_Collection,
50         .EndCollection = HID_Mouse_Report_EndCollection,
51         .Input = HID_Mouse_Report_Input,
52 };
53 tMutex  glHID_MouseListLock;
54 tHID_Mouse      *gpHID_FirstMouse;
55 tHID_Mouse      *gpHID_LastMouse = (tHID_Mouse*)&gpHID_FirstMouse;
56
57 // === CODE ===
58 // ----------------------------------------------------------------------------
59 // Data input / Update
60 // ----------------------------------------------------------------------------
61 /**
62  * \brief Read a set amounts of bits from a stream
63  * \param Data  Base of data
64  * \param Offset        Bit offset
65  * \param Length        Number of bits to read
66  * \return Sign-extended value
67  */
68 Sint32 _ReadBits(void *Data, int Offset, int Length)
69 {
70          int    dest_ofs = 0;
71          int    rem = Length;
72         Uint32  rv = 0;
73         Uint8   *bytes = (Uint8*)Data + Offset / 8;
74
75         // Sanity please        
76         if( Length > 32 )       return 0;
77
78         // Leading byte
79         if( Offset & 7 )
80         {
81                 if( Length < 8 - (Offset & 7) )
82                 {
83                         rv = (*bytes >> Offset) & ((1 << Length)-1);
84                         goto _ext;
85                 }
86                 
87                 rv = (*bytes >> Offset);
88                 
89                 dest_ofs = Offset & 7;
90                 rem = Length - (Offset & 7);
91                 bytes ++;
92         }
93
94         // Body bytes
95         while( rem >= 8 )
96         {
97                 rv |= *bytes << dest_ofs;
98                 dest_ofs += 8;
99                 rem -= 8;
100                 bytes ++;
101         }
102         
103         if( rem )
104         {
105                 rv |= (*bytes & ((1 << rem)-1)) << dest_ofs;
106         }
107         
108         // Do sign extension
109 _ext:
110         if( rv & (1 << (Length-1)) )
111                 rv |= 0xFFFFFFFF << Length;
112         return rv;
113 }
114
115 /**
116  * \brief Handle an update from the device
117  */
118 void HID_Mouse_DataAvail(tUSBInterface *Dev, int EndPt, int Length, void *Data)
119 {
120         tHID_Mouse      *info;
121          int    ofs;
122         Uint32  button_value = 0;
123          int    axis_values[MAX_AXIES] = {0};
124         
125         info = USB_GetDeviceDataPtr(Dev);
126         if( !info )     return ;
127
128         ofs = 0;
129         for( int i = 0; i < info->nMappings; i ++ )
130         {
131                 Sint32  value;
132                 Uint8   dest = info->Mappings[i].Dest;
133
134                 if( ofs + info->Mappings[i].BitSize > Length * 8 )
135                         return ;
136
137                 value = _ReadBits(Data, ofs, info->Mappings[i].BitSize);
138                 LOG("%i+%i: value = %i", ofs, info->Mappings[i].BitSize, value);
139                 ofs += info->Mappings[i].BitSize;
140                 
141                 if( dest == 0xFF )      continue ;
142                 
143                 if( dest & 0x80 )
144                 {
145                         // Axis
146                         axis_values[ dest & 0x7F ] = value;
147                         LOG("Axis %i = %i", dest & 0x7F, value);
148                 }
149                 else
150                 {
151                         // Button
152                         if( value == 0 )
153                                 ;
154                         else
155                                 button_value |= 1 << (dest & 0x7F);
156                 }
157         }
158         
159         Mouse_HandleEvent(info->Handle, button_value, axis_values);
160 }
161
162 // ----------------------------------------------------------------------------
163 // Device initialisation
164 // ----------------------------------------------------------------------------
165 /**
166  * \brief Handle the opening of a collection
167  */
168 tHID_ReportCallbacks *HID_Mouse_Report_Collection(
169         tUSBInterface *Dev,
170         tHID_ReportGlobalState *Global, tHID_ReportLocalState *Local,
171         Uint32 Value
172         )
173 {
174         tHID_Mouse      *info;
175
176         info = USB_GetDeviceDataPtr(Dev);
177         if( !info )
178         {
179                 // New device!
180                 info = calloc( sizeof(tHID_Mouse), 1 );
181                 info->DataAvail = HID_Mouse_DataAvail;
182         
183                 info->Handle = Mouse_Register("USBMouse", MAX_BUTTONS, MAX_AXIES);
184         
185                 LOG("Initialised new mouse at %p", info);
186                 
187                 USB_SetDeviceDataPtr(Dev, info);
188         }
189         else
190         {
191                 info->CollectionDepth ++;
192         }
193         
194         return &gHID_Mouse_ReportCBs;
195 }
196
197 /**
198  * \brief Handle the end of a collection
199  */
200 void HID_Mouse_Report_EndCollection(tUSBInterface *Dev)
201 {
202         tHID_Mouse      *info;
203
204         info = USB_GetDeviceDataPtr(Dev);       
205         if(!info) {
206                 Log_Error("HID", "HID is not initialised when _AddInput is called");
207                 return ;
208         }
209
210         if( info->CollectionDepth == 0 )
211         {
212                 // Perform final initialisation steps
213                 Mutex_Acquire(&glHID_MouseListLock);
214                 gpHID_LastMouse->Next = info;
215                 gpHID_LastMouse = info;
216                 Mutex_Release(&glHID_MouseListLock);
217         }
218         else
219         {
220                 info->CollectionDepth --;
221         }
222 }
223
224 /**
225  * \brief Add a new input mapping
226  */
227 void HID_int_AddInput(tUSBInterface *Dev, Uint32 Usage, Uint8 Size, Uint32 Min, Uint32 Max)
228 {
229         Uint8   tag;
230         tHID_Mouse      *info;
231
232         info = USB_GetDeviceDataPtr(Dev);
233         if(!info) {
234                 Log_Error("HID", "HID is not initialised when _AddInput is called");
235                 return ;
236         }
237
238         // --- Get the destination for the field ---
239         switch(Usage)
240         {
241         case 0x00010030:        tag = 0x80;     break;  // Generic Desktop - X
242         case 0x00010031:        tag = 0x81;     break;  // Generic Desktop - Y
243         case 0x00010038:        tag = 0x82;     break;  // Generic Desktop - Wheel
244         case 0x00090001:        tag = 0x00;     break;  // Button 1
245         case 0x00090002:        tag = 0x01;     break;  // Button 2
246         case 0x00090003:        tag = 0x02;     break;  // Button 3
247         case 0x00090004:        tag = 0x03;     break;  // Button 4
248         case 0x00090005:        tag = 0x04;     break;  // Button 5
249         default:        tag = 0xFF;     break;
250         }
251         
252         LOG("Usage = 0x%08x, tag = 0x%2x", Usage, tag);
253
254         // --- Add to list of mappings ---
255         info->nMappings ++;
256         info->Mappings = realloc(info->Mappings, info->nMappings * sizeof(info->Mappings[0]));
257         // TODO: NULL check
258         info->Mappings[ info->nMappings - 1].Dest = tag;
259         info->Mappings[ info->nMappings - 1].BitSize = Size;
260         
261         // --- Update Min/Max for Axies ---
262         // TODO: DPI too
263         // TODO: Pass to mouse multiplexer
264 //      if( tag != 0xFF && (tag & 0x80) )
265 //      {
266 //              info->Axies[ tag & 0x7F ].MinValue = Min;
267 //              info->Axies[ tag & 0x7F ].MaxValue = Max;
268 //      }
269 }
270
271 /**
272  * \brief Handle an input item in a report
273  */
274 void HID_Mouse_Report_Input(
275         tUSBInterface *Dev,
276         tHID_ReportGlobalState *Global, tHID_ReportLocalState *Local,
277         Uint32 Value
278         )
279 {
280         Uint32  usage = 0;
281         LOG("Local->Usages.nItems = %i", Local->Usages.nItems);
282         for( int i = 0; i < Global->ReportCount; i ++ )
283         {
284                 // - Update usage
285                 if( i < Local->Usages.nItems )
286                         usage = Local->Usages.Items[i];
287                 LOG("%i: usage = %x", i, usage);
288                 // - Add to list
289                 HID_int_AddInput(Dev, usage, Global->ReportSize, Global->LogMin, Global->LogMax);
290         }
291 }
292

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