/*
    Copyright (C) 1995-1997
        Rainer Schnitker, Heeper Str. 283, 33607 Bielefeld
        email: rainer@mathematik.uni-bielefeld.de

    All rights reserved
*/

#include <rsxnt.h>

static void __emx_version (SYSCALL_FRAME *f)
{
  static char emx_version[] = "emx_version=c9.0";
  #define EMX_VERSION (*(DWORD *)&emx_version[12])

  #define RUN_387         0x0020L
  #define RUN_486         0x0040L
  #define RUN_RSX         0x1000L

  #define RSXNT_VERSION   (0x00020000 | 0x0140)

  f->e.eax = EMX_VERSION;
  f->e.ebx = RUN_RSX | RUN_387;   /* FPU always 1 */
  f->e.ecx = RSXNT_VERSION;
  f->e.edx = 0;
}

static void set_return (int ret, SYSCALL_FRAME * f)
{
    if (ret < 0) {
        f->e.ecx = -ret;
        f->e.eax = -1;
    } else {
        f->e.ecx = 0;
        f->e.eax = ret;
    }
}

static void set_return_carry (int ret, SYSCALL_FRAME * f)
{
    if (ret < 0) {
        f->e.eax = - f->e.eax;
        f->e.eflags |= 1;
    } else {
        f->e.eax = ret;
        f->e.eflags &= ~1;
    }
}

