Modules/USB - Untested updates to USB mouse support
authorJohn Hodge <[email protected]>
Thu, 16 Feb 2012 14:58:14 +0000 (22:58 +0800)
committerJohn Hodge <[email protected]>
Thu, 16 Feb 2012 14:58:14 +0000 (22:58 +0800)
KernelLand/Modules/USB/HID/main.c
KernelLand/Modules/USB/HID/mouse.c

index 336609d..68e301e 100644 (file)
 #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);
@@ -29,6 +40,11 @@ tUSBDriver   gHID_USBDriver = {
        .Name = "HID",
        .Match = {.Class = {0x030000, 0xFF0000}},
        .Connected = HID_DeviceConnected,
+       .MaxEndpoints = 2,
+       .Endpoints = {
+               {0x80, HID_InterruptCallback},
+               {0, NULL}
+       }
 };
 tHID_ReportCallbacks   gHID_RootCallbacks = {
        .Collection = HID_RootCollection
@@ -41,6 +57,27 @@ int HID_Initialise(char **Arguments)
        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;
@@ -49,7 +86,7 @@ void HID_DeviceConnected(tUSBInterface *Dev, void *Descriptors, size_t Descripto
        
        ENTER("pDev pDescriptors iDescriptorsLen", Dev, Descriptors, DescriptorsLen);
 
-       // Locate HID descriptor
+       // --- Locate HID descriptor ---
        hid_desc = NULL;
        while(ofs + 2 <= DescriptorsLen)
        {
@@ -70,16 +107,7 @@ void HID_DeviceConnected(tUSBInterface *Dev, void *Descriptors, size_t Descripto
                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!
@@ -90,7 +118,15 @@ void HID_DeviceConnected(tUSBInterface *Dev, void *Descriptors, size_t Descripto
                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 ) {
@@ -104,7 +140,8 @@ void HID_DeviceConnected(tUSBInterface *Dev, void *Descriptors, size_t Descripto
                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);
@@ -169,19 +206,22 @@ void HID_int_ParseReport(tUSBInterface *Dev, Uint8 *Data, size_t Length, tHID_Re
        
        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:
@@ -189,19 +229,23 @@ void HID_int_ParseReport(tUSBInterface *Dev, Uint8 *Data, size_t Length, tHID_Re
                        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)
                {
@@ -329,6 +373,9 @@ void HID_int_ParseReport(tUSBInterface *Dev, Uint8 *Data, size_t Length, tHID_Re
        LEAVE('-');
 }
 
+// --------------------------------------------------------------------
+// List helpers
+// --------------------------------------------------------------------
 static void _AddItem(struct sHID_IntList *List, Uint32 Value)
 {
        if( List->Space == List->nItems )
@@ -352,6 +399,7 @@ static void _AddItems(struct sHID_IntList *List, Uint32 First, Uint32 Last)
 
 static void _FreeList(struct sHID_IntList *List)
 {
-       free(List->Items);
+       if( List->Items )
+               free(List->Items);
 }
 
index b7737f9..be015ad 100644 (file)
 #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);
+       }
 }
 

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