3 * - By John Hodge (thePowersGang)
12 #include <semaphore.h>
13 #include <memfs_helpers.h>
16 #define DEFAULT_RING_SIZE 2048
22 tMemFS_FileHdr FileHdr;
32 int FIFO_Install(char **Arguments);
33 int FIFO_IOCtl(tVFS_Node *Node, int Id, void *Data);
34 int FIFO_ReadDir(tVFS_Node *Node, int Id, char Dest[FILENAME_MAX]);
35 tVFS_Node *FIFO_FindDir(tVFS_Node *Node, const char *Filename, Uint Flags);
36 tVFS_Node *FIFO_MkNod(tVFS_Node *Node, const char *Name, Uint Flags);
37 void FIFO_Reference(tVFS_Node *Node);
38 void FIFO_Close(tVFS_Node *Node);
39 int FIFO_Unlink(tVFS_Node *Node, const char *OldName);
40 size_t FIFO_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer, Uint Flags);
41 size_t FIFO_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer, Uint Flags);
42 tPipe *FIFO_Int_NewPipe(int Size, const char *Name);
45 MODULE_DEFINE(0, 0x0032, FIFO, FIFO_Install, NULL, NULL);
46 tMemFS_DirHdr gFIFO_RootDir = {
47 .FileHdr = { .Name = "FIFO" },
49 tVFS_NodeType gFIFO_DirNodeType = {
50 .TypeName = "FIFO Dir Node",
51 .ReadDir = FIFO_ReadDir,
52 .FindDir = FIFO_FindDir,
54 .Unlink = FIFO_Unlink,
57 tVFS_NodeType gFIFO_PipeNodeType = {
58 .TypeName = "FIFO Pipe Node",
62 .Reference = FIFO_Reference
64 tDevFS_Driver gFIFO_DriverInfo = {
69 .ACLs = &gVFS_ACL_EveryoneRW,
70 .Flags = VFS_FFLAG_DIRECTORY,
71 .Type = &gFIFO_DirNodeType
74 tVFS_Node gFIFO_AnonNode = {
76 .ACLs = &gVFS_ACL_EveryoneRW,
81 * \fn int FIFO_Install(char **Options)
82 * \brief Installs the FIFO Driver
84 int FIFO_Install(char **Options)
86 MemFS_InitDir( &gFIFO_RootDir );
87 DevFS_AddDevice( &gFIFO_DriverInfo );
92 * \fn int FIFO_IOCtl(tVFS_Node *Node, int Id, void *Data)
94 int FIFO_IOCtl(tVFS_Node *Node, int Id, void *Data)
100 * \fn char *FIFO_ReadDir(tVFS_Node *Node, int Id)
101 * \brief Reads from the FIFO root
103 int FIFO_ReadDir(tVFS_Node *Node, int Id, char Dest[FILENAME_MAX])
105 // Entry 0 is Anon Pipes
108 strcpy(Dest, "anon");
112 return MemFS_ReadDir(&gFIFO_RootDir, Id-1, Dest);
116 * \fn tVFS_Node *FIFO_FindDir(tVFS_Node *Node, const char *Filename)
117 * \brief Find a file in the FIFO root
118 * \note Creates an anon pipe if anon is requested
120 tVFS_Node *FIFO_FindDir(tVFS_Node *Node, const char *Filename, Uint Flags)
122 ASSERTR(Filename, NULL);
123 ASSERTR(Filename[0], NULL);
126 if( strcmp(Filename, "anon") == 0 )
128 if( Flags & VFS_FDIRFLAG_STAT ) {
129 //return &gFIFI_TemplateAnonNode;
131 tPipe *ret = FIFO_Int_NewPipe(DEFAULT_RING_SIZE, "anon");
136 tPipe *ret = (tPipe*)MemFS_FindDir(&gFIFO_RootDir, Filename);
143 * \fn int FIFO_MkNod(tVFS_Node *Node, const char *Name, Uint Flags)
145 tVFS_Node *FIFO_MkNod(tVFS_Node *Node, const char *Name, Uint Flags)
152 * \brief Delete a pipe
154 int FIFO_Unlink(tVFS_Node *Node, const char *OldName)
156 if(Node != &gFIFO_DriverInfo.RootNode) return 0;
159 if(strcmp(OldName, "anon")) return 0;
162 tPipe* pipe = (tPipe*)MemFS_Remove(&gFIFO_RootDir, OldName);
169 void FIFO_Reference(tVFS_Node *Node)
171 if(!Node->ImplPtr) return ;
173 Node->ReferenceCount ++;
177 * \fn void FIFO_Close(tVFS_Node *Node)
178 * \brief Close a FIFO end
180 void FIFO_Close(tVFS_Node *Node)
182 if(!Node->ImplPtr) return ;
184 Node->ReferenceCount --;
185 if(Node->ReferenceCount) return ;
187 tPipe *pipe = Node->ImplPtr;
189 if(strcmp(pipe->FileHdr.Name, "anon") == 0)
191 Log_Debug("FIFO", "Pipe %p closed", pipe);
200 * \brief Read from a fifo pipe
202 size_t FIFO_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer, Uint Flags)
204 tPipe *pipe = Node->ImplPtr;
206 Uint remaining = Length;
210 ENTER("pNode XOffset xLength pBuffer", Node, Offset, Length, Buffer);
214 // Wait for buffer to fill
215 if( (pipe->Flags & PF_BLOCKING) && !(Flags & VFS_IOFLAG_NOBLOCK) )
217 if( pipe->ReadPos == pipe->WritePos )
218 VFS_SelectNode(Node, VFS_SELECT_READ, NULL, "FIFO_Read");
223 if(pipe->ReadPos == pipe->WritePos)
225 VFS_MarkAvaliable(Node, 0);
232 if( pipe->ReadPos < pipe->WritePos )
234 int avail_bytes = pipe->WritePos - pipe->ReadPos;
235 if( avail_bytes < remaining ) len = avail_bytes;
239 int avail_bytes = pipe->WritePos + pipe->BufSize - pipe->ReadPos;
240 if( avail_bytes < remaining ) len = avail_bytes;
243 LOG("len = %i, remaining = %i", len, remaining);
245 // Check if read overflows buffer
246 if(len > pipe->BufSize - pipe->ReadPos)
248 int ofs = pipe->BufSize - pipe->ReadPos;
249 memcpy(Buffer, &pipe->Buffer[pipe->ReadPos], ofs);
250 memcpy((Uint8*)Buffer + ofs, &pipe->Buffer, len-ofs);
254 memcpy(Buffer, &pipe->Buffer[pipe->ReadPos], len);
257 // Increment read position
258 pipe->ReadPos += len;
259 pipe->ReadPos %= pipe->BufSize;
262 if( pipe->ReadPos == pipe->WritePos ) {
263 LOG("%i == %i, marking none to read", pipe->ReadPos, pipe->WritePos);
264 VFS_MarkAvaliable(Node, 0);
266 VFS_MarkFull(Node, 0); // Buffer can't still be full
268 // Decrement Remaining Bytes
270 // Increment Buffer address
271 Buffer = (Uint8*)Buffer + len;
273 // TODO: Option to read differently
284 * \brief Write to a fifo pipe
286 size_t FIFO_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer, Uint Flags)
288 tPipe *pipe = Node->ImplPtr;
290 Uint remaining = Length;
294 ENTER("pNode XOffset xLength pBuffer", Node, Offset, Length, Buffer);
298 // Wait for buffer to empty
299 if( (pipe->Flags & PF_BLOCKING) && !(Flags & VFS_IOFLAG_NOBLOCK) )
301 if( pipe->ReadPos == (pipe->WritePos+1)%pipe->BufSize ) {
302 LOG("Blocking write on FIFO");
303 VFS_SelectNode(Node, VFS_SELECT_WRITE, NULL, "FIFO_Write");
307 if( pipe->ReadPos > pipe->WritePos )
309 int rem_space = pipe->ReadPos - pipe->WritePos;
310 if(rem_space < remaining) len = rem_space;
314 int rem_space = pipe->ReadPos + pipe->BufSize - pipe->WritePos;
315 if(rem_space < remaining) len = rem_space;
320 if(pipe->ReadPos == (pipe->WritePos+1)%pipe->BufSize)
326 if(pipe->ReadPos - pipe->WritePos < remaining)
327 len = pipe->ReadPos - pipe->WritePos;
332 // Check if write overflows buffer
333 if(len > pipe->BufSize - pipe->WritePos)
335 int ofs = pipe->BufSize - pipe->WritePos;
336 LOG("pipe->Buffer = %p, pipe->WritePos = %i, ofs=%i, len=%i",
337 pipe->Buffer, pipe->WritePos, ofs, len);
338 memcpy(&pipe->Buffer[pipe->WritePos], Buffer, ofs);
339 memcpy(&pipe->Buffer[0], (Uint8*)Buffer + ofs, len-ofs);
343 LOG("pipe->Buffer = %p, pipe->WritePos = %i", pipe->Buffer, pipe->WritePos);
344 memcpy(&pipe->Buffer[pipe->WritePos], Buffer, len);
347 // Increment read position
348 pipe->WritePos += len;
349 pipe->WritePos %= pipe->BufSize;
352 if( pipe->ReadPos == pipe->WritePos ) {
353 LOG("Buffer is full");
354 VFS_MarkFull(Node, 1); // Buffer full
356 VFS_MarkAvaliable(Node, 1);
358 // Decrement Remaining Bytes
360 // Increment Buffer address
361 Buffer = (Uint8*)Buffer + len;
370 * \fn tPipe *FIFO_Int_NewPipe(int Size, const char *Name)
371 * \brief Create a new pipe
373 tPipe *FIFO_Int_NewPipe(int Size, const char *Name)
376 int namelen = strlen(Name) + 1;
377 int allocsize = sizeof(tPipe) + sizeof(tVFS_ACL) + Size + namelen;
379 ENTER("iSize sName", Size, Name);
381 ret = calloc(1, allocsize);
382 if(!ret) LEAVE_RET('n', NULL);
385 ret->Flags = PF_BLOCKING;
389 ret->Buffer = (void*)( (Uint)ret + sizeof(tPipe) + sizeof(tVFS_ACL) );
391 // Set name (and FIFO name)
392 ret->FileHdr.Name = ret->Buffer + Size;
393 strcpy((char*)ret->FileHdr.Name, Name);
396 ret->Node.ReferenceCount = 1;
398 ret->Node.ImplPtr = ret;
399 ret->Node.UID = Threads_GetUID();
400 ret->Node.GID = Threads_GetGID();
401 ret->Node.NumACLs = 1;
402 ret->Node.ACLs = (void*)( (Uint)ret + sizeof(tPipe) );
403 ret->Node.ACLs->Ent.Group = 0;
404 ret->Node.ACLs->Ent.ID = ret->Node.UID;
405 ret->Node.ACLs->Perm.Inv = 0;
406 ret->Node.ACLs->Perm.Perms = -1;
409 = ret->Node.ATime = now();
410 ret->Node.Type = &gFIFO_PipeNodeType;