2 * Acess2 USB Stack HID Driver
3 * - By John Hodge (thePowersGang)
10 #include "hid_reports.h"
12 #include <api_drv_joystick.h>
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)
20 typedef struct sHID_Mouse tHID_Mouse;
25 tUSB_DataCallback DataAvail;
31 Uint8 FileData[ FILE_SIZE ];
32 tJoystick_FileHeader *FileHeader;
33 tJoystick_Axis *Axies;
36 // Limits for axis positions
37 Uint16 AxisLimits[MAX_AXIES];
42 Uint8 Dest; // 0x00-0x7F = Buttons, 0x80-0xFE = Axies, 0xFF = Ignore
46 // - Initialisation only data
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);
58 void HID_Mouse_DataAvail(tUSBInterface *Dev, int EndPt, int Length, void *Data);
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);
65 tVFS_NodeType gHID_Mouse_RootNodeType = {
66 .TypeName = "HID Mouse Root",
67 .ReadDir = HID_Mouse_Root_ReadDir,
68 .FindDir = HID_Mouse_Root_FindDir
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,
77 tDevFS_Driver gHID_Mouse_DevFS = {
80 .Type = &gHID_Mouse_RootNodeType,
81 .Flags = VFS_FFLAG_DIRECTORY
84 tHID_ReportCallbacks gHID_Mouse_ReportCBs = {
85 .Collection = HID_Mouse_Report_Collection,
86 .EndCollection = HID_Mouse_Report_EndCollection,
87 .Input = HID_Mouse_Report_Input,
89 tMutex glHID_MouseListLock;
90 tHID_Mouse *gpHID_FirstMouse;
91 tHID_Mouse *gpHID_LastMouse = (tHID_Mouse*)&gpHID_FirstMouse;
94 // ----------------------------------------------------------------------------
96 // ----------------------------------------------------------------------------
97 char *HID_Mouse_Root_ReadDir(tVFS_Node *Node, int Pos)
100 if(Pos < 0 || Pos >= Node->Size) return NULL;
102 snprintf(data, 3, "%i", Pos);
106 tVFS_Node *HID_Mouse_Root_FindDir(tVFS_Node *Node, const char *Name)
112 if( Name[0] == '\0' )
115 ofs = ParseInt(Name, &ID);
116 if( ofs == 0 || Name[ofs] != '\0' )
119 // Scan list, locate item
120 Mutex_Acquire(&glHID_MouseListLock);
121 for( mouse = gpHID_FirstMouse; mouse && ID --; mouse = mouse->Next ) ;
123 mouse->Node.ReferenceCount ++;
124 Mutex_Release(&glHID_MouseListLock);
132 size_t HID_Mouse_Dev_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer)
134 tHID_Mouse *info = Node->ImplPtr;
136 if( Offset > FILE_SIZE ) return 0;
138 if( Length > FILE_SIZE ) Length = FILE_SIZE;
139 if( Offset + Length > FILE_SIZE ) Length = FILE_SIZE - Offset;
141 memcpy( Buffer, info->FileData + Offset, Length );
143 VFS_MarkAvaliable( &info->Node, 0 );
148 static const char *csaDevIOCtls[] = {DRV_IOCTLNAMES, DRV_JOY_IOCTLNAMES, NULL};
149 int HID_Mouse_Dev_IOCtl(tVFS_Node *Node, int ID, void *Data)
151 tJoystick_NumValue *numval = Data;
152 tHID_Mouse *info = Node->ImplPtr;
155 BASE_IOCTLS(DRV_TYPE_JOYSTICK, "USBMouse", 0x050, csaDevIOCtls);
157 case JOY_IOCTL_GETSETAXISLIMIT:
158 if( !numval || !CheckMem(numval, sizeof(*numval)) )
160 if(numval->Num < 0 || numval->Num >= MAX_AXIES)
162 if(numval->Value != -1)
163 info->AxisLimits[numval->Num] = numval->Value;
164 return info->AxisLimits[numval->Num];
166 case JOY_IOCTL_GETSETAXISPOSITION:
167 if( !numval || !CheckMem(numval, sizeof(*numval)) )
169 if(numval->Num < 0 || numval->Num >= MAX_AXIES)
171 if(numval->Value != -1)
172 info->Axies[numval->Num].CursorPos = numval->Value;
173 return info->Axies[numval->Num].CursorPos;
177 void HID_Mouse_Dev_Reference(tVFS_Node *Node)
179 Node->ReferenceCount ++;
181 void HID_Mouse_Dev_Close(tVFS_Node *Node)
183 Node->ReferenceCount --;
186 // ----------------------------------------------------------------------------
187 // Data input / Update
188 // ----------------------------------------------------------------------------
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
196 Sint32 _ReadBits(void *Data, int Offset, int Length)
201 Uint8 *bytes = (Uint8*)Data + Offset / 8;
204 if( Length > 32 ) return 0;
209 if( Length < 8 - (Offset & 7) )
211 rv = (*bytes >> Offset) & ((1 << Length)-1);
215 rv = (*bytes >> Offset);
217 dest_ofs = Offset & 7;
218 rem = Length - (Offset & 7);
225 rv |= *bytes << dest_ofs;
233 rv |= (*bytes & ((1 << rem)-1)) << dest_ofs;
238 if( rv & (1 << (Length-1)) )
239 rv |= 0xFFFFFFFF << Length;
244 * \brief Handle an update from the device
246 void HID_Mouse_DataAvail(tUSBInterface *Dev, int EndPt, int Length, void *Data)
251 info = USB_GetDeviceDataPtr(Dev);
255 for( int i = 0; i < info->nMappings; i ++ )
258 Uint8 dest = info->Mappings[i].Dest;
260 if( ofs + info->Mappings[i].BitSize > Length * 8 )
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;
267 if( dest == 0xFF ) continue ;
272 info->Axies[ dest & 0x7F ].CurValue = value;
273 LOG("Axis %i = %i", dest & 0x7F, info->Axies[dest & 0x7F].CurValue);
278 info->Buttons[ dest & 0x7F ] = (value == 0) ? 0 : 0xFF;
279 LOG("Button %i = %x", dest & 0x7F, info->Buttons[dest & 0x7F]);
283 // Update axis positions
284 for( int i = 0; i < MAX_AXIES; i ++ )
289 newpos = info->Axies[i].CursorPos + info->Axies[i].CurValue;
291 if(newpos < 0) newpos = 0;
292 if(newpos > info->AxisLimits[i]) newpos = info->AxisLimits[i];
294 info->Axies[i].CursorPos = newpos;
296 // Log_Debug("USBMouse", "New Pos (%i,%i,%i)",
297 // info->Axies[0].CursorPos, info->Axies[1].CursorPos, info->Axies[2].CursorPos
299 VFS_MarkAvaliable( &info->Node, 1 );
302 // ----------------------------------------------------------------------------
303 // Device initialisation
304 // ----------------------------------------------------------------------------
306 * \brief Handle the opening of a collection
308 tHID_ReportCallbacks *HID_Mouse_Report_Collection(
310 tHID_ReportGlobalState *Global, tHID_ReportLocalState *Local,
316 info = USB_GetDeviceDataPtr(Dev);
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;
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;
331 for( int i = 0; i < MAX_AXIES; i ++ ) {
332 info->Axies[i].MinValue = -10;
333 info->Axies[i].MaxValue = 10;
337 LOG("Initialised new mouse at %p", info);
339 USB_SetDeviceDataPtr(Dev, info);
343 info->CollectionDepth ++;
346 return &gHID_Mouse_ReportCBs;
350 * \brief Handle the end of a collection
352 void HID_Mouse_Report_EndCollection(tUSBInterface *Dev)
356 info = USB_GetDeviceDataPtr(Dev);
358 Log_Error("HID", "HID is not initialised when _AddInput is called");
362 if( info->CollectionDepth == 0 )
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);
373 info->CollectionDepth --;
378 * \brief Add a new input mapping
380 void HID_int_AddInput(tUSBInterface *Dev, Uint32 Usage, Uint8 Size, Uint32 Min, Uint32 Max)
385 info = USB_GetDeviceDataPtr(Dev);
387 Log_Error("HID", "HID is not initialised when _AddInput is called");
391 // --- Get the destination for the field ---
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;
405 LOG("Usage = 0x%08x, tag = 0x%2x", Usage, tag);
407 // --- Add to list of mappings ---
409 info->Mappings = realloc(info->Mappings, info->nMappings * sizeof(info->Mappings[0]));
411 info->Mappings[ info->nMappings - 1].Dest = tag;
412 info->Mappings[ info->nMappings - 1].BitSize = Size;
414 // --- Update Min/Max for Axies ---
416 if( tag != 0xFF && (tag & 0x80) )
418 info->Axies[ tag & 0x7F ].MinValue = Min;
419 info->Axies[ tag & 0x7F ].MaxValue = Max;
424 * \brief Handle an input item in a report
426 void HID_Mouse_Report_Input(
428 tHID_ReportGlobalState *Global, tHID_ReportLocalState *Local,
433 LOG("Local->Usages.nItems = %i", Local->Usages.nItems);
434 for( int i = 0; i < Global->ReportCount; i ++ )
437 if( i < Local->Usages.nItems )
438 usage = Local->Usages.Items[i];
439 LOG("%i: usage = %x", i, usage);
441 HID_int_AddInput(Dev, usage, Global->ReportSize, Global->LogMin, Global->LogMax);