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

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