int _rsxnt_emx_call(SYSCALL_FRAME * f)
{
    switch (f->h.al) {

    /* oldbrk_eax sbrk(inc_edx) ; err:eax=-1 */
    case 0x00:
        f->e.eax = (long) __sbrk(f->e.edx);
        break;

    /* eax=0 brk(newbrk_edx) ; err:eax=-1 */
    case 0x01:
        f->e.eax = (long) __brk((void *)f->e.edx);
        break;

    /* maxbrk_eax ulimit(cmd_ecx,newlimit_edx) errno:ecx */
    case 0x02:
        set_return (__ulimit(f->e.ecx, f->e.edx), f);
        break;

    /* emx special: void vmstat() */
    case 0x03:
        if (f->e.ecx >= 4)
            ((DWORD *)f->e.ebx)[0] = 0;
        if (f->e.ecx >= 8)
            ((DWORD *)f->e.ebx)[1] = 0;
        break;

    /* eax=filepermmask umask(edx) ; err:-  (OLD: ignore) */
    case 0x04:
        f->e.eax = f->e.edx;
        break;

    /* eax getpid(void) err:- */
    case 0x05:
        f->e.eax = __getpid();
        break;

    /* eax = spawnve(proc_env *edx) err:carry errno:eax */
    case 0x06:
        set_return_carry(__spawnve((struct _new_proc *) f->e.edx), f);
        break;

    /* sigreturn (RSX) */
    case 0x07:
        break;

    /* eax ptrace(ebx,edi,edx,ecx) err:ecx!=0 eax=-1 */
    case 0x08:
        {
            int retv;

            f->e.eax = _rsxnt_do_ptrace(f->e.ebx, f->e.edi, f->e.edx, f->e.ecx, &retv);
            if (f->e.eax < 0) {
                f->e.ecx = - f->e.eax;
                f->e.eflags |= 1;
                f->e.eax = -1;
            } else {
                f->e.eax = retv;
                f->e.ecx = 0;
            }
        }
        break;

    /* eax=child_id wait(status_edx) ; errno:ecx */
    case 0x09:
        {
          f->e.eax = __wait((int *) &(f->e.edx));
          if (f->e.eax == -ECHILD) {  /* fix for -handles */
              f->e.ecx = - f->e.eax;
              f->e.eax = -1;
          } else {
              f->e.ecx = 0;
          }
          break;
        }

    /* get emx-version ; err:- */
    case 0x0a:
        __emx_version (f);
        break;

    /* eax_pages memavail(void) ; err:- */
    case 0x0b:
        f->e.eax = __memavail();
        break;

    /* (*prevh) signal(signo_ecx,address_edx) err:eax=-1 */
    case 0x0c:
        f->e.eax = (int) __signal(f->e.ecx, (SA_HANDLER) f->e.edx);
        break;

    /* eax=0 kill(id_edx,signo_ecx) errno:ecx eax=-1 */
    case 0x0d:
        set_return (__kill(f->e.edx, f->e.ecx), f);

    /* eax raise(ecx) errno:ecx eax=-1 */
    case 0x0e:
        set_return (__raise(f->e.ecx), f);
        break;

    /* oldflags uflags(mask=ecx,new=edx) ;; bits 0-1 emx,SysV,BSD signals */
    case 0x0f:
        f->e.eax = __uflags(f->e.ecx, f->e.edx);
        break;

    /* void unwind(void) err:no */
    case 0x10:
        break;

    /* core(handle_ebx) err:carry errno */
    case 0x11:
        f->e.eax = EACCES;
        f->e.eflags |= 1;
        break;

    /* portaccess(ecx,edx) ecx=first edx=last, err:cy errno:eax */
    case 0x12:
        set_return_carry (__portaccess(f->e.ecx, f->e.edx), f);
        break;

    /* eax memaccess(Start=ebx,End=ecx,Flags=edx) err:carry errno:eax */
    case 0x13:
        f->e.ecx = ENOSYS;
        f->e.eax = -1;
        break;

    /* eax = ioctl2(ebx,ecx,edx) errno:ecx eax=-1 */
    case 0x14:
        set_return (__ioctl2(f->e.ebx, f->e.ecx, f->e.edx), f);
        break;

    /* eax=sec alarm(sec_edx) err:no */
    case 0x15:
        f->e.eax = __alarm(f->e.edx);
        break;

    /* 0x16 no syscall; internal */

    /* eax=0 sleep(edx) err:no */
    case 0x17:
        f->e.eax = __sleep(f->e.edx);
        break;

    /* eax chsize(handle ebx, arg edx) errno:carry */
    case 0x18:
        set_return_carry(__chsize(f->e.ebx, f->e.edx), f);
        break;

    /* eax fcntl(handle ebx,req ecx,arg edx) errno:ecx */
    case 0x19:
        set_return (__fcntl(f->e.ebx, f->e.ecx, f->e.edx), f);
        break;

    /* eax pipe(edx,ecx) errno:ecx*/
    case 0x1a:
        set_return (__pipe((int *)f->e.edx, f->e.ecx), f);
        break;

    /* eax fsync(ebx) errno:ecx */
    case 0x1b:
        set_return (__fsync(f->e.ebx), f);
        break;

    /* eax fork(void) errno:ecx */
    case 0x1c:
        set_return (_rsxnt_do_fork(f), f);
        break;

    /* void scrsize(EDX) */
    case 0x1d:
        __scrsize((int *)f->e.edx);
        break;

    /* void select(edx) errno:ecx */
    case 0x1e:
        set_return (__select((struct _select *) f->e.edx), f);
        break;

    /* eax syserrno(void) */
    case 0x1f:
        f->e.eax = 0;//__syserrno();
        break;

    /* eax stat(name_edx,struc_edi) errno:ecx */
    case 0x20:
        set_return (__stat((const char *)f->e.edx, (struct stat *)f->e.edi), f);
        break;

    /* eax fstat(ebx, edi) errno:ecx */
    case 0x21:
        set_return (__fstat(f->e.ebx, (struct stat *)f->e.edi), f);
        break;

    /* unused 0x22 */

    /* filesys(edx,edi,ecx) errno:ecx */
    case 0x23:
        set_return (__filesys((const char *)f->e.edx, (char *)f->e.edi, f->e.ecx), f);
        break;

    /* eax utimes(name_edx,struct tval esi) errno:ecx */
    case 0x24:
        set_return (__utimes((const char *) f->e.edx,
                        (const struct timeval *)f->e.esi), f);
        break;

    /* eax ftruncate(ebx,edx) errno:ecx */
    case 0x25:
        set_return (__ftruncate(f->e.ebx, f->e.edx), f);
        break;

    /* eax clock(void) err:no */
    case 0x26:
        f->e.eax = __clock();
        f->e.edx = 0;
        break;

    /* void ftime(edx) err:no */
    case 0x27:
        __ftime((struct timeb *)f->e.edx);
        break;

    /* eax umask(edx) err:no */
    case 0x28:
        f->e.eax = __umask(f->e.edx);
        break;

    /* eax getppid(void) err:no */
    case 0x29:
        f->e.eax = __getppid();
        break;

    /* void nls_memupr(buf edx,size ecx) err:no */
    case 0x2a:
        __nls_memupr ((unsigned char *) f->e.edx, f->e.ecx);
        break;

    /* eax open(edx, ecx) errno:ecx */
    case 0x2b:
        set_return (__open((const char *) f->e.edx, f->e.ecx, f->e.ebx), f);
        break;

    /* eax newthread(edx = tid) errno:ecx */
    case 0x2c:
        f->e.eax = f->e.ecx = 0;
        break;

    /* eax endthread(edx = tid) errno:ecx */
    case 0x2d:
        f->e.eax = f->e.ecx = 0;
        break;

    /* waitpid(pid_edx, options_ecx) ret: eax,ecx edx=status*/
    case 0x2e:
        {
            int status;
            f->e.eax = __waitpid(f->e.edx, &status, f->e.ecx);
            if (f->e.eax == -ECHILD) {
                f->e.ecx = - f->e.eax;
                f->e.eax = -1;
            } else {
                f->e.ecx = 0;
                f->e.edx = status;
            }
        }
        break;

    /* eax = readkbd(flags_edx) */
    case 0x2f:
        f->e.eax = __read_kbd(f->e.edx & 1, f->e.edx & 2,f->e.edx & 4);
        break;

    /* sleep2 ; eax = 0 */
    case 0x30:
        f->e.eax = __sleep2(f->e.edx);
        break;

    /* void unwind2(); */
    case 0x31:
        break;

    /* void pause(); err: eax=-1, return until signal handler */
    case 0x32:
        __pause();
        break;

    /* int execname(edx=buf, ecx=size); err=-1 */
    case 0x33:
        f->e.eax = __execname((char *)f->e.edx, (size_t)f->e.ecx);
        break;

    /* int initthread() */
    case 0x34:
        f->e.eax = f->e.ecx = 0;
        break;

    /* int sigaction(no ECX, in EDX, out EBX) */
    case 0x35:
        set_return (__sigaction(f->e.ecx, (const struct sigaction *)f->e.edx,
                        (struct sigaction *)f->e.ebx), f);
        break;

    /* int sigpending(in EDX) */
    case 0x36:
        set_return (__sigpending((sigset_t *)f->e.edx), f);
        break;

    /* int sigprocmask(how ECX, in EDX, out EBX) */
    case 0x37:
        set_return (__sigprocmask(f->e.ecx, (const sigset_t *) f->e.edx,
                            (sigset_t *) f->e.ebx), f);
        break;

    /* int sigsuspend(sigset_t EDX) */
    case 0x38:
        set_return (__sigsuspend((const sigset_t *) f->e.edx), f);
        break;

    /* import handle to C-runtime-lib */
    case 0x39:
        set_return (__imphandle(f->e.edx), f);
        break;

    /* internal emx fpu interface */
    case 0x3a:
        break;

    case 0x3b:
        set_return( __getsockhandle(f->e.ebx), f);
        break;

    case 0x3c:
        set_return( __socket(f->e.ecx, f->e.edx, f->e.ebx), f);
        break;

    case 0x3d:
        set_return( __bind(f->e.ebx, (struct sockaddr *) f->e.edx, f->e.ecx), f);
        break;

    case 0x3e:
        set_return( __listen(f->e.ebx, f->e.edx), f);
        break;

    case 0x3f:
        set_return( __recv(f->e.ebx, (void *) f->e.edx, f->e.ecx, f->e.esi), f);
        break;

    case 0x40:
        set_return( __send(f->e.ebx, (void *) f->e.edx, f->e.ecx, f->e.esi), f);
        break;

    case 0x41:
        set_return( __accept(f->e.ebx, (struct sockaddr *) f->e.edx, (int *) f->e.ecx), f);
        break;

    case 0x42:
        set_return( __connect(f->e.ebx, (struct sockaddr *) f->e.edx, f->e.ecx), f);
        break;

    case 0x43:
        set_return( __getsockopt(f->e.ebx, f->e.edx, f->e.ecx, (void *) f->e.esi, (int *) f->e.edi), f);
        break;

    case 0x44:
        set_return( __setsockopt(f->e.ebx, f->e.edx, f->e.ecx, (void *) f->e.esi, f->e.edi), f);
        break;

    case 0x45:
        set_return( __getsockname(f->e.ebx, (struct sockaddr *) f->e.edx, (int *) f->e.ecx), f);
        break;

    case 0x46:
        set_return( __getpeername(f->e.ebx, (struct sockaddr *) f->e.edx, (int *) f->e.ecx), f);
        break;

    case 0x47:
        set_return( __gethostbyname((char *) f->e.edx, (struct hostent **) f->e.ebx), f);
        break;

    case 0x48:
        set_return( __gethostbyaddr((char *) f->e.edx, f->e.ecx, f->e.esi, (struct hostent **)f->e.ebx), f);
        break;

    case 0x49:
        set_return( __getservbyname((char *) f->e.edx, (char *) f->e.ecx, (struct servent **) f->e.ebx), f);
        break;

    case 0x4a:
        set_return( __getservbyport(f->e.edx, (char *) f->e.ecx, (struct servent **) f->e.ebx), f);
        break;

    case 0x4b:
        set_return( __getprotobyname((char *) f->e.edx, (struct protoent **) f->e.ebx), f);
        break;

    case 0x4c:
        set_return( __getprotobynumber(f->e.edx, (struct protoent **) f->e.ebx), f);
        break;

    case 0x4d:
        set_return( __getnetbyname((char *) f->e.edx, (struct netent **) f->e.ebx), f);
        break;

    case 0x4e:
        set_return( __getnetbyaddr(f->e.edx, (struct netent **) f->e.ebx), f);
        break;

    case 0x4f:
        set_return( __gethostname((char *) f->e.edx, f->e.ecx), f);
        break;

    case 0x50:
        set_return( __gethostid((int *) f->e.ebx), f);
        break;

    case 0x51:
        set_return( __shutdown(f->e.ebx, f->e.edx), f);
        break;

    case 0x52:
        set_return( __recvfrom((struct _recvfrom *) f->e.edx), f);
        break;

    case 0x53:
        set_return( __sendto((struct _sendto *) f->e.edx), f);
        break;

    case 0x54:
        set_return( __impsockhandle(f->e.edx, f->e.ecx), f);
        break;

    /*
    case 0x55:
        // syscall AL=55H __recvmsg() -- NOT YET IMPLEMENTED
        break;

    case 0x56:
        // syscall AL=56H __sendmsg() -- NOT YET IMPLEMENTED
        break;
    */

    case 0x57:
        set_return (__ttyname(f->e.edx, (char *) f->e.edi, f->e.ecx), f);
        break;

    case 0x58:
        set_return (__settime((struct timeval *) f->e.edx), f);
        break;

    /* -----
    case 0x59:
        set_return (__profile((const struct _profil *) f->e.edx), f);
        break;
    ----- */

    case 0x5a:
        set_return (__nls_ctype((unsigned char *)f->e.edx), f);
        break;

    default:
        f->e.ecx = ENOSYS;
        f->e.eax = -1;
        f->e.eflags |= 1;
        return 0;
    }
    return 0;
}

