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);
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);
40 size_t FIFO_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer);
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)
127 if(!Filename) return NULL;
130 if(Filename[0] == '\0') return NULL;
133 if( strcmp(Filename, "anon") == 0 )
135 tmp = FIFO_Int_NewPipe(DEFAULT_RING_SIZE, "anon");
140 tmp = gFIFO_NamedPipes;
143 if(strcmp(tmp->Name, Filename) == 0)
151 * \fn int FIFO_MkNod(tVFS_Node *Node, const char *Name, Uint Flags)
153 tVFS_Node *FIFO_MkNod(tVFS_Node *Node, const char *Name, Uint Flags)
158 void FIFO_Reference(tVFS_Node *Node)
160 if(!Node->ImplPtr) return ;
162 Node->ReferenceCount ++;
166 * \fn void FIFO_Close(tVFS_Node *Node)
167 * \brief Close a FIFO end
169 void FIFO_Close(tVFS_Node *Node)
172 if(!Node->ImplPtr) return ;
174 Node->ReferenceCount --;
175 if(Node->ReferenceCount) return ;
177 pipe = Node->ImplPtr;
179 if(strcmp(pipe->Name, "anon") == 0) {
180 Log_Debug("FIFO", "Pipe %p closed", Node->ImplPtr);
189 * \brief Delete a pipe
191 int FIFO_Unlink(tVFS_Node *Node, const char *OldName)
195 if(Node != &gFIFO_DriverInfo.RootNode) return 0;
198 if(strcmp(OldName, "anon")) return 0;
201 for(pipe = gFIFO_NamedPipes;
205 if(strcmp(pipe->Name, OldName) == 0)
220 * \brief Read from a fifo pipe
222 size_t FIFO_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer)
224 tPipe *pipe = Node->ImplPtr;
226 Uint remaining = Length;
230 ENTER("pNode XOffset xLength pBuffer", Node, Offset, Length, Buffer);
234 // Wait for buffer to fill
235 if(pipe->Flags & PF_BLOCKING)
237 if( pipe->ReadPos == pipe->WritePos )
238 VFS_SelectNode(Node, VFS_SELECT_READ, NULL, "FIFO_Read");
243 if(pipe->ReadPos == pipe->WritePos)
245 VFS_MarkAvaliable(Node, 0);
252 if( pipe->ReadPos < pipe->WritePos )
254 int avail_bytes = pipe->WritePos - pipe->ReadPos;
255 if( avail_bytes < remaining ) len = avail_bytes;
259 int avail_bytes = pipe->WritePos + pipe->BufSize - pipe->ReadPos;
260 if( avail_bytes < remaining ) len = avail_bytes;
263 LOG("len = %i, remaining = %i", len, remaining);
265 // Check if read overflows buffer
266 if(len > pipe->BufSize - pipe->ReadPos)
268 int ofs = pipe->BufSize - pipe->ReadPos;
269 memcpy(Buffer, &pipe->Buffer[pipe->ReadPos], ofs);
270 memcpy((Uint8*)Buffer + ofs, &pipe->Buffer, len-ofs);
274 memcpy(Buffer, &pipe->Buffer[pipe->ReadPos], len);
277 // Increment read position
278 pipe->ReadPos += len;
279 pipe->ReadPos %= pipe->BufSize;
282 if( pipe->ReadPos == pipe->WritePos ) {
283 VFS_MarkAvaliable(Node, 0);
285 VFS_MarkFull(Node, 0); // Buffer can't still be full
287 // Decrement Remaining Bytes
289 // Increment Buffer address
290 Buffer = (Uint8*)Buffer + len;
292 // TODO: Option to read differently
303 * \brief Write to a fifo pipe
305 size_t FIFO_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer)
307 tPipe *pipe = Node->ImplPtr;
309 Uint remaining = Length;
313 ENTER("pNode XOffset xLength pBuffer", Node, Offset, Length, Buffer);
317 // Wait for buffer to empty
318 if(pipe->Flags & PF_BLOCKING) {
319 if( pipe->ReadPos == (pipe->WritePos+1)%pipe->BufSize )
320 VFS_SelectNode(Node, VFS_SELECT_WRITE, NULL, "FIFO_Write");
323 if( pipe->ReadPos > pipe->WritePos )
325 int rem_space = pipe->ReadPos - pipe->WritePos;
326 if(rem_space < remaining) len = rem_space;
330 int rem_space = pipe->ReadPos + pipe->BufSize - pipe->WritePos;
331 if(rem_space < remaining) len = rem_space;
336 if(pipe->ReadPos == (pipe->WritePos+1)%pipe->BufSize)
342 if(pipe->ReadPos - pipe->WritePos < remaining)
343 len = pipe->ReadPos - pipe->WritePos;
348 // Check if write overflows buffer
349 if(len > pipe->BufSize - pipe->WritePos)
351 int ofs = pipe->BufSize - pipe->WritePos;
352 memcpy(&pipe->Buffer[pipe->WritePos], Buffer, ofs);
353 memcpy(&pipe->Buffer, (Uint8*)Buffer + ofs, len-ofs);
357 memcpy(&pipe->Buffer[pipe->WritePos], Buffer, len);
360 // Increment read position
361 pipe->WritePos += len;
362 pipe->WritePos %= pipe->BufSize;
365 if( pipe->ReadPos == pipe->WritePos ) {
366 VFS_MarkFull(Node, 1); // Buffer full
368 VFS_MarkAvaliable(Node, 1);
370 // Decrement Remaining Bytes
372 // Increment Buffer address
373 Buffer = (Uint8*)Buffer + len;
382 * \fn tPipe *FIFO_Int_NewPipe(int Size, const char *Name)
383 * \brief Create a new pipe
385 tPipe *FIFO_Int_NewPipe(int Size, const char *Name)
388 int namelen = strlen(Name) + 1;
389 int allocsize = sizeof(tPipe) + sizeof(tVFS_ACL) + Size + namelen;
391 ENTER("iSize sName", Size, Name);
393 ret = calloc(1, allocsize);
394 if(!ret) LEAVE_RET('n', NULL);
397 ret->Flags = PF_BLOCKING;
401 ret->Buffer = (void*)( (Uint)ret + sizeof(tPipe) + sizeof(tVFS_ACL) );
403 // Set name (and FIFO name)
404 ret->Name = ret->Buffer + Size;
405 strcpy(ret->Name, Name);
406 // - Start empty, max of `Size`
407 //Semaphore_Init( &ret->Semaphore, 0, Size, "FIFO", ret->Name );
410 ret->Node.ReferenceCount = 1;
412 ret->Node.ImplPtr = ret;
413 ret->Node.UID = Threads_GetUID();
414 ret->Node.GID = Threads_GetGID();
415 ret->Node.NumACLs = 1;
416 ret->Node.ACLs = (void*)( (Uint)ret + sizeof(tPipe) );
417 ret->Node.ACLs->Group = 0;
418 ret->Node.ACLs->ID = ret->Node.UID;
419 ret->Node.ACLs->Inv = 0;
420 ret->Node.ACLs->Perms = -1;
423 = ret->Node.ATime = now();
424 ret->Node.Type = &gFIFO_PipeNodeType;