Kernel - Implimenting PTYs (untested, unintegrated)
authorJohn Hodge <[email protected]>
Fri, 17 May 2013 12:26:14 +0000 (20:26 +0800)
committerJohn Hodge <[email protected]>
Fri, 17 May 2013 12:26:14 +0000 (20:26 +0800)
KernelLand/Kernel/Makefile
KernelLand/Kernel/drv/pty.c [new file with mode: 0644]
KernelLand/Kernel/include/drv_pty.h [new file with mode: 0644]
Usermode/Libraries/ld-acess.so_src/include_exp/acess/devices.h
Usermode/Libraries/ld-acess.so_src/include_exp/acess/devices/pty.h [new file with mode: 0644]

index f955068..136706e 100644 (file)
@@ -59,6 +59,7 @@ OBJ += messages.o modules.o syscalls.o system.o
 OBJ += threads.o mutex.o semaphore.o workqueue.o events.o rwlock.o
 OBJ += drv/zero-one.o drv/proc.o drv/fifo.o drv/dgram_pipe.o drv/iocache.o drv/pci.o drv/vpci.o
 OBJ += drv/vterm.o drv/vterm_font.o drv/vterm_vt100.o drv/vterm_output.o drv/vterm_input.o drv/vterm_termbuf.o
+OBJ += drv/pty.o
 OBJ += binary.o bin/elf.o bin/pe.o
 OBJ += vfs/main.o vfs/open.o vfs/acls.o vfs/dir.o vfs/io.o vfs/mount.o
 OBJ += vfs/memfile.o vfs/nodecache.o vfs/handle.o vfs/select.o vfs/mmap.o
