Merge branch 'master' of git://git.ucc.asn.au/tpg/acess2
[tpg/acess2.git] / KernelLand / Modules / Input / PS2KbMouse / kb.c
diff --git a/KernelLand/Modules/Input/PS2KbMouse/kb.c b/KernelLand/Modules/Input/PS2KbMouse/kb.c
new file mode 100644 (file)
index 0000000..a121b61
--- /dev/null
@@ -0,0 +1,251 @@
+/*
+ * Acess2
+ * PS2 Keyboard Driver
+ */
+#include <acess.h>
+#include <modules.h>
+#include <fs_devfs.h>
+#include <api_drv_common.h>
+#include <api_drv_keyboard.h>
+#include "kb_kbdus.h"
+
+// === CONSTANTS ===
+#define        KB_BUFFER_SIZE  1024
+#define        USE_KERNEL_MAGIC        1
+
+// === IMPORTS ===
+extern void    Threads_ToggleTrace(int TID);
+extern void    Threads_Dump(void);
+extern void    Heap_Stats(void);
+
+// === PROTOTYPES ===
+ int   KB_Install(char **Arguments);
+void   KB_HandleScancode(Uint8 scancode);
+void   KB_UpdateLEDs(void);
+ int   KB_IOCtl(tVFS_Node *Node, int Id, void *Data);
+
+// === GLOBALS ===
+tVFS_NodeType  gKB_NodeType = {
+       .IOCtl = KB_IOCtl
+};
+tDevFS_Driver  gKB_DevInfo = {
+       NULL, "PS2Keyboard",
+       { .Type = &gKB_NodeType }
+};
+tKeybardCallback       gKB_Callback = NULL;
+Uint32 **gpKB_Map = gpKBDUS;
+Uint8  gbaKB_States[3][256];
+ int   gbKB_ShiftState = 0;
+ int   gbKB_CapsState = 0;
+ int   gbKB_KeyUp = 0;
+ int   giKB_KeyLayer = 0;
+#if USE_KERNEL_MAGIC
+ int   gbKB_MagicState = 0;
+ int   giKB_MagicAddress = 0;
+ int   giKB_MagicAddressPos = 0;
+#endif
+
+// === CODE ===
+/**
+ * \brief Install the keyboard driver
+ */
+int KB_Install(char **Arguments)
+{
+       DevFS_AddDevice( &gKB_DevInfo );
+       //Log("KB_Install: Installed");
+       return MODULE_ERR_OK;
+}
+
+/**
+ * \brief Called on a keyboard IRQ
+ * \param IRQNum       IRQ number (unused)
+ */
+void KB_HandleScancode(Uint8 scancode)
+{
+       Uint32  ch;
+        int    bCaseSwitch = (gbKB_ShiftState != 0) != (gbKB_CapsState != 0);
+
+       //Log_Debug("Keyboard", "scancode = %02x", scancode);
+
+       // Ignore ACKs
+       if(scancode == 0xFA) {
+               // Oh man! This is anarchic (I'm leaving it here to represent
+               // the mess that Acess once was)
+               //kb_lastChar = KB_ACK;
+               return;
+       }
+
+       // Layer +1
+       if(scancode == 0xE0) {
+               giKB_KeyLayer = 1;
+               return;
+       }
+       // Layer +2
+       if(scancode == 0xE1) {
+               giKB_KeyLayer = 2;
+               return;
+       }
+
+       #if KB_ALT_SCANCODES
+       if(scancode == 0xF0)
+       {
+               gbKB_KeyUp = 1;
+               return;
+       }
+       #else
+       if(scancode & 0x80)
+       {
+               scancode &= 0x7F;
+               gbKB_KeyUp = 1;
+       }
+       #endif
+       
+       if( gKB_Callback )
+               gKB_Callback( (giKB_KeyLayer << 8) | scancode | KEY_ACTION_RAWSYM );
+
+       // Translate
+       ch = gpKB_Map[giKB_KeyLayer*2+bCaseSwitch][scancode];
+       // - Unknown characters in the shift layer fall through to lower
+       if(bCaseSwitch && ch == 0)
+               ch = gpKB_Map[giKB_KeyLayer*2][scancode];
+       // Check for unknown key
+       if(!ch)
+       {
+               if(!gbKB_KeyUp)
+                       Log_Warning("Keyboard", "UNK %i %x", giKB_KeyLayer, scancode);
+//             return ;
+               // Can pass through to ensure each raw message has a up/down with it
+       }
+
+       // Key Up?
+       if (gbKB_KeyUp)
+       {
+               gbKB_KeyUp = 0;
+               gbaKB_States[giKB_KeyLayer][scancode] = 0;      // Unset key state flag
+
+               #if USE_KERNEL_MAGIC
+               if(ch == KEY_LCTRL)     gbKB_MagicState &= ~1;
+               if(ch == KEY_LALT)      gbKB_MagicState &= ~2;
+               #endif
+
+               if(ch == KEY_LSHIFT)    gbKB_ShiftState &= ~1;
+               if(ch == KEY_RSHIFT)    gbKB_ShiftState &= ~2;
+
+               // Call callback
+               if(gKB_Callback)        gKB_Callback( ch | KEY_ACTION_RELEASE );
+
+               // Reset Layer
+               giKB_KeyLayer = 0;
+               return;
+       }
+
+       // Refire?
+       if( gbaKB_States[giKB_KeyLayer][scancode] == 1 )
+       {
+               if(gKB_Callback)        gKB_Callback(ch | KEY_ACTION_REFIRE);
+               giKB_KeyLayer = 0;
+               return ;
+       }
+
+       // Set the bit relating to the key
+       gbaKB_States[giKB_KeyLayer][scancode] = 1;
+       // Set shift key bits
+       if(ch == KEY_LSHIFT)    gbKB_ShiftState |= 1;
+       if(ch == KEY_RSHIFT)    gbKB_ShiftState |= 2;
+
+       // Check for Caps Lock
+       if(ch == KEY_CAPSLOCK) {
+               gbKB_CapsState = !gbKB_CapsState;
+               KB_UpdateLEDs();
+       }
+
+       // --- Check for Kernel Magic Combos
+       #if USE_KERNEL_MAGIC
+       if(ch == KEY_LCTRL) {
+               gbKB_MagicState |= 1;
+               //Log_Log("Keyboard", "Kernel Magic LCTRL Down\n");
+       }
+       if(ch == KEY_LALT) {
+               gbKB_MagicState |= 2;
+               //Log_Log("Keyboard", "Kernel Magic LALT Down\n");
+       }
+       if(gbKB_MagicState == 3)
+       {
+               switch(ch)
+               {
+               case '0':       case '1':       case '2':       case '3':
+               case '4':       case '5':       case '6':       case '7':
+               case '8':       case '9':       case 'a':       case 'b':
+               case 'c':       case 'd':       case 'e':       case 'f':
+                       {
+                       char    str[4] = {'0', 'x', ch, 0};
+                       if(giKB_MagicAddressPos == BITS/4)      return;
+                       giKB_MagicAddress |= atoi(str) << giKB_MagicAddressPos;
+                       giKB_MagicAddressPos ++;
+                       }
+                       return;
+               
+               // Instruction Tracing
+               case 't':
+                       Log("Toggle instruction tracing on %i\n", giKB_MagicAddress);
+                       Threads_ToggleTrace( giKB_MagicAddress );
+                       giKB_MagicAddress = 0;  giKB_MagicAddressPos = 0;
+                       return;
+               
+               // Thread List Dump
+               case 'p':       Threads_Dump(); return;
+               // Heap Statistics
+               case 'h':       Heap_Stats();   return;
+               // Dump Structure
+               case 's':       return;
+               }
+       }
+       #endif
+
+       if(gKB_Callback)
+               gKB_Callback(ch | KEY_ACTION_PRESS);
+
+       // Reset Layer
+       giKB_KeyLayer = 0;
+}
+
+/**
+ * \fn void KB_UpdateLEDs(void)
+ * \brief Updates the status of the keyboard LEDs
+ */
+void KB_UpdateLEDs(void)
+{
+       Uint8   leds;
+
+       leds = (gbKB_CapsState ? 4 : 0);
+
+       // TODO: Update LEDS
+       Log_Warning("Keyboard", "TODO: Update LEDs");
+}
+
+static const char      *csaIOCTL_NAMES[] = {DRV_IOCTLNAMES, DRV_KEYBAORD_IOCTLNAMES, NULL};
+
+/**
+ * \fn int KB_IOCtl(tVFS_Node *Node, int Id, void *Data)
+ * \brief Calls an IOCtl Command
+ */
+int KB_IOCtl(tVFS_Node *Node, int Id, void *Data)
+{
+       switch(Id)
+       {
+       BASE_IOCTLS(DRV_TYPE_KEYBOARD, "KB", 0x100, csaIOCTL_NAMES);
+       
+       // Sets the Keyboard Callback
+       case KB_IOCTL_SETCALLBACK:
+               // Sanity Check
+               if((Uint)Data < KERNEL_BASE)    return 0;
+               // Can only be set once
+               if(gKB_Callback != NULL)        return 0;
+               // Set Callback
+               gKB_Callback = Data;
+               return 1;
+
+       default:
+               return 0;
+       }
+}

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