83d11755166291d57c9137ec72cf13ef9ae3b8e7
[tpg/acess2.git] / Kernel / drv / fifo.c
1 /* AcessOS
2  * FIFO Pipe Driver
3  */
4 #include <acess.h>
5 #include <modules.h>
6 #include <fs_devfs.h>
7
8 // === CONSTANTS ===
9 #define DEFAULT_RING_SIZE       2048
10 #define PF_BLOCKING             1
11
12 // === TYPES ===
13 typedef struct sPipe {
14         struct sPipe    *Next;
15         char    *Name;
16         tVFS_Node       Node;
17         Uint    Flags;
18          int    ReadPos;
19          int    WritePos;
20          int    BufSize;
21         char    *Buffer;
22 } tPipe;
23
24 // === PROTOTYPES ===
25  int    FIFO_Install(char **Arguments);
26  int    FIFO_IOCtl(tVFS_Node *Node, int Id, void *Data);
27 char    *FIFO_ReadDir(tVFS_Node *Node, int Id);
28 tVFS_Node       *FIFO_FindDir(tVFS_Node *Node, const char *Filename);
29  int    FIFO_MkNod(tVFS_Node *Node, const char *Name, Uint Flags);
30 void    FIFO_Close(tVFS_Node *Node);
31  int    FIFO_Relink(tVFS_Node *Node, const char *OldName, const char *NewName);
32 Uint64  FIFO_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
33 Uint64  FIFO_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
34 tPipe   *FIFO_Int_NewPipe(int Size, char *Name);
35
36 // === GLOBALS ===
37 MODULE_DEFINE(0, 0x0032, FIFO, FIFO_Install, NULL, NULL);
38 tDevFS_Driver   gFIFO_DriverInfo = {
39         NULL, "fifo",
40         {
41         .NumACLs = 1,
42         .ACLs = &gVFS_ACL_EveryoneRW,
43         .Flags = VFS_FFLAG_DIRECTORY,
44         .ReadDir = FIFO_ReadDir,
45         .FindDir = FIFO_FindDir,
46         .MkNod = FIFO_MkNod,
47         .Relink = FIFO_Relink,
48         .IOCtl = FIFO_IOCtl
49         }
50 };
51 tVFS_Node       gFIFO_AnonNode = {
52         .NumACLs = 1,
53         .ACLs = &gVFS_ACL_EveryoneRW,
54         };
55 tPipe   *gFIFO_NamedPipes = NULL;
56
57 // === CODE ===
58 /**
59  * \fn int FIFO_Install(char **Options)
60  * \brief Installs the FIFO Driver
61  */
62 int FIFO_Install(char **Options)
63 {
64         DevFS_AddDevice( &gFIFO_DriverInfo );
65         return MODULE_ERR_OK;
66 }
67
68 /**
69  * \fn int FIFO_IOCtl(tVFS_Node *Node, int Id, void *Data)
70  */
71 int FIFO_IOCtl(tVFS_Node *Node, int Id, void *Data)
72 {
73         return 0;
74 }
75
76 /**
77  * \fn char *FIFO_ReadDir(tVFS_Node *Node, int Id)
78  * \brief Reads from the FIFO root
79  */
80 char *FIFO_ReadDir(tVFS_Node *Node, int Id)
81 {
82         tPipe   *tmp = gFIFO_NamedPipes;
83         // Entry 0 is Anon Pipes
84         if(Id == 0)     return strdup("anon");
85         
86         // Find the id'th node
87         while(--Id && tmp)      tmp = tmp->Next;
88         // If node found, return it
89         if(tmp) return strdup(tmp->Name);
90         // else error return
91         return NULL;
92 }
93
94 /**
95  * \fn tVFS_Node *FIFO_FindDir(tVFS_Node *Node, const char *Filename)
96  * \brief Find a file in the FIFO root
97  * \note Creates an anon pipe if anon is requested
98  */
99 tVFS_Node *FIFO_FindDir(tVFS_Node *Node, const char *Filename)
100 {
101         tPipe   *tmp;
102         if(!Filename)   return NULL;
103         
104         // NULL String Check
105         if(Filename[0] == '\0') return NULL;
106         
107         // Anon Pipe
108         if(Filename[0] == 'a' && Filename[1] == 'n'
109         && Filename[2] == 'o' && Filename[3] == 'n'
110         && Filename[4] == '\0') {
111                 tmp = FIFO_Int_NewPipe(DEFAULT_RING_SIZE, "anon");
112                 return &tmp->Node;
113         }
114         
115         // Check Named List
116         tmp = gFIFO_NamedPipes;
117         while(tmp)
118         {
119                 if(strcmp(tmp->Name, Filename) == 0)
120                         return &tmp->Node;
121                 tmp = tmp->Next;
122         }
123         return NULL;
124 }
125
126 /**
127  * \fn int FIFO_MkNod(tVFS_Node *Node, const char *Name, Uint Flags)
128  */
129 int FIFO_MkNod(tVFS_Node *Node, const char *Name, Uint Flags)
130 {
131         return 0;
132 }
133
134 /**
135  * \fn void FIFO_Close(tVFS_Node *Node)
136  * \brief Close a FIFO end
137  */
138 void FIFO_Close(tVFS_Node *Node)
139 {
140         tPipe   *pipe;
141         if(!Node->ImplPtr)      return ;
142         
143         Node->ReferenceCount --;
144         if(Node->ReferenceCount)        return ;
145         
146         pipe = Node->ImplPtr;
147         
148         if(strcmp(pipe->Name, "anon") == 0) {
149                 free(Node->ImplPtr);
150                 return ;
151         }
152         
153         return ;
154 }
155
156 /**
157  * \fn int FIFO_Relink(tVFS_Node *Node, const char *OldName, const char *NewName)
158  * \brief Relink a file (Deletes named pipes)
159  */
160 int FIFO_Relink(tVFS_Node *Node, const char *OldName, const char *NewName)
161 {
162         tPipe   *pipe, *tmp;
163         
164         if(Node != &gFIFO_DriverInfo.RootNode)  return 0;
165         
166         // Can't relink anon
167         if(strcmp(OldName, "anon"))     return 0;
168         
169         // Find node
170         for(pipe = gFIFO_NamedPipes;
171                 pipe;
172                 pipe = pipe->Next)
173         {
174                 if(strcmp(pipe->Name, OldName) == 0)
175                         break;
176         }
177         if(!pipe)       return 0;
178         
179         // Relink a named pipe
180         if(NewName) {
181                 // Check new name
182                 for(tmp = gFIFO_NamedPipes;
183                         tmp;
184                         tmp = tmp->Next)
185                 {
186                         if(strcmp(tmp->Name, NewName) == 0)     return 0;
187                 }
188                 // Create new name
189                 free(pipe->Name);
190                 pipe->Name = malloc(strlen(NewName)+1);
191                 strcpy(pipe->Name, NewName);
192                 return 1;
193         }
194         
195         // Unlink the pipe
196         if(Node->ImplPtr) {
197                 free(Node->ImplPtr);
198                 return 1;
199         }
200         
201         return 0;
202 }
203
204 /**
205  * \fn Uint64 FIFO_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
206  * \brief Read from a fifo pipe
207  */
208 Uint64 FIFO_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
209 {
210         tPipe   *pipe = Node->ImplPtr;
211         Uint    len;
212         Uint    remaining = Length;
213         
214         if(!pipe)       return 0;
215         
216         while(remaining)
217         {
218                 // Wait for buffer to fill
219                 if(pipe->Flags & PF_BLOCKING)
220                         while(pipe->ReadPos == pipe->WritePos)
221                                 Threads_Yield();
222                 else
223                         if(pipe->ReadPos == pipe->WritePos)
224                                 return 0;
225                 
226                 // Read buffer
227                 if(pipe->WritePos - pipe->ReadPos < remaining)
228                         len = pipe->WritePos - pipe->ReadPos;
229                 else
230                         len = remaining;
231                 
232                 // Check if read overflows buffer
233                 if(len > pipe->BufSize - pipe->ReadPos)
234                 {
235                         int ofs = pipe->BufSize - pipe->ReadPos;
236                         memcpy(Buffer, &pipe->Buffer[pipe->ReadPos], ofs);
237                         memcpy(Buffer + ofs, &pipe->Buffer, len-ofs);
238                 }
239                 else
240                 {
241                         memcpy(Buffer, &pipe->Buffer[pipe->ReadPos], len);
242                 }
243                 
244                 // Increment read position
245                 pipe->ReadPos += len;
246                 pipe->ReadPos %= pipe->BufSize;
247                 
248                 // Decrement Remaining Bytes
249                 remaining -= len;
250                 // Increment Buffer address
251                 Buffer += len;
252         }
253
254         return Length;
255
256 }
257
258 /**
259  * \fn Uint64 FIFO_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
260  * \brief Write to a fifo pipe
261  */
262 Uint64 FIFO_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
263 {
264         tPipe   *pipe = Node->ImplPtr;
265         Uint    len;
266         Uint    remaining = Length;
267         
268         if(!pipe)       return 0;
269         
270         while(remaining)
271         {
272                 // Wait for buffer to empty
273                 if(pipe->Flags & PF_BLOCKING)
274                         while(pipe->ReadPos == (pipe->WritePos+1)%pipe->BufSize)
275                                 Threads_Yield();
276                 else
277                         if(pipe->ReadPos == (pipe->WritePos+1)%pipe->BufSize)
278                                 return 0;
279                 
280                 // Write buffer
281                 if(pipe->ReadPos - pipe->WritePos < remaining)
282                         len = pipe->ReadPos - pipe->WritePos;
283                 else
284                         len = remaining;
285                 
286                 // Check if write overflows buffer
287                 if(len > pipe->BufSize - pipe->WritePos)
288                 {
289                         int ofs = pipe->BufSize - pipe->WritePos;
290                         memcpy(&pipe->Buffer[pipe->WritePos], Buffer, ofs);
291                         memcpy(&pipe->Buffer, Buffer + ofs, len-ofs);
292                 }
293                 else
294                 {
295                         memcpy(&pipe->Buffer[pipe->WritePos], Buffer, len);
296                 }
297                 
298                 // Increment read position
299                 pipe->WritePos += len;
300                 pipe->WritePos %= pipe->BufSize;
301                 
302                 // Decrement Remaining Bytes
303                 remaining -= len;
304                 // Increment Buffer address
305                 Buffer += len;
306         }
307
308         return Length;
309 }
310
311 // --- HELPERS ---
312 /**
313  * \fn tPipe *FIFO_Int_NewPipe(int Size, char *Name)
314  * \brief Create a new pipe
315  */
316 tPipe *FIFO_Int_NewPipe(int Size, char *Name)
317 {
318         tPipe   *ret;
319          int    allocsize = sizeof(tPipe) + sizeof(tVFS_ACL) + Size;
320         
321         ret = malloc(allocsize);
322         if(!ret)        return NULL;
323         
324         // Clear Return
325         memset(ret, 0, allocsize);
326         
327         ret->Name = Name;
328         
329         // Allocate Buffer
330         ret->BufSize = Size;
331         ret->Buffer = (void*)( (Uint)ret + sizeof(tPipe) + sizeof(tVFS_ACL) );
332         if(!ret->Buffer) {
333                 free(ret);
334                 return NULL;
335         }
336         
337         // Set Node
338         ret->Node.Size = 0;
339         ret->Node.ImplPtr = ret;
340         ret->Node.UID = Threads_GetUID();
341         ret->Node.GID = Threads_GetGID();
342         ret->Node.NumACLs = 1;
343         ret->Node.ACLs = (void*)( (Uint)ret + sizeof(tPipe) );
344                 ret->Node.ACLs->Group = 0;
345                 ret->Node.ACLs->ID = ret->Node.UID;
346                 ret->Node.ACLs->Inv = 0;
347                 ret->Node.ACLs->Perms = -1;
348         ret->Node.CTime
349                 = ret->Node.MTime
350                 = ret->Node.ATime = now();
351         ret->Node.Read = FIFO_Read;
352         ret->Node.Write = FIFO_Write;
353         ret->Node.Close = FIFO_Close;
354         
355         return ret;
356 }

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