diff --git a/KernelLand/Kernel/drv/pty.c b/KernelLand/Kernel/drv/pty.c
new file mode 100644 (file)
index 0000000..6dc8f94
--- /dev/null
@@ -0,0 +1,650 @@
+/*
+ * Acess2 Kernel
+ * - By John Hodge (thePowersGang)
+ *
+ * drv/pty.c
+ * - Pseudo Terminals
+ */
+#include <acess.h>
+#include <vfs.h>
+#include <fs_devfs.h>
+#include <drv_pty.h>
+#include <modules.h>
+#include <rwlock.h>
+#include <mutex.h>
+
+// === CONSTANTS ===
+#define OUTPUT_RINGBUFFER_LEN  1024    // Number of bytes in output queue before client blocks
+#define INPUT_RINGBUFFER_LEN   256     // Number of bytes in input queue before being dropped
+#define INPUT_LINE_LEN 256
+
+// === TYPES ===
+struct sPTY
+{
+       tPTY    *Next;
+       
+       char    *Name;
+        int    NumericName;
+       void    *OutputHandle;
+       tPTY_OutputFcn  OutputFcn;
+
+       struct ptymode  Mode;
+       struct ptydims  Dims;
+
+        int    HasHitEOF;      
+       tMutex  InputMutex;
+        int    InputWritePos;
+        int    InputReadPos;
+       char    InputData[INPUT_RINGBUFFER_LEN];
+       
+        int    LineLength;
+       char    LineData[INPUT_LINE_LEN];
+
+       tMutex  OutputMutex;    
+        int    OutputWritePos;
+        int    OutputReadPos;
+       char    OutputData[OUTPUT_RINGBUFFER_LEN];
+       
+       tVFS_Node       ClientNode;
+       tVFS_Node       ServerNode;
+       tVFS_ACL        OwnerRW;
+       
+       // TODO: Maintain list of client PIDs
+};
+
+// === PROTOTYPES ===
+ int   PTY_Install(char **Arguments);
+ int   PTY_ReadDir(tVFS_Node *Node, int Pos, char Name[FILENAME_MAX]);
+tVFS_Node      *PTY_FindDir(tVFS_Node *Node, const char *Name, Uint Flags);
+
+size_t _rb_write(void *buf, size_t buflen, int *rd, int *wr, const void *data, size_t len);
+size_t _rb_read(void *buf, size_t buflen, int *rd, int *wr, void *data, size_t len);
+size_t PTY_int_WriteInput(tPTY *PTY, const char *Input, size_t Length);
+size_t PTY_int_SendInput(tPTY *PTY, const char *Input, size_t Length);
+// PTY_SendInput
+size_t PTY_ReadClient(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer, Uint Flags);
+size_t PTY_WriteClient(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer, Uint Flags);
+ int   PTY_IOCtlClient(tVFS_Node *Node, int ID, void *Arg);
+void   PTY_ReferenceClient(tVFS_Node *Node);
+void   PTY_CloseClient(tVFS_Node *Node);
+size_t PTY_ReadServer(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer, Uint Flags);
+size_t PTY_WriteServer(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer, Uint Flags);
+ int   PTY_IOCtlServer(tVFS_Node *Node, int ID, void *Arg);
+void   PTY_CloseServer(tVFS_Node *Node);
+
+// === GLOBALS ===
+MODULE_DEFINE(0, 0x100, PTY, PTY_Install, NULL, NULL);
+tVFS_NodeType  gPTY_NodeType_Root = {
+       .TypeName = "PTY-Root",
+       .ReadDir = PTY_ReadDir,
+       .FindDir = PTY_FindDir
+};
+tVFS_NodeType  gPTY_NodeType_Client = {
+       .TypeName = "PTY-Client",
+       .Read = PTY_ReadClient,
+       .Write = PTY_WriteClient,
+       .IOCtl = PTY_IOCtlClient,
+       .Reference = PTY_ReferenceClient,
+       .Close = PTY_CloseClient
+};
+tVFS_NodeType  gPTY_NodeType_Server = {
+       .TypeName = "PTY-Server",
+       .Read = PTY_ReadServer,
+       .Write = PTY_WriteServer,
+       .IOCtl = PTY_IOCtlServer,
+       .Close = PTY_CloseServer
+};
+ int   giPTY_NumCount;
+tRWLock        glPTY_NumPTYs;
+tPTY   *gpPTY_FirstNumPTY;
+ int   giPTY_NamedCount;
+tRWLock        glPTY_NamedPTYs;
+tPTY   *gpPTY_FirstNamedPTY;
+
+// === CODE ===
+int PTY_Install(char **Arguments)
+{
+       return MODULE_ERR_OK;
+}
+
+// --- Management ---
+tPTY *PTY_Create(const char *Name, void *Handle, tPTY_OutputFcn Output)
+{
+       tPTY    **prev_np = NULL;
+       size_t  namelen;
+        int    idx = 1;
+       if( Name && Name[0] )
+       {
+               prev_np = &gpPTY_FirstNamedPTY;
+               
+               // Check the name isn't decimal
+               char *end;
+               if( strtol(Name, &end, 10) != 0 && *end == '\0' ) {
+                       errno = EINVAL;
+                       return NULL;
+               }
+               
+               RWLock_AcquireWrite(&glPTY_NamedPTYs);
+               // Detect duplicates
+               for( tPTY *pty = gpPTY_FirstNamedPTY; pty; prev_np = &pty->Next, pty = pty->Next )
+               {
+                        int    cmp = strcmp(pty->Name, Name);
+                       if( cmp < 0 )
+                               continue;
+                       if( cmp == 0 ) {
+                               RWLock_Release(&glPTY_NamedPTYs);
+                               errno = EEXIST;
+                               return NULL;
+                       }
+                       break;
+               }
+               namelen = strlen(Name);
+               idx = -1;
+       }
+       else
+       {
+               RWLock_AcquireWrite(&glPTY_NumPTYs);
+               // Get a pty ID if Name==NULL
+               prev_np = &gpPTY_FirstNumPTY;
+               for( tPTY *pty = gpPTY_FirstNumPTY; pty; prev_np = &pty->Next, pty = pty->Next )
+               {
+                       if( pty->NumericName > idx )
+                               break;
+                       idx ++;
+               }
+               namelen = 0;
+       }
+       
+       tPTY *ret = calloc(sizeof(tPTY) + namelen + 1, 1);
+       
+       // - List maintainance
+       ret->Next = *prev_np;
+       *prev_np = ret;
+       // - PTY Name (Used by VT)
+       ret->Name = (char*)(ret + 1);
+       if(Name)
+               strcpy(ret->Name, Name);
+       else
+               ret->Name[0] = 0;
+       ret->NumericName = idx;
+       // - Output function and handle (same again)
+       ret->OutputHandle = Handle;
+       ret->OutputFcn = Output;
+       // - Server node
+       ret->ServerNode.ImplPtr = ret;
+       ret->ServerNode.Type = &gPTY_NodeType_Server;
+       ret->ServerNode.UID = Threads_GetUID();
+       ret->ServerNode.GID = Threads_GetGID();
+       ret->ServerNode.NumACLs = 1;
+       ret->ServerNode.ACLs = &ret->OwnerRW;
+       ret->ServerNode.ReferenceCount = (Output ? 1 : 0);      // Prevents a userland open/close killing a kernel pty
+       // - Client node
+       ret->ClientNode.ImplPtr = ret;
+       ret->ClientNode.Type = &gPTY_NodeType_Client;
+       ret->ClientNode.UID = Threads_GetUID();
+       ret->ClientNode.GID = Threads_GetGID();
+       ret->ClientNode.NumACLs = 1;
+       ret->ClientNode.ACLs = &ret->OwnerRW;
+       // - Owner Read-Write ACL
+       ret->OwnerRW.Ent.ID = Threads_GetUID();
+       ret->OwnerRW.Perm.Perms = -1;
+
+       if( Name && Name[0] ) {
+               giPTY_NamedCount ++;
+               RWLock_Release(&glPTY_NamedPTYs);
+       }
+       else {
+               giPTY_NumCount ++;
+               RWLock_Release(&glPTY_NumPTYs); 
+       }
+
+       return ret;
+}
+
+void PTY_SetAttrib(tPTY *PTY, const struct ptydims *Dims, const struct ptymode *Mode, int WasClient)
+{
+       if( Mode ) {
+               PTY->Mode = *Mode;
+               if( !WasClient && !PTY->OutputFcn )
+               {
+                       Log_Warning("PTY", "TODO: Need to stop client output until modeset has been ACKed");
+                       // Block write until acked
+                       // ACK by server doing GETMODE
+               }
+       }
+       if( Dims ) {
+               PTY->Dims = *Dims;
+               if( WasClient ) {
+                       // Poke the server?
+               }
+               else {
+                       // SIGWINSZ to client
+               }
+       }
+}
+
+void PTY_Close(tPTY *PTY)
+{
+       
+}
+
+size_t _rb_write(void *buf, size_t buflen, int *rd, int *wr, const void *data, size_t len)
+{
+       size_t space = (*rd - *wr + buflen) % buflen - 1;
+       len = MIN(space, len);
+       if(*wr + len >= buflen) {
+               size_t prelen = buflen - *wr;
+               memcpy((char*)buf + *wr, data, prelen);
+               memcpy(buf, (char*)data + prelen, len - prelen);
+               *wr = len - prelen;
+       }
+       else {
+               memcpy((char*)buf + *wr, data, len);
+               *wr += len;
+       }
+       return len;
+}
+size_t _rb_read(void *buf, size_t buflen, int *rd, int *wr, void *data, size_t len)
+{
+       size_t space = (*wr - *rd + buflen) % buflen;
+       len = MIN(space, len);
+       if(*rd + len >= buflen) {
+               size_t prelen = buflen - *rd;
+               memcpy(data, (char*)buf + *rd, prelen);
+               memcpy((char*)data + prelen, buf, len - prelen);
+               *rd = len - prelen;
+       }
+       else {
+               memcpy(data, (char*)buf + *rd, len);
+               *rd += len;
+       }
+       return len;
+}
+
+size_t PTY_int_WriteInput(tPTY *PTY, const char *Input, size_t Length)
+{
+       size_t  ret;
+
+       Mutex_Acquire(&PTY->InputMutex);        
+
+       ret = _rb_write(PTY->InputData, INPUT_RINGBUFFER_LEN, &PTY->InputReadPos, &PTY->InputWritePos,
+               Input, Length);
+       
+       Mutex_Release(&PTY->InputMutex);
+
+       VFS_MarkAvaliable(&PTY->ClientNode, 1);
+       if(ret < Length)
+               VFS_MarkFull(&PTY->ServerNode, 1);      
+
+       return ret;
+}
+
+size_t PTY_int_SendInput(tPTY *PTY, const char *Input, size_t Length)
+{
+       size_t  ret = 1, print = 1;
+       
+       // Only counts for text input modes
+       if( (PTY->Mode.OutputMode & PTYOMODE_BUFFMT) == PTYBUFFMT_TEXT )
+               return PTY_int_WriteInput(PTY, Input, Length);
+       // If in raw mode, flush directlr
+       if( (PTY->Mode.InputMode & PTYIMODE_RAW) )
+               return PTY_int_WriteInput(PTY, Input, Length);
+       
+       if( PTY->Mode.InputMode & PTYIMODE_CANON )
+       {
+               const char      char_bs = '\b';
+               switch(Input[0])
+               {
+               case 3: // INTR - ^C
+                       // TODO: Send SIGINT
+                       print = 0;
+                       break;
+               case 4: // EOF - ^D
+                       PTY_int_WriteInput(PTY, PTY->LineData, PTY->LineLength);
+                       PTY->HasHitEOF = (PTY->LineLength == 0);
+                       PTY->LineLength = 0;
+                       print = 0;
+                       break;
+               case 8: // Backspace
+                       if(PTY->LineLength != 0)
+                               PTY->LineLength --;
+                       break;
+               case 'w'-'a':   // Word erase
+                       while(PTY->LineLength != 0 && isalnum(PTY->LineData[--PTY->LineLength]))
+                               PTY_WriteClient(&PTY->ClientNode, 0, 1, &char_bs, 0);
+                       print = 0;
+                       break;
+               case 'u'-'a':   // Kill
+                       while(PTY->LineLength > 0)
+                               PTY_WriteClient(&PTY->ClientNode, 0, 1, &char_bs, 0);
+                       print = 0;
+                       break;
+               case 'v'-'a':
+                       Input ++;
+                       Length --;
+                       ret ++;
+                       goto _default;
+               case '\0':
+               case '\n':
+                       if(PTY->LineLength == INPUT_LINE_LEN) {
+                               PTY_int_WriteInput(PTY, PTY->LineData, PTY->LineLength);
+                               PTY->LineLength = 0;
+                       }
+                       PTY->LineData[PTY->LineLength++] = '\n';
+                       PTY_int_WriteInput(PTY, PTY->LineData, PTY->LineLength);
+                       PTY->LineLength = 0;
+                       break;
+               // TODO: Handle ^[[D and ^[[C for in-line editing, also ^[[1~/^[[4~ (home/end)
+               //case 0x1B:
+               //      break;
+               default:
+               _default:
+                       if(PTY->LineLength == INPUT_LINE_LEN) {
+                               PTY_int_WriteInput(PTY, PTY->LineData, PTY->LineLength);
+                               PTY->LineLength = 0;
+                       }
+                       PTY->LineData[PTY->LineLength++] = Input[0];
+                       break;
+               }
+       }
+       else
+       {
+               ret = PTY_int_WriteInput(PTY, Input, Length);
+       }
+       
+       // Echo if requested
+       if( PTY->Mode.InputMode & PTYIMODE_ECHO )
+       {
+               PTY_WriteClient(&PTY->ClientNode, 0, print, Input, 0);
+       }
+       
+       return ret;
+}
+
+size_t PTY_SendInput(tPTY *PTY, const char *Input, size_t Length)
+{
+       size_t ret = 0;
+       while( ret < Length && !PTY->ClientNode.BufferFull )
+       {
+               // TODO: Detect blocking?
+               ret += PTY_int_SendInput(PTY, Input + ret, Length - ret);
+       }
+       return ret;
+}
+
+// --- VFS ---
+int PTY_ReadDir(tVFS_Node *Node, int Pos, char Name[FILENAME_MAX])
+{
+       tPTY    *pty = NULL;
+       if( Pos < giPTY_NumCount * 2 )
+       {
+               RWLock_AcquireRead(&glPTY_NumPTYs);
+               for( pty = gpPTY_FirstNumPTY; pty; pty = pty->Next )
+               {
+                       if( Pos < 2 )
+                               break;
+                       Pos -= 2;
+               }
+               RWLock_Release(&glPTY_NumPTYs);
+       }
+       else if( Pos < (giPTY_NumCount + giPTY_NamedCount) * 2 )
+       {
+               RWLock_AcquireRead(&glPTY_NamedPTYs);
+               for( pty = gpPTY_FirstNamedPTY; pty; pty = pty->Next )
+               {
+                       if( Pos < 2 )
+                               break;
+                       Pos -= 2;
+               }
+               RWLock_Release(&glPTY_NamedPTYs);
+       }
+       
+
+       if( !pty )
+               return -1;
+       
+       if( pty->Name[0] )
+               snprintf(Name, 255, "%s%c", pty->Name, (Pos == 0 ? 'c' : 's'));
+       else
+               snprintf(Name, 255, "%i%c", pty->NumericName, (Pos == 0 ? 'c' : 's'));
+       return 0;
+}
+
+tVFS_Node *PTY_FindDir(tVFS_Node *Node, const char *Name, Uint Flags)
+{
+       char    *end;
+        int    num = strtol(Name, &end, 10);
+       
+       if( Name[0] == '\0' || Name[1] == '\0' )
+               return NULL;
+       
+       size_t  len = strlen(Name);
+       if( Name[len-1] != 'c' && Name[len-1] != 's' )
+               return NULL;
+        int    isServer = (Name[len-1] != 'c');
+       
+       tPTY    *ret = NULL;
+       if( num && (end[0] == 'c' || end[0] == 's') && end[1] == '\0' )
+       {
+               // Numeric name
+               RWLock_AcquireRead(&glPTY_NumPTYs);
+               for( tPTY *pty = gpPTY_FirstNumPTY; pty; pty = pty->Next )
+               {
+                       if( pty->NumericName > num )
+                               break;
+                       if( pty->NumericName == num ) {
+                               ret = pty;
+                               break;
+                       }
+               }
+               RWLock_Release(&glPTY_NumPTYs);
+       }
+       else
+       {
+               // String name
+               RWLock_AcquireRead(&glPTY_NamedPTYs);
+               for( tPTY *pty = gpPTY_FirstNamedPTY; pty; pty = pty->Next )
+               {
+                       int cmp = strncmp(pty->Name, Name, len-1);
+                       if(cmp > 0)
+                               break;
+                       if(cmp == 0 && pty->Name[len-1] == '\0' ) {
+                               ret = pty;
+                               break;
+                       }
+               }
+               RWLock_Release(&glPTY_NamedPTYs);
+       }
+       if( ret )
+               return (isServer ? &ret->ServerNode : &ret->ClientNode);
+       else
+               return NULL;
+}
+
+//\! Read from the client's input
+size_t PTY_ReadClient(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer, Uint Flags)
+{
+       tPTY *pty = Node->ImplPtr;
+       
+       // Read from flushed queue
+       tTime   timeout_z = 0, *timeout = (Flags & VFS_IOFLAG_NOBLOCK) ? &timeout_z : NULL;
+        int    rv;
+_select:
+       rv = VFS_SelectNode(Node, VFS_SELECT_READ, timeout, "PTY_ReadClient");
+       if(!rv) {
+               errno = (timeout ? EWOULDBLOCK : EINTR);
+               return -1;
+       }
+
+       Mutex_Acquire(&pty->InputMutex);
+       Length = _rb_read(pty->InputData, INPUT_RINGBUFFER_LEN, &pty->InputReadPos, &pty->InputWritePos,
+               Buffer, Length);
+       Mutex_Release(&pty->InputMutex);
+
+       if(Length == 0 && !pty->HasHitEOF) {
+               goto _select;
+       }
+       pty->HasHitEOF = 0;
+
+       return Length;
+}
+
+//\! Write to the client's output
+size_t PTY_WriteClient(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer, Uint Flags)
+{
+       tPTY *pty = Node->ImplPtr;
+       
+       // Write to either FIFO or directly to output function
+       if( pty->OutputFcn )
+       {
+               pty->OutputFcn(pty->OutputHandle, Buffer, Length, &pty->Dims);
+       }
+       else
+       {
+               // Write to output ringbuffer
+               Length = _rb_write(pty->OutputData, OUTPUT_RINGBUFFER_LEN,
+                       &pty->OutputReadPos, &pty->OutputWritePos,
+                       Buffer, Length);
+               VFS_MarkAvaliable(&pty->ServerNode, 1);
+       }
+       
+       return Length;
+}
+
+int PTY_IOCtlClient(tVFS_Node *Node, int ID, void *Data)
+{
+       tPTY    *pty = Node->ImplPtr;
+       struct ptymode  *mode = Data;
+       struct ptydims  *dims = Data;
+       switch(ID)
+       {
+       case DRV_IOCTL_TYPE:    return DRV_TYPE_TERMINAL;
+       case DRV_IOCTL_IDENT:   memcpy(Data, "PTY\0", 4);       return 0;
+       case DRV_IOCTL_VER:     return 0x100;
+       case DRV_IOCTL_LOOKUP:  return 0;
+       
+       case PTY_IOCTL_GETMODE:
+               if( !CheckMem(Data, sizeof(*mode)) ) { errno = EINVAL; return -1; }
+               *mode = pty->Mode;
+               return 0;
+       case PTY_IOCTL_SETMODE:
+               if( !CheckMem(Data, sizeof(*mode)) ) { errno = EINVAL; return -1; }
+               PTY_SetAttrib(pty, NULL, mode, 1);
+               return 0;
+       case PTY_IOCTL_GETDIMS:
+               if( !CheckMem(Data, sizeof(*dims)) ) { errno = EINVAL; return -1; }
+               *dims = pty->Dims;
+               return 0;
+       case PTY_IOCTL_SETDIMS:
+               if( !CheckMem(Data, sizeof(*dims)) ) { errno = EINVAL; return -1; }
+               PTY_SetAttrib(pty, dims, NULL, 1);
+               // Inform the server?
+               return 0;
+       }
+       errno = ENOSYS;
+       return -1;
+}
+
+void PTY_ReferenceClient(tVFS_Node *Node)
+{
+       Node->ReferenceCount ++;
+       // TODO: Add PID to list of client PIDs
+       Log_Notice("PTY", "TODO: List of client PIDs");
+}
+
+void PTY_CloseClient(tVFS_Node *Node)
+{
+       tPTY    *pty = Node->ImplPtr;
+       Node->ReferenceCount --;
+
+       // Remove PID from list
+
+       // Free structure if this was the last open handle
+       if( Node->ReferenceCount == 0 && pty->ServerNode.ReferenceCount == 0 )
+       {
+               // Free the structure! (Should be off the PTY list now)
+               free(pty);
+       }
+}
+
+//\! Read from the client's output
+size_t PTY_ReadServer(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer, Uint Flags)
+{
+       tPTY *pty = Node->ImplPtr;
+
+       // TODO: Prevent two servers fighting over client's output      
+       if( pty->OutputFcn )
+       {
+               // Kernel-land PTYs can't be read from userland
+               return 0;
+       }
+       
+       // Read back from fifo
+       tTime   timeout_z = 0, *timeout = (Flags & VFS_IOFLAG_NOBLOCK) ? &timeout_z : NULL;
+       int rv = VFS_SelectNode(Node, VFS_SELECT_READ, timeout, "PTY_ReadServer");
+       if(!rv) {
+               errno = (timeout ? EWOULDBLOCK : EINTR);
+               return -1;
+       }
+       
+       Length = _rb_read(pty->OutputData, OUTPUT_RINGBUFFER_LEN,
+               &pty->OutputReadPos, &pty->OutputWritePos,
+               Buffer, Length);
+       if( pty->OutputReadPos == pty->OutputWritePos )
+               VFS_MarkAvaliable(Node, 0);
+       VFS_MarkFull(&pty->ClientNode, 0);
+       
+       return Length;
+}
+
+//\! Write to the client's input
+size_t PTY_WriteServer(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer, Uint Flags)
+{
+       // Write to current line buffer, flushing on unknown character or newline
+       // - or line wrap?
+       // Echo back if instructed
+       PTY_SendInput(Node->ImplPtr, Buffer, Length);
+       return -1;
+}
+
+int PTY_IOCtlServer(tVFS_Node *Node, int ID, void *Data)
+{
+       tPTY    *pty = Node->ImplPtr;
+       struct ptymode  *mode = Data;
+       struct ptydims  *dims = Data;
+       switch(ID)
+       {
+       case DRV_IOCTL_TYPE:    return DRV_TYPE_TERMINAL;
+       case DRV_IOCTL_IDENT:   memcpy(Data, "PTY\0", 4);       return 0;
+       case DRV_IOCTL_VER:     return 0x100;
+       case DRV_IOCTL_LOOKUP:  return 0;
+       
+       case PTY_IOCTL_GETMODE:
+               if( !CheckMem(Data, sizeof(*mode)) ) { errno = EINVAL; return -1; }
+               *mode = pty->Mode;
+               // ACK client's SETMODE
+               return 0;
+       case PTY_IOCTL_SETMODE:
+               if( !CheckMem(Data, sizeof(*mode)) ) { errno = EINVAL; return -1; }
+               PTY_SetAttrib(pty, NULL, mode, 0);
+               return 0;
+       case PTY_IOCTL_GETDIMS:
+               if( !CheckMem(Data, sizeof(*dims)) ) { errno = EINVAL; return -1; }
+               *dims = pty->Dims;
+               return 0;
+       case PTY_IOCTL_SETDIMS:
+               if( !CheckMem(Data, sizeof(*dims)) ) { errno = EINVAL; return -1; }
+               PTY_SetAttrib(pty, dims, NULL, 0);
+               break;
+       }
+       errno = ENOSYS;
+       return -1;
+}
+
+void PTY_CloseServer(tVFS_Node *Node)
+{
+       // Dereference node
+       Node->ReferenceCount --;
+       // If reference count == 0, remove from main list and SIGPIPE all clients when they write
+}
+
diff --git a/KernelLand/Kernel/include/drv_pty.h b/KernelLand/Kernel/include/drv_pty.h
new file mode 100644 (file)
index 0000000..1238d92
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Acess2 Kernel
+ * - By John Hodge (thePowersGang)
+ *
+ * drv_pty.h
+ * - Pseudo Terminals
+ */
+#ifndef _KERNEL_DRV_PTY_H_
+#define _KERNEL_DRV_PTY_H_
+
+#include "../../../Usermode/Libraries/ld-acess.so_src/include_exp/acess/devices/pty.h"
+
+typedef struct sPTY    tPTY;
+typedef void   (*tPTY_OutputFcn)(void *Handle, const void *Data, size_t Length, const struct ptydims *Mode);
+
+extern tPTY    *PTY_Create(const char *Name, void *Handle, tPTY_OutputFcn Output);
+extern void    PTY_SetAttrib(tPTY *PTY, const struct ptydims *Dims, const struct ptymode *Mode, int WasClient);
+extern void    PTY_Close(tPTY *PTY);
+extern size_t  PTY_SendInput(tPTY *PTY, const char *InputString, size_t InputLength);
+
+#endif
+
index bfbb625..c154c0b 100644 (file)
@@ -6,10 +6,10 @@
 
 // === COMMON ===
 enum eDrv_Common {
-       DRV_IOCTL_NULL,
        DRV_IOCTL_TYPE,
        DRV_IOCTL_IDENT,
-       DRV_IOCTL_VER
+       DRV_IOCTL_VER,
+       DRV_IOCTL_LOOKUP,
 };
 
 enum eDrv_Types {
diff --git a/Usermode/Libraries/ld-acess.so_src/include_exp/acess/devices/pty.h b/Usermode/Libraries/ld-acess.so_src/include_exp/acess/devices/pty.h
new file mode 100644 (file)
index 0000000..31978f4
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Acess2 User Core
+ * - By John Hodge (thePowersGang)
+ * 
+ * acess/devices/pty.h
+ * - PTY Device type IOCtls
+ */
+#ifndef _ACESS_DEVICES_PTY_H_
+#define _ACESS_DEVICES_PTY_H_
+
+#include "../devices.h"
+
+#define PTYIMODE_CANON 0x001
+#define PTYIMODE_ECHO  0x002
+#define PTYIMODE_RAW   0x004
+
+#define PTYOMODE_BUFFMT        0x003
+#define PTYBUFFMT_TEXT  0x000
+#define PTYBUFFMT_FB    0x001
+#define PTYBUFFMT_2DCMD         0x002
+#define PTYBUFFMT_3DCMD         0x003
+
+struct ptydims
+{
+       short   W;
+       short   H;
+};
+struct ptymode
+{
+       unsigned int    OutputMode;
+       unsigned int    InputMode;
+};
+
+enum
+{
+       PTY_IOCTL_GETMODE = 4,
+       PTY_IOCTL_SETMODE,
+       PTY_IOCTL_GETDIMS,
+       PTY_IOCTL_SETDIMS,
+};
+
+#endif
+

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