3 * - By John Hodge (thePowersGang)
12 #include <semaphore.h>
15 #define DEFAULT_RING_SIZE 2048
19 typedef struct sPipe {
31 int FIFO_Install(char **Arguments);
32 int FIFO_IOCtl(tVFS_Node *Node, int Id, void *Data);
33 int FIFO_ReadDir(tVFS_Node *Node, int Id, char Dest[FILENAME_MAX]);
34 tVFS_Node *FIFO_FindDir(tVFS_Node *Node, const char *Filename, Uint Flags);
35 tVFS_Node *FIFO_MkNod(tVFS_Node *Node, const char *Name, Uint Flags);
36 void FIFO_Reference(tVFS_Node *Node);
37 void FIFO_Close(tVFS_Node *Node);
38 int FIFO_Unlink(tVFS_Node *Node, const char *OldName);
39 size_t FIFO_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer, Uint Flags);
40 size_t FIFO_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer, Uint Flags);
41 tPipe *FIFO_Int_NewPipe(int Size, const char *Name);
44 MODULE_DEFINE(0, 0x0032, FIFO, FIFO_Install, NULL, NULL);
45 tVFS_NodeType gFIFO_DirNodeType = {
46 .TypeName = "FIFO Dir Node",
47 .ReadDir = FIFO_ReadDir,
48 .FindDir = FIFO_FindDir,
50 .Unlink = FIFO_Unlink,
53 tVFS_NodeType gFIFO_PipeNodeType = {
54 .TypeName = "FIFO Pipe Node",
58 .Reference = FIFO_Reference
60 tDevFS_Driver gFIFO_DriverInfo = {
65 .ACLs = &gVFS_ACL_EveryoneRW,
66 .Flags = VFS_FFLAG_DIRECTORY,
67 .Type = &gFIFO_DirNodeType
70 tVFS_Node gFIFO_AnonNode = {
72 .ACLs = &gVFS_ACL_EveryoneRW,
74 tPipe *gFIFO_NamedPipes = NULL;
78 * \fn int FIFO_Install(char **Options)
79 * \brief Installs the FIFO Driver
81 int FIFO_Install(char **Options)
83 DevFS_AddDevice( &gFIFO_DriverInfo );
88 * \fn int FIFO_IOCtl(tVFS_Node *Node, int Id, void *Data)
90 int FIFO_IOCtl(tVFS_Node *Node, int Id, void *Data)
96 * \fn char *FIFO_ReadDir(tVFS_Node *Node, int Id)
97 * \brief Reads from the FIFO root
99 int FIFO_ReadDir(tVFS_Node *Node, int Id, char Dest[FILENAME_MAX])
101 tPipe *tmp = gFIFO_NamedPipes;
103 // Entry 0 is Anon Pipes
105 strcpy(Dest, "anon");
109 // Find the id'th node
110 while(--Id && tmp) tmp = tmp->Next;
111 // If the list ended, error return
115 strncpy(Dest, tmp->Name, FILENAME_MAX);
120 * \fn tVFS_Node *FIFO_FindDir(tVFS_Node *Node, const char *Filename)
121 * \brief Find a file in the FIFO root
122 * \note Creates an anon pipe if anon is requested
124 tVFS_Node *FIFO_FindDir(tVFS_Node *Node, const char *Filename, Uint Flags)
127 if(!Filename) return NULL;
130 if(Filename[0] == '\0') return NULL;
133 if( strcmp(Filename, "anon") == 0 )
135 if( Flags & VFS_FDIRFLAG_STAT ) {
136 //return &gFIFI_TemplateAnonNode;
138 tmp = FIFO_Int_NewPipe(DEFAULT_RING_SIZE, "anon");
143 tmp = gFIFO_NamedPipes;
146 if(strcmp(tmp->Name, Filename) == 0)
154 * \fn int FIFO_MkNod(tVFS_Node *Node, const char *Name, Uint Flags)
156 tVFS_Node *FIFO_MkNod(tVFS_Node *Node, const char *Name, Uint Flags)
161 void FIFO_Reference(tVFS_Node *Node)
163 if(!Node->ImplPtr) return ;
165 Node->ReferenceCount ++;
169 * \fn void FIFO_Close(tVFS_Node *Node)
170 * \brief Close a FIFO end
172 void FIFO_Close(tVFS_Node *Node)
175 if(!Node->ImplPtr) return ;
177 Node->ReferenceCount --;
178 if(Node->ReferenceCount) return ;
180 pipe = Node->ImplPtr;
182 if(strcmp(pipe->Name, "anon") == 0) {
183 Log_Debug("FIFO", "Pipe %p closed", Node->ImplPtr);
192 * \brief Delete a pipe
194 int FIFO_Unlink(tVFS_Node *Node, const char *OldName)
198 if(Node != &gFIFO_DriverInfo.RootNode) return 0;
201 if(strcmp(OldName, "anon")) return 0;
204 for(pipe = gFIFO_NamedPipes;
208 if(strcmp(pipe->Name, OldName) == 0)
223 * \brief Read from a fifo pipe
225 size_t FIFO_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer, Uint Flags)
227 tPipe *pipe = Node->ImplPtr;
229 Uint remaining = Length;
233 ENTER("pNode XOffset xLength pBuffer", Node, Offset, Length, Buffer);
237 // Wait for buffer to fill
238 if( (pipe->Flags & PF_BLOCKING) && !(Flags & VFS_IOFLAG_NOBLOCK) )
240 if( pipe->ReadPos == pipe->WritePos )
241 VFS_SelectNode(Node, VFS_SELECT_READ, NULL, "FIFO_Read");
246 if(pipe->ReadPos == pipe->WritePos)
248 VFS_MarkAvaliable(Node, 0);
255 if( pipe->ReadPos < pipe->WritePos )
257 int avail_bytes = pipe->WritePos - pipe->ReadPos;
258 if( avail_bytes < remaining ) len = avail_bytes;
262 int avail_bytes = pipe->WritePos + pipe->BufSize - pipe->ReadPos;
263 if( avail_bytes < remaining ) len = avail_bytes;
266 LOG("len = %i, remaining = %i", len, remaining);
268 // Check if read overflows buffer
269 if(len > pipe->BufSize - pipe->ReadPos)
271 int ofs = pipe->BufSize - pipe->ReadPos;
272 memcpy(Buffer, &pipe->Buffer[pipe->ReadPos], ofs);
273 memcpy((Uint8*)Buffer + ofs, &pipe->Buffer, len-ofs);
277 memcpy(Buffer, &pipe->Buffer[pipe->ReadPos], len);
280 // Increment read position
281 pipe->ReadPos += len;
282 pipe->ReadPos %= pipe->BufSize;
285 if( pipe->ReadPos == pipe->WritePos ) {
286 LOG("%i == %i, marking none to read", pipe->ReadPos, pipe->WritePos);
287 VFS_MarkAvaliable(Node, 0);
289 VFS_MarkFull(Node, 0); // Buffer can't still be full
291 // Decrement Remaining Bytes
293 // Increment Buffer address
294 Buffer = (Uint8*)Buffer + len;
296 // TODO: Option to read differently
307 * \brief Write to a fifo pipe
309 size_t FIFO_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer, Uint Flags)
311 tPipe *pipe = Node->ImplPtr;
313 Uint remaining = Length;
317 ENTER("pNode XOffset xLength pBuffer", Node, Offset, Length, Buffer);
321 // Wait for buffer to empty
322 if( (pipe->Flags & PF_BLOCKING) && !(Flags & VFS_IOFLAG_NOBLOCK) )
324 if( pipe->ReadPos == (pipe->WritePos+1)%pipe->BufSize ) {
325 LOG("Blocking write on FIFO");
326 VFS_SelectNode(Node, VFS_SELECT_WRITE, NULL, "FIFO_Write");
330 if( pipe->ReadPos > pipe->WritePos )
332 int rem_space = pipe->ReadPos - pipe->WritePos;
333 if(rem_space < remaining) len = rem_space;
337 int rem_space = pipe->ReadPos + pipe->BufSize - pipe->WritePos;
338 if(rem_space < remaining) len = rem_space;
343 if(pipe->ReadPos == (pipe->WritePos+1)%pipe->BufSize)
349 if(pipe->ReadPos - pipe->WritePos < remaining)
350 len = pipe->ReadPos - pipe->WritePos;
355 // Check if write overflows buffer
356 if(len > pipe->BufSize - pipe->WritePos)
358 int ofs = pipe->BufSize - pipe->WritePos;
359 LOG("pipe->Buffer = %p, pipe->WritePos = %i, ofs=%i, len=%i",
360 pipe->Buffer, pipe->WritePos, ofs, len);
361 memcpy(&pipe->Buffer[pipe->WritePos], Buffer, ofs);
362 memcpy(&pipe->Buffer[0], (Uint8*)Buffer + ofs, len-ofs);
366 LOG("pipe->Buffer = %p, pipe->WritePos = %i", pipe->Buffer, pipe->WritePos);
367 memcpy(&pipe->Buffer[pipe->WritePos], Buffer, len);
370 // Increment read position
371 pipe->WritePos += len;
372 pipe->WritePos %= pipe->BufSize;
375 if( pipe->ReadPos == pipe->WritePos ) {
376 LOG("Buffer is full");
377 VFS_MarkFull(Node, 1); // Buffer full
379 VFS_MarkAvaliable(Node, 1);
381 // Decrement Remaining Bytes
383 // Increment Buffer address
384 Buffer = (Uint8*)Buffer + len;
393 * \fn tPipe *FIFO_Int_NewPipe(int Size, const char *Name)
394 * \brief Create a new pipe
396 tPipe *FIFO_Int_NewPipe(int Size, const char *Name)
399 int namelen = strlen(Name) + 1;
400 int allocsize = sizeof(tPipe) + sizeof(tVFS_ACL) + Size + namelen;
402 ENTER("iSize sName", Size, Name);
404 ret = calloc(1, allocsize);
405 if(!ret) LEAVE_RET('n', NULL);
408 ret->Flags = PF_BLOCKING;
412 ret->Buffer = (void*)( (Uint)ret + sizeof(tPipe) + sizeof(tVFS_ACL) );
414 // Set name (and FIFO name)
415 ret->Name = ret->Buffer + Size;
416 strcpy(ret->Name, Name);
417 // - Start empty, max of `Size`
418 //Semaphore_Init( &ret->Semaphore, 0, Size, "FIFO", ret->Name );
421 ret->Node.ReferenceCount = 1;
423 ret->Node.ImplPtr = ret;
424 ret->Node.UID = Threads_GetUID();
425 ret->Node.GID = Threads_GetGID();
426 ret->Node.NumACLs = 1;
427 ret->Node.ACLs = (void*)( (Uint)ret + sizeof(tPipe) );
428 ret->Node.ACLs->Ent.Group = 0;
429 ret->Node.ACLs->Ent.ID = ret->Node.UID;
430 ret->Node.ACLs->Perm.Inv = 0;
431 ret->Node.ACLs->Perm.Perms = -1;
434 = ret->Node.ATime = now();
435 ret->Node.Type = &gFIFO_PipeNodeType;