+// ----------------------------------------------------------------------------
+// VFS Interface
+// ----------------------------------------------------------------------------
+char *HID_Mouse_Root_ReadDir(tVFS_Node *Node, int Pos)
+{
+ char data[3];
+ if(Pos < 0 || Pos >= Node->Size) return NULL;
+
+ snprintf(data, 3, "%i", Pos);
+ return strdup(data);
+}
+
+tVFS_Node *HID_Mouse_Root_FindDir(tVFS_Node *Node, const char *Name)
+{
+ int ID;
+ int ofs;
+ tHID_Mouse *mouse;
+
+ if( Name[0] == '\0' )
+ return NULL;
+
+ ofs = ParseInt(Name, &ID);
+ if( ofs == 0 || Name[ofs] != '\0' )
+ return NULL;
+
+ // Scan list, locate item
+ Mutex_Acquire(&glHID_MouseListLock);
+ for( mouse = gpHID_FirstMouse; mouse && ID --; mouse = mouse->Next ) ;
+ mouse->Node.ReferenceCount ++;
+ Mutex_Release(&glHID_MouseListLock);
+
+ return &mouse->Node;
+}
+
+Uint64 HID_Mouse_Dev_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+{
+ tHID_Mouse *info = Node->ImplPtr;
+
+ if( Offset > FILE_SIZE ) return 0;
+
+ if( Length > FILE_SIZE ) Length = FILE_SIZE;
+ if( Offset + Length > FILE_SIZE ) Length = FILE_SIZE - Offset;
+
+ memcpy( Buffer, info->FileData + Offset, Length );
+
+ return Length;
+}
+
+static const char *csaDevIOCtls[] = {DRV_IOCTLNAMES, DRV_JOY_IOCTLNAMES, NULL};
+int HID_Mouse_Dev_IOCtl(tVFS_Node *Node, int ID, void *Data)
+{
+ switch(ID)
+ {
+ BASE_IOCTLS(DRV_TYPE_JOYSTICK, "USBMouse", 0x050, csaDevIOCtls);
+ }
+ return -1;
+}
+void HID_Mouse_Dev_Reference(tVFS_Node *Node)
+{
+ Node->ReferenceCount ++;
+}
+void HID_Mouse_Dev_Close(tVFS_Node *Node)
+{
+ Node->ReferenceCount --;
+}
+
+// ----------------------------------------------------------------------------
+// Data input / Update
+// ----------------------------------------------------------------------------
+/**
+ * \brief Read a set amounts of bits from a stream
+ * \param Data Base of data
+ * \param Offset Bit offset
+ * \param Length Number of bits to read
+ * \return Sign-extended value
+ */
+Sint32 _ReadBits(void *Data, int Offset, int Length)
+{
+ int dest_ofs = 0;
+ Uint32 rv = 0;
+ Uint8 *bytes = (Uint8*)Data + Offset / 8;
+
+ // Sanity please
+ if( Length > 32 ) return 0;
+
+ // Leading byte
+ if( Offset & 7 )
+ {
+ if( Length < 8 - (Offset & 7) )
+ {
+ rv = (*bytes >> Offset) & ((1 << Length)-1);
+ goto _ext;
+ }
+
+ rv = (*bytes >> Offset);
+
+ dest_ofs = Offset & 7;
+ Length -= Offset & 7;
+ bytes ++;
+ }
+
+ // Body bytes
+ while( Length >= 8 )
+ {
+ rv |= *bytes << dest_ofs;
+ dest_ofs += 8;
+ Length -= 8;
+ bytes ++;
+ }
+
+ if( Length )
+ {
+ rv |= (*bytes & ((1 << Length)-1)) << dest_ofs;
+
+ }
+
+ // Do sign extension
+_ext:
+ if( rv & (1 << (Length-1)) )
+ rv |= 0xFFFFFFFF << Length;
+ return rv;
+}
+
+/**
+ * \brief Handle an update from the device
+ */
+void HID_Mouse_DataAvail(tUSBInterface *Dev, int EndPt, int Length, void *Data)
+{
+ tHID_Mouse *info;
+ int ofs;
+
+ info = USB_GetDeviceDataPtr(Dev);
+ if( !info ) return ;
+
+ Log_Debug("USBMouse", "info = %p", info);
+
+ ofs = 0;
+ for( int i = 0; i < info->nMappings; i ++ )
+ {
+ Sint32 value;
+ Uint8 dest = info->Mappings[i].Dest;
+
+ if( ofs + info->Mappings[i].BitSize > Length * 8 )
+ return ;
+
+ value = _ReadBits(Data, ofs, info->Mappings[i].BitSize);
+ ofs += info->Mappings[i].BitSize;
+
+ if( dest == 0xFF ) continue ;
+
+ if( dest & 0x80 )
+ {
+ // Axis
+ info->Axies[ dest & 0x7F ].CurValue = value;
+ }
+ else
+ {
+ // Button
+ info->Buttons[ dest & 0x7F ] = (value == 0) ? 0 : 0xFF;
+ }
+ }
+
+ // Update axis positions
+ for( int i = 0; i < MAX_AXIES; i ++ )
+ {
+ int newpos;
+
+ // TODO: Scaling
+ newpos = info->Axies[i].CursorPos + info->Axies[i].CurValue;
+
+ if(newpos < 0) newpos = 0;
+ if(newpos > info->AxisLimits[i]) newpos = info->AxisLimits[i];
+
+ info->Axies[i].CursorPos = newpos;
+ }
+ Log_Debug("USBMouse", "New Pos (%i,%i,%i)",
+ info->Axies[0].CursorPos, info->Axies[1].CursorPos, info->Axies[2].CursorPos
+ );
+}
+
+// ----------------------------------------------------------------------------
+// Device initialisation
+// ----------------------------------------------------------------------------
+/**
+ * \brief Handle the opening of a collection
+ */