953bac6afa3ddba7e8e6ce8b1142a5565e3f17ff
[tpg/acess2.git] / Kernel / drv / fifo.c
1 /* AcessOS
2  * FIFO Pipe Driver
3  */
4 #include <common.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, char *Filename);
29  int    FIFO_MkNod(tVFS_Node *Node, char *Name, Uint Flags);
30 void    FIFO_Close(tVFS_Node *Node);
31  int    FIFO_Relink(tVFS_Node *Node, char *OldName, 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 0;
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, 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, 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, char *Name, Uint Flags)
128  */
129 int FIFO_MkNod(tVFS_Node *Node, char *Name, Uint Flags)
130 {
131         return 0;
132 }
133
134 /**
135  * \fn void FIFO_Close(vfs_node *Node)
136  */
137 void FIFO_Close(tVFS_Node *Node)
138 {
139         tPipe   *pipe;
140         if(!Node->ImplPtr)      return ;
141         
142         Node->ReferenceCount --;
143         if(Node->ReferenceCount)        return ;
144         
145         pipe = Node->ImplPtr;
146         
147         if(strcmp(pipe->Name, "anon") == 0) {
148                 free(Node->ImplPtr);
149                 return ;
150         }
151         
152         return ;
153 }
154
155 /**
156  * \fn int FIFO_Relink(tVFS_Node *Node, char *OldName, char *NewName)
157  * \brief Relink a file (Deletes named pipes)
158  */
159 int FIFO_Relink(tVFS_Node *Node, char *OldName, char *NewName)
160 {
161         tPipe   *pipe, *tmp;
162         
163         if(Node != &gFIFO_DriverInfo.RootNode)  return 0;
164         
165         // Can't relink anon
166         if(strcmp(OldName, "anon"))     return 0;
167         
168         // Find node
169         for(pipe = gFIFO_NamedPipes;
170                 pipe;
171                 pipe = pipe->Next)
172         {
173                 if(strcmp(pipe->Name, OldName) == 0)
174                         break;
175         }
176         if(!pipe)       return 0;
177         
178         // Relink a named pipe
179         if(NewName) {
180                 // Check new name
181                 for(tmp = gFIFO_NamedPipes;
182                         tmp;
183                         tmp = tmp->Next)
184                 {
185                         if(strcmp(tmp->Name, NewName) == 0)     return 0;
186                 }
187                 // Create new name
188                 free(pipe->Name);
189                 pipe->Name = malloc(strlen(NewName)+1);
190                 strcpy(pipe->Name, NewName);
191                 return 1;
192         }
193         
194         // Unlink the pipe
195         if(Node->ImplPtr) {
196                 free(Node->ImplPtr);
197                 return 1;
198         }
199         
200         return 0;
201 }
202
203 /**
204  * \fn Uint64 FIFO_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
205  * \brief Read from a fifo pipe
206  */
207 Uint64 FIFO_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
208 {
209         tPipe   *pipe = Node->ImplPtr;
210         Uint    len;
211         Uint    remaining = Length;
212         
213         if(!pipe)       return 0;
214         
215         while(remaining)
216         {
217                 // Wait for buffer to fill
218                 if(pipe->Flags & PF_BLOCKING)
219                         while(pipe->ReadPos == pipe->WritePos)
220                                 Threads_Yield();
221                 else
222                         if(pipe->ReadPos == pipe->WritePos)
223                                 return 0;
224                 
225                 // Read buffer
226                 if(pipe->WritePos - pipe->ReadPos < remaining)
227                         len = pipe->WritePos - pipe->ReadPos;
228                 else
229                         len = remaining;
230                 
231                 // Check if read overflows buffer
232                 if(len > pipe->BufSize - pipe->ReadPos)
233                 {
234                         int ofs = pipe->BufSize - pipe->ReadPos;
235                         memcpy(Buffer, &pipe->Buffer[pipe->ReadPos], ofs);
236                         memcpy(Buffer + ofs, &pipe->Buffer, len-ofs);
237                 }
238                 else
239                 {
240                         memcpy(Buffer, &pipe->Buffer[pipe->ReadPos], len);
241                 }
242                 
243                 // Increment read position
244                 pipe->ReadPos += len;
245                 pipe->ReadPos %= pipe->BufSize;
246                 
247                 // Decrement Remaining Bytes
248                 remaining -= len;
249                 // Increment Buffer address
250                 Buffer += len;
251         }
252
253         return Length;
254
255 }
256
257 /**
258  * \fn Uint64 FIFO_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
259  * \brief Write to a fifo pipe
260  */
261 Uint64 FIFO_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
262 {
263         tPipe   *pipe = Node->ImplPtr;
264         Uint    len;
265         Uint    remaining = Length;
266         
267         if(!pipe)       return 0;
268         
269         while(remaining)
270         {
271                 // Wait for buffer to empty
272                 if(pipe->Flags & PF_BLOCKING)
273                         while(pipe->ReadPos == (pipe->WritePos+1)%pipe->BufSize)
274                                 Threads_Yield();
275                 else
276                         if(pipe->ReadPos == (pipe->WritePos+1)%pipe->BufSize)
277                                 return 0;
278                 
279                 // Write buffer
280                 if(pipe->ReadPos - pipe->WritePos < remaining)
281                         len = pipe->ReadPos - pipe->WritePos;
282                 else
283                         len = remaining;
284                 
285                 // Check if write overflows buffer
286                 if(len > pipe->BufSize - pipe->WritePos)
287                 {
288                         int ofs = pipe->BufSize - pipe->WritePos;
289                         memcpy(&pipe->Buffer[pipe->WritePos], Buffer, ofs);
290                         memcpy(&pipe->Buffer, Buffer + ofs, len-ofs);
291                 }
292                 else
293                 {
294                         memcpy(&pipe->Buffer[pipe->WritePos], Buffer, len);
295                 }
296                 
297                 // Increment read position
298                 pipe->WritePos += len;
299                 pipe->WritePos %= pipe->BufSize;
300                 
301                 // Decrement Remaining Bytes
302                 remaining -= len;
303                 // Increment Buffer address
304                 Buffer += len;
305         }
306
307         return Length;
308 }
309
310 // --- HELPERS ---
311 /**
312  * \fn tPipe *FIFO_Int_NewPipe(int Size, char *Name)
313  * \brief Create a new pipe
314  */
315 tPipe *FIFO_Int_NewPipe(int Size, char *Name)
316 {
317         tPipe   *ret;
318          int    allocsize = sizeof(tPipe) + sizeof(tVFS_ACL) + Size;
319         
320         ret = malloc(allocsize);
321         if(!ret)        return NULL;
322         
323         // Clear Return
324         memset(ret, 0, allocsize);
325         
326         ret->Name = Name;
327         
328         // Allocate Buffer
329         ret->BufSize = Size;
330         ret->Buffer = (void*)( (Uint)ret + sizeof(tPipe) + sizeof(tVFS_ACL) );
331         if(!ret->Buffer) {
332                 free(ret);
333                 return NULL;
334         }
335         
336         // Set Node
337         ret->Node.Size = 0;
338         ret->Node.ImplPtr = ret;
339         ret->Node.UID = Threads_GetUID();
340         ret->Node.GID = Threads_GetGID();
341         ret->Node.NumACLs = 1;
342         ret->Node.ACLs = (void*)( (Uint)ret + sizeof(tPipe) );
343                 ret->Node.ACLs->Group = 0;
344                 ret->Node.ACLs->ID = ret->Node.UID;
345                 ret->Node.ACLs->Inv = 0;
346                 ret->Node.ACLs->Perms = -1;
347         ret->Node.CTime
348                 = ret->Node.MTime
349                 = ret->Node.ATime = now();
350         ret->Node.Read = FIFO_Read;
351         ret->Node.Write = FIFO_Write;
352         ret->Node.Close = FIFO_Close;
353         
354         return ret;
355 }

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