changing circuitry to disable RTC, update initialization to match
[fw/openalt] / newlib / syscalls.c
1 //
2 //  Support files for GNU libc.  Files in the system namespace go here.
3 //  Files in the C namespace (ie those that do not start with an underscore) go in .c
4 //  
5 #include <_ansi.h>
6 #include <sys/types.h>
7 #include <sys/stat.h>
8 #include <sys/fcntl.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <time.h>
12 #include <sys/time.h>
13 #include <sys/times.h>
14 #include <errno.h>
15 #include <reent.h>
16 #include <signal.h>
17 #include <unistd.h>
18 #include <sys/wait.h>
19 #include "FreeRTOS.h"
20 #include "task.h"
21 #include "../uart/uart.h"
22 #include "../usbser/usbser.h"
23 #include "../rtc/rtc.h"
24 #include "../fatfs/ff.h"
25
26 //
27 //  Forward prototypes
28 //
29 int     _mkdir        _PARAMS ((const char *, mode_t));
30 int     _chmod        _PARAMS ((const char *, mode_t));
31 int     _read         _PARAMS ((int, char *, int));
32 int     _lseek        _PARAMS ((int, int, int));
33 int     _write        _PARAMS ((int, const char *, int));
34 int     _open         _PARAMS ((const char *, int, ...));
35 int     _close        _PARAMS ((int));
36 int     _kill         _PARAMS ((int, int));
37 void    _exit         _PARAMS ((int));
38 int     _getpid       _PARAMS ((int));
39 caddr_t _sbrk         _PARAMS ((int));
40 int     _fstat        _PARAMS ((int, struct stat *));
41 int     _stat         _PARAMS ((const char *, struct stat *));
42 int     _link         _PARAMS ((void));
43 int     _unlink       _PARAMS ((const char *));
44 void    _raise        _PARAMS ((void));
45 int     _gettimeofday _PARAMS ((struct timeval *, struct timezone *));
46 clock_t _times        _PARAMS ((struct tms *));
47 int     isatty        _PARAMS ((int));
48 int     _rename       _PARAMS ((const char *, const char *));
49 int     _system       _PARAMS ((const char *));
50 void    _sync         _PARAMS ((void));
51 void    syscallsInit  _PARAMS ((void));
52
53 int     rename        _PARAMS ((const char *, const char *));
54
55 static int  set_errno             _PARAMS ((int));
56 static time_t fatfs_time_to_timet _PARAMS ((FILINFO *));
57 static int  remap_handle          _PARAMS ((int));
58 static int  findslot              _PARAMS ((int));
59
60 //
61 //  Register name faking - works in collusion with the linker
62 //
63 register char *stack_ptr asm ("sp");
64
65 //
66 //  Following is copied from libc/stdio/local.h to check std streams 
67 //
68 extern void _EXFUN (__sinit,( struct _reent *));
69
70 #define CHECK_INIT(ptr)            \
71 do                                 \
72 {                                  \
73   if ((ptr) && !(ptr)->__sdidinit) \
74   __sinit (ptr);                   \
75 }                                  \
76 while (0)
77
78 //
79 //  Adjust our internal handles to stay away from std* handles
80 //
81 #define FILE_HANDLE_OFFSET (0x20)
82
83 #define MONITOR_STDIN  0
84 #define MONITOR_STDOUT 1
85 #define MONITOR_STDERR 2
86 #define MONITOR_UART0  3
87 #define MONITOR_UART1  4
88 #define MONITOR_USB    5
89 #define MONITOR_FATFS  6
90
91 // 
92 //
93 //
94 typedef struct
95 {
96   int handle;
97   int pos;
98   int flags;
99   FIL *fatfsFCB;
100 }
101 openFiles_t;
102
103 //
104 //
105 //
106 #define MAX_OPEN_FILES 10
107 static openFiles_t openfiles [MAX_OPEN_FILES];
108
109 static int findslot (int fh)
110 {
111   static int slot;
112   static int lastfh = -1;
113
114   if ((fh != -1) && (fh == lastfh))
115     return slot;
116
117   for (slot = 0; slot < MAX_OPEN_FILES; slot++)
118     if (openfiles [slot].handle == fh)
119       break;
120
121   lastfh = fh;
122
123   return slot;
124 }
125
126 //
127 //  Function to convert std(in|out|err) handles to internal versions.  
128 //
129 static int remap_handle (int fh)
130 {
131   CHECK_INIT(_REENT);
132
133   if (fh == STDIN_FILENO)
134     return MONITOR_STDIN;
135   if (fh == STDOUT_FILENO)
136     return MONITOR_STDOUT;
137   if (fh == STDERR_FILENO)
138     return MONITOR_STDERR;
139
140   return fh - FILE_HANDLE_OFFSET;
141 }
142
143 static int remap_fatfs_errors (FRESULT f)
144 {
145   switch (f)
146   {
147     case FR_NO_FILE         : errno = ENOENT;   break;
148     case FR_NO_PATH         : errno = ENOENT;   break;
149     case FR_INVALID_NAME    : errno = EINVAL;   break;
150     case FR_INVALID_DRIVE   : errno = ENODEV;   break;
151     case FR_DENIED          : errno = EACCES;   break;
152     case FR_EXIST           : errno = EEXIST;   break;
153     case FR_NOT_READY       : errno = EIO;      break;
154     case FR_WRITE_PROTECTED : errno = EACCES;   break;
155     case FR_RW_ERROR        : errno = EIO;      break;
156     case FR_NOT_ENABLED     : errno = EIO;      break;
157     case FR_NO_FILESYSTEM   : errno = EIO;      break;
158     case FR_INVALID_OBJECT  : errno = EBADF;    break;
159     default                 : errno = EIO;      break;
160   }
161
162   return -1;
163 }
164
165 static time_t fatfs_time_to_timet (FILINFO *f)
166 {
167   struct tm tm;
168
169   tm.tm_sec  =  (f->ftime & 0x001f) << 1;
170   tm.tm_min  =  (f->ftime & 0x07e0) >> 5;
171   tm.tm_hour =  (f->ftime & 0xf800) >> 11;
172   tm.tm_mday =  (f->fdate & 0x001f);
173   tm.tm_mon  = ((f->fdate & 0x01e0) >> 5) - 1;
174   tm.tm_year = ((f->fdate & 0xfe00) >> 9) + 80;
175   tm.tm_isdst = 0;
176
177   return mktime (&tm);
178 }
179
180 static int set_errno (int errval)
181 {
182   errno = errval;
183
184   return -1;
185 }
186
187 void syscallsInit (void)
188 {
189   int slot;
190   static int initialized = 0;
191
192   if (initialized)
193     return;
194
195   initialized = 1;
196
197   __builtin_memset (openfiles, 0, sizeof (openfiles));
198
199   for (slot = 0; slot < MAX_OPEN_FILES; slot++)
200     openfiles [slot].handle = -1;
201
202   openfiles [0].handle = MONITOR_STDIN;
203   openfiles [1].handle = MONITOR_STDOUT;
204   openfiles [2].handle = MONITOR_STDERR;
205 }
206
207 int _mkdir (const char *path, mode_t mode __attribute__ ((unused)))
208 {
209   FRESULT f;
210
211   if ((f = f_mkdir (path)) != FR_OK)
212     return remap_fatfs_errors (f);
213
214   return 0;
215 }
216
217 int _chmod (const char *path, mode_t mode)
218 {
219   FRESULT f;
220
221   if ((f = f_chmod (path, (mode & S_IWUSR) ? 0 : AM_RDO, AM_RDO)) != FR_OK)
222     return remap_fatfs_errors (f);
223
224   return 0;
225 }
226
227 int _read (int fd, char *ptr, int len)
228 {
229   int i;
230   int fh;
231   int slot;
232   portTickType xBlockTime;
233   int bytesUnRead = -1;
234
235   if ((slot = findslot (fh = remap_handle (fd))) == MAX_OPEN_FILES)
236     return set_errno (EBADF);
237
238   if (openfiles [slot].flags & O_WRONLY)
239     return set_errno (EBADF);
240
241   xBlockTime = (openfiles [slot].flags & O_NONBLOCK) ? 0 : portMAX_DELAY;
242
243   switch (fh)
244   {
245     case MONITOR_STDIN :
246       {
247         for (i = 0; i < len; i++)
248           if (!uartGetChar (0, (signed portCHAR *) ptr++, xBlockTime))
249             break;
250
251         bytesUnRead = len - i;
252       }
253       break;
254
255     case MONITOR_STDOUT :
256     case MONITOR_STDERR :
257       break;
258
259     case MONITOR_UART0 :
260       {
261         for (i = 0; i < len; i++)
262           if (!uartGetChar (0, (signed portCHAR *) ptr++, xBlockTime))
263             break;
264
265         bytesUnRead = len - i;
266       }
267       break;
268
269     case MONITOR_UART1 :
270       {
271         for (i = 0; i < len; i++)
272           if (!uartGetChar (1, (signed portCHAR *) ptr++, xBlockTime))
273             break;
274
275         bytesUnRead = len - i;
276       }
277       break;
278
279     case MONITOR_USB :
280       {
281         for (i = 0; i < len; i++)
282           if (!usbserGetChar ((signed portCHAR *) ptr++, xBlockTime))
283             break;
284
285         bytesUnRead = len - i;
286       }
287       break;
288
289     default :
290       {
291         if (openfiles [slot].fatfsFCB)
292         {
293           FRESULT f;
294           U16 fatfsBytesRead;
295
296           if ((f = f_read (openfiles [slot].fatfsFCB, ptr, len, &fatfsBytesRead)) != FR_OK)
297             return remap_fatfs_errors (f);
298
299           bytesUnRead = len - fatfsBytesRead;
300         }
301       }      
302       break;
303   }
304
305   if (bytesUnRead < 0)
306     return -1;
307
308   openfiles [slot].pos += len - bytesUnRead;
309
310   return len - bytesUnRead;
311 }
312
313 int _lseek (int fd, int ptr, int dir)
314 {
315   int fh;
316   int slot;
317   FRESULT f = FR_INVALID_OBJECT;
318
319   if (((slot = findslot (fh = remap_handle (fd))) == MAX_OPEN_FILES) || !openfiles [slot].fatfsFCB)
320     return set_errno (EBADF);
321
322   if (dir == SEEK_SET)
323     f = f_lseek (openfiles [slot].fatfsFCB, ptr); 
324   else if (dir == SEEK_CUR)
325     f = f_lseek (openfiles [slot].fatfsFCB, openfiles [slot].fatfsFCB->fptr + ptr); 
326   else if (dir == SEEK_END)
327     f = f_lseek (openfiles [slot].fatfsFCB, openfiles [slot].fatfsFCB->fsize + ptr); 
328
329   if (f != FR_OK)
330     return remap_fatfs_errors (f);
331
332   return openfiles [slot].pos = openfiles [slot].fatfsFCB->fptr;
333 }
334
335 int _write (int fd, const char *ptr, int len)
336 {
337   int i;
338   int fh;
339   int slot;
340   portTickType xBlockTime;
341   int bytesUnWritten = -1;
342
343   if ((slot = findslot (fh = remap_handle (fd))) == MAX_OPEN_FILES)
344     return set_errno (EBADF);
345
346   if (openfiles [slot].flags & O_RDONLY)
347     return set_errno (EBADF);
348
349   xBlockTime = (openfiles [slot].flags & O_NONBLOCK) ? 0 : portMAX_DELAY;
350   
351   switch (fh)
352   {
353     case MONITOR_STDIN :
354       break;
355
356     case MONITOR_STDOUT :
357     case MONITOR_STDERR :
358       {
359         for (i = 0; i < len; i++)
360         {
361           if (*ptr == '\n')
362             if (!uartPutChar (0, '\r', xBlockTime))
363               break;
364           if (!uartPutChar (0, *ptr++, xBlockTime))
365             break;
366         }
367
368         bytesUnWritten = len - i;
369       }
370       break;
371
372     case MONITOR_UART0 :
373       {
374         for (i = 0; i < len; i++)
375           if (!uartPutChar (0, *ptr++, xBlockTime))
376             break;
377
378         bytesUnWritten = len - i;
379       }
380       break;
381
382     case MONITOR_UART1 :
383       {
384         for (i = 0; i < len; i++)
385         {
386 #ifdef CFG_CONSOLE_UART1
387           if (*ptr == '\n')
388             if (!uartPutChar (1, '\r', xBlockTime))
389               break;
390 #endif
391           if (!uartPutChar (1, *ptr++, xBlockTime))
392             break;
393         }
394
395         bytesUnWritten = len - i;
396       }
397       break;
398
399     case MONITOR_USB :
400       {
401         for (i = 0; i < len; i++)
402         {
403 #ifdef CFG_CONSOLE_USB
404           if (*ptr == '\n')
405             if (!usbserPutChar ('\r', xBlockTime))
406               break;
407 #endif
408           if (!usbserPutChar (*ptr++, xBlockTime))
409             break;
410         }
411
412         bytesUnWritten = len - i;
413       }
414       break;
415
416     default :
417       {
418         if (openfiles [slot].fatfsFCB)
419         {
420           FRESULT f;
421           U16 fatfsBytesWritten;
422
423           if ((f = f_write (openfiles [slot].fatfsFCB, ptr, len, &fatfsBytesWritten)) != FR_OK)
424             return remap_fatfs_errors (f);
425
426           bytesUnWritten = len - fatfsBytesWritten;
427         }
428         else
429           return set_errno (EBADF);
430       }
431       break;
432   }
433
434   if (bytesUnWritten == -1 || bytesUnWritten == len)
435     return -1;
436
437   openfiles [slot].pos += len - bytesUnWritten;
438
439   return len - bytesUnWritten;
440 }
441
442 int _open (const char *path, int flags, ...)
443 {
444   int fh = 0;
445   int slot;
446
447   if ((slot = findslot (-1)) == MAX_OPEN_FILES)
448     return set_errno (ENFILE);
449
450   if (flags & O_APPEND)
451     flags &= ~O_TRUNC;
452
453   if (!__builtin_strcmp (path, "/dev/uart0"))
454     fh = MONITOR_UART0;
455   else if (!__builtin_strcmp (path, "/dev/uart1"))
456     fh = MONITOR_UART1;
457   else if (!__builtin_strcmp (path, "/dev/usb"))
458     fh = MONITOR_USB;
459   else
460   {
461     U8 fatfsFlags = FA_OPEN_EXISTING;
462     FRESULT f;
463
464     //
465     // FA_OPEN_EXISTING Opens the file. The function fails if the file is not existing. (Default)
466     // FA_OPEN_ALWAYS   Opens the file, if it is existing. If not, the function creates the new file.
467     // FA_CREATE_NEW    Creates a new file. The function fails if the file is already existing.
468     // FA_CREATE_ALWAYS Creates a new file. If the file is existing, it is truncated and overwritten.
469     //
470     // O_CREAT If the file does not exist it will be created.
471     // O_EXCL  When used with O_CREAT, if the file already exists it is an error and the open() will fail.
472     // O_TRUNC If the file already exists and is a regular file and the open mode allows writing (i.e., is O_RDWR or O_WRONLY) it will be truncated to length 0. 
473     //
474     if (((flags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC)) && (flags & (O_RDWR | O_WRONLY)))
475       fatfsFlags = FA_CREATE_ALWAYS;
476     else if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
477       fatfsFlags = FA_OPEN_EXISTING;
478     else if ((flags & O_CREAT) == O_CREAT)
479       fatfsFlags = FA_OPEN_ALWAYS;
480     else if ((flags == O_RDONLY) || (flags == O_WRONLY) || (flags == O_RDWR))
481       fatfsFlags = FA_OPEN_EXISTING;
482     else
483       return set_errno (EINVAL);
484
485     if ((flags & O_ACCMODE) == O_RDONLY)
486       fatfsFlags |= FA_READ;
487     else if ((flags & O_ACCMODE) == O_WRONLY)
488       fatfsFlags |= FA_WRITE;
489     else if ((flags & O_ACCMODE) == O_RDWR)
490       fatfsFlags |= (FA_READ | FA_WRITE);
491     else
492       return set_errno (EINVAL);
493
494     fh = -1;
495     errno = EIO;
496
497     if (!openfiles [slot].fatfsFCB)
498       if ((openfiles [slot].fatfsFCB = __builtin_calloc (1, sizeof (FIL))))
499         if ((fh = ((f = f_open (openfiles [slot].fatfsFCB, path, fatfsFlags)) == FR_OK) ? (slot + MONITOR_FATFS) : -1) == -1)
500           return remap_fatfs_errors (f);
501   }
502
503   if (fh >= 0)
504   {
505     openfiles [slot].handle = fh;
506     openfiles [slot].pos = 0;
507     openfiles [slot].flags = flags;
508   }
509
510   return fh >= 0 ? (fh + FILE_HANDLE_OFFSET) : -1;
511 }
512
513 int _close (int fd)
514 {
515   int slot;
516
517   if ((slot = findslot (remap_handle (fd))) == MAX_OPEN_FILES)
518     return set_errno (EBADF);
519
520   openfiles [slot].handle = -1;
521
522   if (openfiles [slot].fatfsFCB)
523   {
524     FRESULT f;
525
526     f = f_close (openfiles [slot].fatfsFCB);
527     free (openfiles [slot].fatfsFCB);
528     openfiles [slot].fatfsFCB = NULL;
529
530     if (f != FR_OK)
531       return remap_fatfs_errors (f);
532   }
533
534   return 0;
535 }
536
537 int _kill (int pid __attribute__ ((unused)), int sig __attribute__ ((unused)))
538 {
539   return set_errno (ENOTSUP);
540 }
541
542 void _exit (int status)
543 {
544   /* There is only one SWI for both _exit and _kill. For _exit, call
545      the SWI with the second argument set to -1, an invalid value for
546      signum, so that the SWI handler can distinguish the two calls.
547       Note: The RDI implementation of _kill throws away both its
548       arguments.  */
549   _kill (status, -1);
550
551   while (1);
552 }
553
554 int _getpid (int n)
555 {
556   return 1;
557   n = n;
558 }
559
560 caddr_t _sbrk (int incr)
561 {
562   extern char end asm ("end");  /* Defined by the linker.  */
563   extern unsigned long __heap_max;
564   static char *heap_end;
565   char *prev_heap_end;
566   char *eom;
567
568   if (!heap_end)
569     heap_end = & end;
570
571   prev_heap_end = heap_end;
572
573   //
574   //  If FreeRTOS is not running, the stack pointer will be in the SVC region,
575   //  and therefore greater than the start of the heap (end of .bss).  In this
576   //  case, we see if the heap allocation will run past the current stack
577   //  pointer, and if so, return ENOMEM (this does not guarantee subsequent
578   //  stack operations won't overflow into the heap!).  
579   //
580   //  If FreeRTOS is running, then we define the end of the heap to be the
581   //  start of end of the supervisor stack (since FreeRTOS is running, the
582   //  system stack, and very little of the supervisor stack space is used).
583   //
584   eom = (stack_ptr > & end) ? stack_ptr : (char *) __heap_max;
585
586   if (heap_end + incr > eom)
587   {
588     errno = ENOMEM;
589     return (caddr_t) -1;
590   }
591
592   heap_end += incr;
593
594   return (caddr_t) prev_heap_end;
595 }
596
597 //
598 //  Tihs is a problem.  FatFS has no way to go from a file handle back to a file,
599 //  since file name information isn't stored with the handle.  Tried to think of
600 //  a good way to handle this, couldn't come up with anything.  For now, it
601 //  returns ENOSYS (not implemented).
602 //
603 int _fstat (int fd __attribute__ ((unused)), struct stat *st __attribute__ ((unused)))
604 {
605   return set_errno (ENOSYS);
606 }
607
608 int _stat (const char *fname, struct stat *st)
609 {
610   FRESULT f;
611   FILINFO fi;
612
613   if ((f = f_stat (fname, &fi)) != FR_OK)
614     return remap_fatfs_errors (f);
615
616   __builtin_memset (st, 0, sizeof (* st));
617
618   st->st_mode |= (fi.fattrib & AM_DIR) ? S_IFDIR : S_IFREG;
619   st->st_mode |= (fi.fattrib & AM_RDO) ? ((S_IRWXU & ~S_IWUSR) | (S_IRWXG & ~S_IWGRP) | (S_IRWXO & ~S_IWOTH)) : (S_IRWXU | S_IRWXG | S_IRWXO);
620   st->st_size = fi.fsize;
621   st->st_ctime = fatfs_time_to_timet (&fi);
622   st->st_mtime = st->st_ctime;
623   st->st_atime = st->st_ctime;
624   st->st_blksize = 512;
625
626   return 0;
627 }
628
629 //
630 //  FatFS and FAT file systems don't support links
631 //
632 int _link (void)
633 {
634   return set_errno (ENOSYS);
635 }
636
637 int _unlink (const char *path)
638 {
639   FRESULT f;
640
641   if ((f = f_unlink (path)) != FR_OK)
642     return remap_fatfs_errors (f);
643
644   return 0;
645 }
646
647 void _raise (void)
648 {
649   return;
650 }
651
652 int _gettimeofday (struct timeval *tp, struct timezone *tzp)
653 {
654   unsigned int milliseconds;
655
656   if (tp)
657   {
658     tp->tv_sec = rtcGetEpochSeconds (&milliseconds);
659     tp->tv_usec = milliseconds * 1000;
660   }
661
662   //
663   //  Return fixed data for the timezone
664   //
665   if (tzp)
666   {
667     tzp->tz_minuteswest = 0;
668     tzp->tz_dsttime = 0;
669   }
670
671   return 0;
672 }
673
674 //
675 //  Return a clock that ticks at 100Hz
676 //
677 clock_t _times (struct tms *tp)
678 {
679   clock_t timeval = (clock_t) xTaskGetTickCount ();
680
681   if (tp)
682   {
683     tp->tms_utime  = timeval;
684     tp->tms_stime  = 0;
685     tp->tms_cutime = 0;
686     tp->tms_cstime = 0;
687   }
688
689   return timeval;
690 };
691
692 int isatty (int fd)
693 {
694   return (fd <= 2) ? 1 : 0;  /* one of stdin, stdout, stderr */
695 }
696
697 int _system (const char *s)
698 {
699   if (s == NULL)
700     return 0;
701
702   return set_errno (ENOSYS);
703 }
704
705 int _rename (const char *oldpath, const char *newpath)
706 {
707   FRESULT f;
708
709   if ((f = f_rename (oldpath, newpath)))
710     return remap_fatfs_errors (f);
711
712   return 0;
713 }
714
715 //
716 //  Default crossdev -t options for ARM newlib doesn't define HAVE_RENAME, so
717 //  it's trying to use the link/unlink process.  FatFS doesn't support link(),
718 //  so override the newlib rename() to make it work correctly.
719 //
720 int rename (const char *oldpath, const char *newpath)
721 {
722   return _rename (oldpath, newpath);
723 }
724
725 void _sync (void)
726 {
727   int slot;
728
729   for (slot = 0; slot < MAX_OPEN_FILES; slot++)
730     if (openfiles [slot].fatfsFCB)
731       f_sync (openfiles [slot].fatfsFCB);
732 }