From 4eca73b17dde3a39b8b918d92ebe45261929615e Mon Sep 17 00:00:00 2001 From: John Hodge Date: Thu, 16 Feb 2012 22:58:14 +0800 Subject: [PATCH] Modules/USB - Untested updates to USB mouse support --- KernelLand/Modules/USB/HID/main.c | 78 +++++++-- KernelLand/Modules/USB/HID/mouse.c | 251 ++++++++++++++++++++++++++--- 2 files changed, 296 insertions(+), 33 deletions(-) diff --git a/KernelLand/Modules/USB/HID/main.c b/KernelLand/Modules/USB/HID/main.c index 336609da..68e301e2 100644 --- a/KernelLand/Modules/USB/HID/main.c +++ b/KernelLand/Modules/USB/HID/main.c @@ -13,8 +13,19 @@ #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); } diff --git a/KernelLand/Modules/USB/HID/mouse.c b/KernelLand/Modules/USB/HID/mouse.c index b7737f9d..be015add 100644 --- a/KernelLand/Modules/USB/HID/mouse.c +++ b/KernelLand/Modules/USB/HID/mouse.c @@ -9,59 +9,274 @@ #include #include "hid_reports.h" #include +#include +// === 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); + } } -- 2.20.1