From: John Hodge Date: Mon, 28 Sep 2009 13:37:53 +0000 (+0800) Subject: Porting FIFO driver X-Git-Tag: rel0.06~407 X-Git-Url: https://git.ucc.asn.au/?a=commitdiff_plain;h=473c245f818c32553109e1a5d3f8f3be43665cf4;p=tpg%2Facess2.git Porting FIFO driver --- diff --git a/Kernel/drv/fifo.c b/Kernel/drv/fifo.c new file mode 100644 index 00000000..953bac6a --- /dev/null +++ b/Kernel/drv/fifo.c @@ -0,0 +1,355 @@ +/* AcessOS + * FIFO Pipe Driver + */ +#include +#include +#include + +// === 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; +}