#include "hid.h"
#include "hid_reports.h"
+// === TYPES ===
+typedef struct sHID_Device tHID_Device;
+
+struct sHID_Device
+{
+ void *Next; // Used by sub-driver
+ tUSB_DataCallback DataAvail;
+ // ... Device-specific data
+};
+
// === PROTOTYPES ===
int HID_Initialise(char **Arguments);
+void HID_InterruptCallback(tUSBInterface *Dev, int EndPt, int Length, void *Data);
void HID_DeviceConnected(tUSBInterface *Dev, void *Descriptors, size_t DescriptorsLen);
tHID_ReportCallbacks *HID_RootCollection(tUSBInterface *Dev, tHID_ReportGlobalState *Global, tHID_ReportLocalState *Local, Uint32 Value);
void HID_int_ParseReport(tUSBInterface *Dev, Uint8 *Data, size_t Length, tHID_ReportCallbacks *StartCBs);
.Name = "HID",
.Match = {.Class = {0x030000, 0xFF0000}},
.Connected = HID_DeviceConnected,
+ .MaxEndpoints = 2,
+ .Endpoints = {
+ {0x80, HID_InterruptCallback},
+ {0, NULL}
+ }
};
tHID_ReportCallbacks gHID_RootCallbacks = {
.Collection = HID_RootCollection
return 0;
}
+/**
+ * \brief Callback for when there's new data from the device
+ *
+ * Calls the subdriver callback (stored at a fixed offset in the device data structure)
+ */
+void HID_InterruptCallback(tUSBInterface *Dev, int EndPt, int Length, void *Data)
+{
+ tHID_Device *info;
+
+ info = USB_GetDeviceDataPtr(Dev);
+ if(!info) {
+ Log_Error("USB HID", "Device %p doesn't have a data pointer.", Dev);
+ return ;
+ }
+
+ info->DataAvail(Dev, EndPt, Length, Data);
+}
+
+/**
+ * \brief Handle a device connection
+ */
void HID_DeviceConnected(tUSBInterface *Dev, void *Descriptors, size_t DescriptorsLen)
{
struct sDescriptor_HID *hid_desc;
ENTER("pDev pDescriptors iDescriptorsLen", Dev, Descriptors, DescriptorsLen);
- // Locate HID descriptor
+ // --- Locate HID descriptor ---
hid_desc = NULL;
while(ofs + 2 <= DescriptorsLen)
{
LEAVE('-');
return ;
}
-
-
- // Dump descriptor header
- LOG("hid_desc = {");
- LOG(" .Length = %i", hid_desc->Length);
- LOG(" .Type = 0x%x", hid_desc->Type);
- LOG(" .Version = 0x%x", hid_desc->Version);
- LOG(" .NumDescriptors = %i", hid_desc->NumDescriptors);
- LOG("}");
-
+ // - Sanity check length
if( hid_desc->Length < sizeof(*hid_desc) + hid_desc->NumDescriptors * sizeof(hid_desc->Descriptors[0]) )
{
// Too small!
return ;
}
- // Locate report descriptor
+ // --- Dump descriptor header ---
+ LOG("hid_desc = {");
+ LOG(" .Length = %i", hid_desc->Length);
+ LOG(" .Type = 0x%x", hid_desc->Type);
+ LOG(" .Version = 0x%x", hid_desc->Version);
+ LOG(" .NumDescriptors = %i", hid_desc->NumDescriptors);
+ LOG("}");
+
+ // --- Locate report descriptor length ---
for( int i = 0; i < hid_desc->NumDescriptors; i ++ )
{
if( hid_desc->Descriptors[i].DescType == 0x22 ) {
return ;
}
- // Read and parse report descriptor
+ // --- Read and parse report descriptor ---
+ // NOTE: Also does sub-driver selection and initialisation
Uint8 *report_data = alloca(report_len);
USB_ReadDescriptor(Dev, 0x1022, 0, report_len, report_data);
HID_int_ParseReport(Dev, report_data, report_len, &gHID_RootCallbacks);
ENTER("pData iLength pStartCBs", Data, Length, StartCBs);
+ // Initialise callback stack
cb_stack[0] = StartCBs;
cur_cbs = StartCBs;
+ // Clear state
memset(&global_state, 0, sizeof(global_state));
memset(&local_state, 0, sizeof(local_state));
+ // Iterate though the report data
for( int ofs = 0; ofs < Length; )
{
Uint8 byte;
Uint32 val;
+ // --- Get value and length ---
byte = Data[ofs];
- // Get value (and increase offset)
switch(byte & 3)
{
case 0:
ofs += 1;
break;
case 1:
+ if( ofs + 2 > Length ) { LEAVE('-'); return; }
val = Data[ofs+1];
ofs += 2;
break;
case 2:
+ if( ofs + 3 > Length ) { LEAVE('-'); return; }
val = Data[ofs + 1] | (Data[ofs + 1]<<8);
ofs += 3;
break;
case 3:
+ if( ofs + 5 > Length ) { LEAVE('-'); return; }
val = Data[ofs + 1] | (Data[ofs + 2] << 8) | (Data[ofs + 3] << 16) | (Data[ofs + 4] << 24);
ofs += 5;
break;
}
+ // --- Process the item ---
LOG("Type = 0x%x, len = %i, val = 0x%x", byte & 0xFC, byte & 3, val);
switch(byte & 0xFC)
{
LEAVE('-');
}
+// --------------------------------------------------------------------
+// List helpers
+// --------------------------------------------------------------------
static void _AddItem(struct sHID_IntList *List, Uint32 Value)
{
if( List->Space == List->nItems )
static void _FreeList(struct sHID_IntList *List)
{
- free(List->Items);
+ if( List->Items )
+ free(List->Items);
}
#include <acess.h>
#include "hid_reports.h"
#include <fs_devfs.h>
+#include <api_drv_joystick.h>
+// === CONSTANTS ===
+#define MAX_AXIES 3 // X, Y, Scroll
+#define MAX_BUTTONS 5 // Left, Right, Middle, ...
+
+// === TYPES ===
+typedef struct sHID_Mouse tHID_Mouse;
+
+struct sHID_Mouse
+{
+ tHID_Mouse *Next;
+ tUSB_DataCallback DataAvail;
+
+ tVFS_Node Node;
+ int CollectionDepth;
+
+ Uint8 FileData[ sizeof(tJoystick_FileHeader) + MAX_AXIES*sizeof(tJoystick_Axis) + MAX_BUTTONS ];
+ tJoystick_FileHeader *FileHeader;
+ tJoystick_Axis *Axies;
+ Uint8 *Buttons;
+
+ Uint16 AxisLimits[MAX_AXIES];
+
+ int nMappings;
+ struct {
+ Uint8 Dest; // 0x00-0x7F = Buttons, 0x80-0xFE = Axies, 0xFF = Ignore
+ Uint8 BitSize;
+ } *Mappings;
+};
// === PROTOTYES ===
+void HID_Mouse_DataAvail(tUSBInterface *Dev, int EndPt, int Length, void *Data);
tHID_ReportCallbacks *HID_Mouse_Report_Collection(tUSBInterface *Dev, tHID_ReportGlobalState *Global, tHID_ReportLocalState *Local, Uint32 Value);
+void HID_Mouse_Report_EndCollection(tUSBInterface *Dev);
void HID_Mouse_Report_Input(tUSBInterface *Dev, tHID_ReportGlobalState *Global, tHID_ReportLocalState *Local, Uint32 Value);
-void HID_Mouse_Report_Output(tUSBInterface *Dev, tHID_ReportGlobalState *Global, tHID_ReportLocalState *Local, Uint32 Value);
-void HID_Mouse_Report_Feature(tUSBInterface *Dev, tHID_ReportGlobalState *Global, tHID_ReportLocalState *Local, Uint32 Value);
// === GLOBALS ===
+tVFS_NodeType gHID_Mouse_RootNodeType = {
+ .TypeName = "HID Mouse Root"
+};
+tVFS_NodeType gHID_Mouse_DevNodeType = {
+ .TypeName = "HID Mouse Dev"
+};
tDevFS_Driver gHID_Mouse_DevFS = {
- .Name = "USBKeyboard",
+ .Name = "USBMouse",
+ .RootNode = {.Type = &gHID_Mouse_RootNodeType}
};
tHID_ReportCallbacks gHID_Mouse_ReportCBs = {
.Collection = HID_Mouse_Report_Collection,
+ .EndCollection = HID_Mouse_Report_EndCollection,
.Input = HID_Mouse_Report_Input,
- .Output = HID_Mouse_Report_Output,
- .Feature = HID_Mouse_Report_Feature
};
+tHID_Mouse *gpHID_FirstMouse;
+tHID_Mouse *gpHID_LastMouse = (tHID_Mouse*)&gpHID_FirstMouse;
// === CODE ===
+// ----------------------------------------------------------------------------
+// VFS Interface
+// ----------------------------------------------------------------------------
+
+// ----------------------------------------------------------------------------
+// Data input / Update
+// ----------------------------------------------------------------------------
+Sint32 _ReadBits(void *Data, int Offset, int Length)
+{
+ int dest_ofs = 0;
+ Uint32 rv = 0;
+ Uint8 *bytes = (Uint8*)Data + Offset / 8;
+
+ // 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;
+}
+
+void HID_Mouse_DataAvail(tUSBInterface *Dev, int EndPt, int Length, void *Data)
+{
+ tHID_Mouse *info;
+ int ofs;
+
+ info = USB_GetDeviceDataPtr(Dev);
+ if( !info ) return ;
+
+
+ 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
+// ----------------------------------------------------------------------------
+/**
+ */
tHID_ReportCallbacks *HID_Mouse_Report_Collection(
tUSBInterface *Dev,
tHID_ReportGlobalState *Global, tHID_ReportLocalState *Local,
Uint32 Value
)
{
+ tHID_Mouse *info;
+
+ info = USB_GetDeviceDataPtr(Dev);
+ if( !info )
+ {
+ // New device!
+ info = calloc( sizeof(tHID_Mouse), 1 );
+ info->DataAvail = HID_Mouse_DataAvail;
+ info->Node.Type = &gHID_Mouse_DevNodeType;
+
+ info->FileHeader = (void*)info->FileData;
+ info->Axies = (void*)(info->FileHeader + 1);
+ info->Buttons = (void*)(info->Axies + MAX_AXIES);
+
+ USB_SetDeviceDataPtr(Dev, info);
+ }
+ else
+ {
+ info->CollectionDepth ++;
+ }
+
return &gHID_Mouse_ReportCBs;
}
-void HID_Mouse_Report_Input(
- tUSBInterface *Dev,
- tHID_ReportGlobalState *Global, tHID_ReportLocalState *Local,
- Uint32 Value
- )
+void HID_Mouse_Report_EndCollection(tUSBInterface *Dev)
{
-
+ tHID_Mouse *info;
+
+ info = USB_GetDeviceDataPtr(Dev);
+ if(!info) {
+ Log_Error("HID", "HID is not initialised when _AddInput is called");
+ return ;
+ }
+
+ if( info->CollectionDepth == 0 )
+ {
+ // TODO: Do final cleanup on device
+ gpHID_LastMouse->Next = info;
+ gpHID_LastMouse = info;
+ }
+ else
+ {
+ info->CollectionDepth --;
+ }
}
-void HID_Mouse_Report_Output(
- tUSBInterface *Dev,
- tHID_ReportGlobalState *Global, tHID_ReportLocalState *Local,
- Uint32 Value
- )
+void HID_int_AddInput(tUSBInterface *Dev, Uint32 Usage, Uint8 Size, Uint32 Min, Uint32 Max)
{
+ Uint8 tag;
+ tHID_Mouse *info;
+
+ info = USB_GetDeviceDataPtr(Dev);
+ if(!info) {
+ Log_Error("HID", "HID is not initialised when _AddInput is called");
+ return ;
+ }
+
+ switch(Usage)
+ {
+ case 0x00010030: tag = 0x80; break; // Generic Desktop - X
+ case 0x00010031: tag = 0x81; break; // Generic Desktop - Y
+ case 0x00010038: tag = 0x82; break; // Generic Desktop - Wheel
+ case 0x00090001: tag = 0x00; break; // Button 1
+ case 0x00090002: tag = 0x01; break; // Button 2
+ case 0x00090003: tag = 0x02; break; // Button 3
+ case 0x00090004: tag = 0x03; break; // Button 4
+ case 0x00090005: tag = 0x04; break; // Button 5
+ default: tag = 0xFF; break;
+ }
+
+ info->nMappings ++;
+ info->Mappings = realloc(info->Mappings, info->nMappings * sizeof(info->Mappings[0]));
+ // TODO: NULL check
+ info->Mappings[ info->nMappings - 1].Dest = tag;
+ info->Mappings[ info->nMappings - 1].BitSize = Size;
+
+ if( tag != 0xFF && (tag & 0x80) )
+ {
+ info->Axies[ tag & 0x7F ].MinValue = Min;
+ info->Axies[ tag & 0x7F ].MaxValue = Max;
+ }
}
-void HID_Mouse_Report_Feature(
+void HID_Mouse_Report_Input(
tUSBInterface *Dev,
tHID_ReportGlobalState *Global, tHID_ReportLocalState *Local,
Uint32 Value
)
{
-
+ Uint32 usage = 0;
+ for( int i = 0; i < Global->ReportCount; i ++ )
+ {
+ if( i < Local->Usages.nItems )
+ usage = Local->Usages.Items[i];
+ HID_int_AddInput(Dev, usage, Global->ReportSize, Global->LogMin, Global->LogMax);
+ }
}