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

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