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

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