Porting FIFO driver
authorJohn Hodge <[email protected]>
Mon, 28 Sep 2009 13:37:53 +0000 (21:37 +0800)
committerJohn Hodge <[email protected]>
Mon, 28 Sep 2009 13:37:53 +0000 (21:37 +0800)
Kernel/drv/fifo.c [new file with mode: 0644]

diff --git a/Kernel/drv/fifo.c b/Kernel/drv/fifo.c
new file mode 100644 (file)
index 0000000..953bac6
--- /dev/null
@@ -0,0 +1,355 @@
+/* AcessOS
+ * FIFO Pipe Driver
+ */
+#include <common.h>
+#include <modules.h>
+#include <fs_devfs.h>
+
+// === CONSTANTS ===
+#define DEFAULT_RING_SIZE      2048
+#define PF_BLOCKING            1
+
+// === TYPES ===
+typedef struct sPipe {
+       struct sPipe    *Next;
+       char    *Name;
+       tVFS_Node       Node;
+       Uint    Flags;
+        int    ReadPos;
+        int    WritePos;
+        int    BufSize;
+       char    *Buffer;
+} tPipe;
+
+// === PROTOTYPES ===
+ int   FIFO_Install(char **Arguments);
+ int   FIFO_IOCtl(tVFS_Node *Node, int Id, void *Data);
+char   *FIFO_ReadDir(tVFS_Node *Node, int Id);
+tVFS_Node      *FIFO_FindDir(tVFS_Node *Node, char *Filename);
+ int   FIFO_MkNod(tVFS_Node *Node, char *Name, Uint Flags);
+void   FIFO_Close(tVFS_Node *Node);
+ int   FIFO_Relink(tVFS_Node *Node, char *OldName, char *NewName);
+Uint64 FIFO_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
+Uint64 FIFO_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
+tPipe  *FIFO_Int_NewPipe(int Size, char *Name);
+
+// === GLOBALS ===
+MODULE_DEFINE(0, 0x0032, FIFO, FIFO_Install, NULL, NULL);
+tDevFS_Driver  gFIFO_DriverInfo = {
+       NULL, "fifo",
+       {
+       .NumACLs = 1,
+       .ACLs = &gVFS_ACL_EveryoneRW,
+       .Flags = VFS_FFLAG_DIRECTORY,
+       .ReadDir = FIFO_ReadDir,
+       .FindDir = FIFO_FindDir,
+       .MkNod = FIFO_MkNod,
+       .Relink = FIFO_Relink,
+       .IOCtl = FIFO_IOCtl
+       }
+};
+tVFS_Node      gFIFO_AnonNode = {
+       .NumACLs = 1,
+       .ACLs = &gVFS_ACL_EveryoneRW,
+       };
+tPipe  *gFIFO_NamedPipes = NULL;
+
+// === CODE ===
+/**
+ * \fn int FIFO_Install(char **Options)
+ * \brief Installs the FIFO Driver
+ */
+int FIFO_Install(char **Options)
+{
+       DevFS_AddDevice( &gFIFO_DriverInfo );
+       return 0;
+}
+
+/**
+ * \fn int FIFO_IOCtl(tVFS_Node *Node, int Id, void *Data)
+ */
+int FIFO_IOCtl(tVFS_Node *Node, int Id, void *Data)
+{
+       return 0;
+}
+
+/**
+ * \fn char *FIFO_ReadDir(tVFS_Node *Node, int Id)
+ * \brief Reads from the FIFO root
+ */
+char *FIFO_ReadDir(tVFS_Node *Node, int Id)
+{
+       tPipe   *tmp = gFIFO_NamedPipes;
+       // Entry 0 is Anon Pipes
+       if(Id == 0)     return strdup("anon");
+       
+       // Find the id'th node
+       while(--Id && tmp)      tmp = tmp->Next;
+       // If node found, return it
+       if(tmp) return strdup(tmp->Name);
+       // else error return
+       return NULL;
+}
+
+/**
+ * \fn tVFS_Node *FIFO_FindDir(tVFS_Node *Node, char *Filename)
+ * \brief Find a file in the FIFO root
+ * \note Creates an anon pipe if anon is requested
+ */
+tVFS_Node *FIFO_FindDir(tVFS_Node *Node, char *Filename)
+{
+       tPipe   *tmp;
+       if(!Filename)   return NULL;
+       
+       // NULL String Check
+       if(Filename[0] == '\0') return NULL;
+       
+       // Anon Pipe
+       if(Filename[0] == 'a' && Filename[1] == 'n'
+       && Filename[2] == 'o' && Filename[3] == 'n'
+       && Filename[4] == '\0') {
+               tmp = FIFO_Int_NewPipe(DEFAULT_RING_SIZE, "anon");
+               return &tmp->Node;
+       }
+       
+       // Check Named List
+       tmp = gFIFO_NamedPipes;
+       while(tmp)
+       {
+               if(strcmp(tmp->Name, Filename) == 0)
+                       return &tmp->Node;
+               tmp = tmp->Next;
+       }
+       return NULL;
+}
+
+/**
+ * \fn int FIFO_MkNod(tVFS_Node *Node, char *Name, Uint Flags)
+ */
+int FIFO_MkNod(tVFS_Node *Node, char *Name, Uint Flags)
+{
+       return 0;
+}
+
+/**
+ * \fn void FIFO_Close(vfs_node *Node)
+ */
+void FIFO_Close(tVFS_Node *Node)
+{
+       tPipe   *pipe;
+       if(!Node->ImplPtr)      return ;
+       
+       Node->ReferenceCount --;
+       if(Node->ReferenceCount)        return ;
+       
+       pipe = Node->ImplPtr;
+       
+       if(strcmp(pipe->Name, "anon") == 0) {
+               free(Node->ImplPtr);
+               return ;
+       }
+       
+       return ;
+}
+
+/**
+ * \fn int FIFO_Relink(tVFS_Node *Node, char *OldName, char *NewName)
+ * \brief Relink a file (Deletes named pipes)
+ */
+int FIFO_Relink(tVFS_Node *Node, char *OldName, char *NewName)
+{
+       tPipe   *pipe, *tmp;
+       
+       if(Node != &gFIFO_DriverInfo.RootNode)  return 0;
+       
+       // Can't relink anon
+       if(strcmp(OldName, "anon"))     return 0;
+       
+       // Find node
+       for(pipe = gFIFO_NamedPipes;
+               pipe;
+               pipe = pipe->Next)
+       {
+               if(strcmp(pipe->Name, OldName) == 0)
+                       break;
+       }
+       if(!pipe)       return 0;
+       
+       // Relink a named pipe
+       if(NewName) {
+               // Check new name
+               for(tmp = gFIFO_NamedPipes;
+                       tmp;
+                       tmp = tmp->Next)
+               {
+                       if(strcmp(tmp->Name, NewName) == 0)     return 0;
+               }
+               // Create new name
+               free(pipe->Name);
+               pipe->Name = malloc(strlen(NewName)+1);
+               strcpy(pipe->Name, NewName);
+               return 1;
+       }
+       
+       // Unlink the pipe
+       if(Node->ImplPtr) {
+               free(Node->ImplPtr);
+               return 1;
+       }
+       
+       return 0;
+}
+
+/**
+ * \fn Uint64 FIFO_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+ * \brief Read from a fifo pipe
+ */
+Uint64 FIFO_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+{
+       tPipe   *pipe = Node->ImplPtr;
+       Uint    len;
+       Uint    remaining = Length;
+       
+       if(!pipe)       return 0;
+       
+       while(remaining)
+       {
+               // Wait for buffer to fill
+               if(pipe->Flags & PF_BLOCKING)
+                       while(pipe->ReadPos == pipe->WritePos)
+                               Threads_Yield();
+               else
+                       if(pipe->ReadPos == pipe->WritePos)
+                               return 0;
+               
+               // Read buffer
+               if(pipe->WritePos - pipe->ReadPos < remaining)
+                       len = pipe->WritePos - pipe->ReadPos;
+               else
+                       len = remaining;
+               
+               // Check if read overflows buffer
+               if(len > pipe->BufSize - pipe->ReadPos)
+               {
+                       int ofs = pipe->BufSize - pipe->ReadPos;
+                       memcpy(Buffer, &pipe->Buffer[pipe->ReadPos], ofs);
+                       memcpy(Buffer + ofs, &pipe->Buffer, len-ofs);
+               }
+               else
+               {
+                       memcpy(Buffer, &pipe->Buffer[pipe->ReadPos], len);
+               }
+               
+               // Increment read position
+               pipe->ReadPos += len;
+               pipe->ReadPos %= pipe->BufSize;
+               
+               // Decrement Remaining Bytes
+               remaining -= len;
+               // Increment Buffer address
+               Buffer += len;
+       }
+
+       return Length;
+
+}
+
+/**
+ * \fn Uint64 FIFO_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+ * \brief Write to a fifo pipe
+ */
+Uint64 FIFO_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+{
+       tPipe   *pipe = Node->ImplPtr;
+       Uint    len;
+       Uint    remaining = Length;
+       
+       if(!pipe)       return 0;
+       
+       while(remaining)
+       {
+               // Wait for buffer to empty
+               if(pipe->Flags & PF_BLOCKING)
+                       while(pipe->ReadPos == (pipe->WritePos+1)%pipe->BufSize)
+                               Threads_Yield();
+               else
+                       if(pipe->ReadPos == (pipe->WritePos+1)%pipe->BufSize)
+                               return 0;
+               
+               // Write buffer
+               if(pipe->ReadPos - pipe->WritePos < remaining)
+                       len = pipe->ReadPos - pipe->WritePos;
+               else
+                       len = remaining;
+               
+               // Check if write overflows buffer
+               if(len > pipe->BufSize - pipe->WritePos)
+               {
+                       int ofs = pipe->BufSize - pipe->WritePos;
+                       memcpy(&pipe->Buffer[pipe->WritePos], Buffer, ofs);
+                       memcpy(&pipe->Buffer, Buffer + ofs, len-ofs);
+               }
+               else
+               {
+                       memcpy(&pipe->Buffer[pipe->WritePos], Buffer, len);
+               }
+               
+               // Increment read position
+               pipe->WritePos += len;
+               pipe->WritePos %= pipe->BufSize;
+               
+               // Decrement Remaining Bytes
+               remaining -= len;
+               // Increment Buffer address
+               Buffer += len;
+       }
+
+       return Length;
+}
+
+// --- HELPERS ---
+/**
+ * \fn tPipe *FIFO_Int_NewPipe(int Size, char *Name)
+ * \brief Create a new pipe
+ */
+tPipe *FIFO_Int_NewPipe(int Size, char *Name)
+{
+       tPipe   *ret;
+        int    allocsize = sizeof(tPipe) + sizeof(tVFS_ACL) + Size;
+       
+       ret = malloc(allocsize);
+       if(!ret)        return NULL;
+       
+       // Clear Return
+       memset(ret, 0, allocsize);
+       
+       ret->Name = Name;
+       
+       // Allocate Buffer
+       ret->BufSize = Size;
+       ret->Buffer = (void*)( (Uint)ret + sizeof(tPipe) + sizeof(tVFS_ACL) );
+       if(!ret->Buffer) {
+               free(ret);
+               return NULL;
+       }
+       
+       // Set Node
+       ret->Node.Size = 0;
+       ret->Node.ImplPtr = ret;
+       ret->Node.UID = Threads_GetUID();
+       ret->Node.GID = Threads_GetGID();
+       ret->Node.NumACLs = 1;
+       ret->Node.ACLs = (void*)( (Uint)ret + sizeof(tPipe) );
+               ret->Node.ACLs->Group = 0;
+               ret->Node.ACLs->ID = ret->Node.UID;
+               ret->Node.ACLs->Inv = 0;
+               ret->Node.ACLs->Perms = -1;
+       ret->Node.CTime
+               = ret->Node.MTime
+               = ret->Node.ATime = now();
+       ret->Node.Read = FIFO_Read;
+       ret->Node.Write = FIFO_Write;
+       ret->Node.Close = FIFO_Close;
+       
+       return ret;
+}

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