!  File  MOUSE:ETHER

! Ethernet Interface Module

%option "-low-nocheck-nodiag"

!!%routinespec etherstop(%record(*)%name s)
%Include "mouse.inc"

%Recordformat reqfm ((%Byte code %or %byte result),
                     %Byte port,
                     (%Byte rdte %or %Byte port0mode),
                     (%Byte rsap %or %Byte channel),
                     (%Integer length %OrInteger maxbytes %orinteger resbytes),
                     %bytearray b(0:532))

%ownrecord(mailboxfm)%Name  ombox==NIL, imbox == NIL
%ownrecord(semaphorefm)%name sem==NIL
%ownrecord(messagefm)%name msg == NIL
%ownrecord(reqfm)%name req == NIL

{*Back-compatibility stuff*}
@16_3fa9 %byte lsap
@16_35c4 %short userno
@744(a5) %integer ethergla
%externalstring(255)%fnspec current directory
%externalroutinespec set directory(%string(255)s)
%routinespec back compat setup

!!%routine Ether Stop (%record(*)%name x)
!!  %unless imbox==nil %start
!!    delete semaphore(sem); sem == nil
!!    delete mailbox(imbox); imbox == nil
!!  %finish
!!%end

%routine Ether Start
!!%record(exit handler fm)%name xh
   %returnunless imbox==nil
   ethergla = a4
   ombox == lookup kernel object("Ether mailbox")
   sem == create semaphore(0)
   imbox == create mailbox(sem)
   back compat setup
!!   xh == create exit handler(ether stop,nil)
%End

%routine get
  msg == get message buffer
  req == record(addr(msg_data))
%end

%routine put
  put message buffer(msg)
  msg == nil
  req == nil
%end

%constinteger -
   Success           =  0,
   Undefined Error   =  1,
   Bad Function Code =  2,
   Bad Port Number   =  3,
   Port not owned    =  4,
   No Free Port      =  5,
   Port already owned=  6,
   Packet was NAKed  =  7,
   Port was closed   =  8,
   Port was open     =  9,
   Bad Transmit Length=10,
   abort             = 11,
   bus error         = 12

%conststring(31)%array  errors(0:12) = 
   "success",
   "undefined error",
   "bad function code",
   "bad port number",
   "port not owned",
   "no free port",
   "port already owned",
   "packet was NAKed",
   "port was closed",
   "port was open",
   "bad transmit length",
   "receive abort",
   "bus error"

%Routine Transact
%integer i
   ether start %if ombox == NIL
   msg_reply == imbox
   send message (msg,ombox)
   msg == receive message (imbox)
   req == record(addr(msg_data))
   i = req_result
   put %and %Signal 3,5,i,errors(i) %unless i=success
%End

%externalroutine EtherTransmitBlock -
  (%integer Port,Bytes,%bytename Buffer)
%integer i
   get
   req_code    = 5
   req_port    = port
   req_length  = bytes
   req_b(i) = buffer[i] %for i = 0,1,bytes -1
   transact
   put
%end

%externalroutine EtherReceiveBlock -
  (%integer Port,MaxBytes,%integername Bytes,%ByteName Buffer)
%integer i
   get
   req_code    = 6
   req_port    = port
   req_maxbytes= maxbytes
   transact
   bytes = req_resbytes
   buffer[i] = req_b(i) %for i = 0,1,bytes-1
   put
%end

%externalroutine EtherOpenPort (%integer Port,RemoteStation,RemotePort)
   get
   req_code = 3
   req_port = port
   req_rdte = Remote Station
   req_rsap = Remote Port
   transact
   lsap = port
   put
%end

%externalroutine EtherClosePort (%integer Port)
   get
   req_code = 4
   req_port = port
   transact
   put
%end

%externalroutine EtherClaimPort (%integer port)
   get
   req_code = 1
   req_port = port
   transact
   put
%end

%externalintegerfn EtherAllocatePort
%integer port
   get
   req_code =1
   req_port = 255
   transact
   port = req_port
   put
   %Result = port
%end

%externalroutine Ether Allocate Zero
   Ether Claim Port (0)
%End

%externalroutine EtherFreePort (%integer Port)
   get
   req_code = 2
   req_port = port
   transact
   put
%end

%externalintegerfn EtherStationAddress
%integer port
   get
   req_code = 7
   transact
   port = req_port
   put
   %result = port
%end

%routine back compat setup

%routine etherclose (%integer port)
  ether close port (port)
  ether free port (port)
%end

%routine etheropen (%integer port,remote)
%integer error=0
  %on 3 %start
    %signal 3,event_sub,event_extra,event_message %unless error=0
    error = 1
    etherclose(port)
  %finish
  ether claim port (port)
  ether open port (port, remote>>8, remote&255)
%end

%routine etherwrite(%integer port,bytes,%bytename buffer)
  ether transmit block (port,bytes,buffer)
%end

%integerfn etherread(%integer port,maxbytes,%bytename buffer)
%integer bytes
  ether receive block (port,maxbytes,bytes,buffer)
  %result = bytes
%end

%integerfn fcomm(%integer cn,%string(255)s)
! J (SETDIR) is intercepted and used to alter the locally held prefix.
! O (COPY) has the current default prefixed to both filenames if needed.
! B (RENAME) does this only to the first filename (such that it will work
!            on the old filestores (The proper RENAME routine does not use
!            FCOMM and will work on both styles of filestore).
! Other commands involving a filename are treated similarly (ACDESTV).
%string(255)f,a,x
%integer c
%bytename b == length(s)
  c = cn>>8&95
  %if c='J' %start
    set directory(s)
!!  %result = 0
  %finish
  %if c='O' %start{copy file comma file}
    s -> f.(",").a
    x = current directory
    f = x.f %unless f -> (":")
    a = x.a %unless a -> (":")
    s = f.",".a
  %elseif 1<<(c-64)&2_10110000000000000111110#0
!                     VUTSRQPONMLKJIHGFEDCBA@
    f = s; a = ""; a = ",".a %if s -> f.(",").a
    x = current directory
    f = x.f %unless f -> (":")
    s = f.a
  %finish
  s = "XX".s; b[1] = cn>>8; b[2] = cn&255; b[2] = userno+'0' %if b[2]=0
  b = b+1; b[b] = nl
  etherwrite(lsap,b,b[1])
  b = etherread(lsap,255,b[1])
  %if b[1]='-' %start
    s = "FCOMM fails: ".s; %signal 3,4,0,s
  %finish
  userno = b[1]-'0' %if cn>>8='L'
  userno = 0 %if cn>>8='M'
  %result = 0 %if b=1
  %result = b[1]-'0'
%end

%routine fcommw(%integer cn,%string(255)s,%bytename buffer,%integer size)
%bytearray bu(1:538)
%bytename b == bu(1)
%integer i
  b = cn>>8; b == b[1]
  b = cn&255; b == b[1]
  b = charno(s,i) %and b == b[1] %for i = 1,1,length(s)
  b = size>>4+'0'; b[1] = size&15+'0'; b[2] = nl; i = i+5
  b == bu(1)
  move(size,buffer,b[i])
  etherwrite(lsap,size+i,b)
  b == length(s)
  b = etherread(lsap,255,b[1])
  %if b[1]='-' %start
    s = "FCOMMW fails: ".s; %signal 3,4,0,s
  %finish
%end

%integerfn fcommr(%integer cn,%string(255)s,%bytename buffer,%integer size)
! F (FINFO) uses the current directory if S does not contain one.
! N (NINFO) uses it if it needs to (as for FCOMM).
%string(255)x
%bytearray bu(1:538)
%bytename b == length(s)
%integer n=0,i
  i = cn>>8&95
  %if i='F' %start
    %if s="" %or charno(s,1)=',' %start
      x = current directory
      length(x) = length(x)-1 %if charno(x,length(x))=':' {normally the case}
      s = x.s
    %finish
  %elseif i='N' %andnot s -> (":")
    x = current directory
    s = x.s
  %finish
  s = "XX".s; b[1] = cn>>8; b[2] = cn&255
  b[2] = userno+'0' %if b[2]<='0'; b = b+1; b[b] = nl
  etherwrite(lsap,b,b[1])
  b == bu(1)
  i = etherread(lsap,538,b)
  %if b='-' %start
    s = "FCOMMR fails: "; s = s.tostring(b) %and b==b[1] %until b=nl
    %signal 3,4,bu(2)-'0',s
  %finish
  %while b>='0' %cycle
    n = n<<4+b-'0'; b == b[1]; i = i-1
  %repeat
  i = i-1
  %unless i=n %start
    %signal 3,4,i-n,"FCOMMR size discrepancy"
  %finish
  i = size %if size<i
  move(i,b[1],buffer)
  %result = n
%end

%routine xcode(%integer n {, %routine(*) A0})
  *muls #-6,d0
  *lea 16_3f00,a1
  *move.w #16_4ef9,0(a1,d0.l)
  *move.l a0,2(a1,d0.l)
%end

%routine eo
  *movem.l d0-a7/a0-a6,-(sp)
  *moveq #0,d4
  *move.l #16_80808080,d7
  *move.l ethergla,a4
  *jsr etheropen
  *movem.l (sp)+,d0-a7/a0-a6
%end

%routine ec
  *movem.l d0-a7/a0-a6,-(sp)
  *moveq #0,d4
  *move.l #16_80808080,d7
  *move.l ethergla,a4
  *jsr etherclose
  *movem.l (sp)+,d0-a7/a0-a6
%end

%routine ew
  *movem.l d0-a7/a0-a6,-(sp)
  *moveq #0,d4
  *move.l #16_80808080,d7
  *move.l ethergla,a4
  *jsr etherwrite
  *movem.l (sp)+,d0-a7/a0-a6
%end

%routine er
  *movem.l d1-a7/a0-a6,-(sp)
  *moveq #0,d4
  *move.l #16_80808080,d7
  *move.l ethergla,a4
  *jsr etherread
  *movem.l (sp)+,d1-a7/a0-a6
%end

%routine fc
  *movem.l d1-a7/a0-a6,-(sp)
  *moveq #0,d4
  *move.l #16_80808080,d7
  *move.l ethergla,a4
  *jsr fcomm
  *movem.l (sp)+,d1-a7/a0-a6
%end

%routine fcw
  *movem.l d0-a7/a0-a6,-(sp)
  *moveq #0,d4
  *move.l #16_80808080,d7
  *move.l ethergla,a4
  *jsr fcommw
  *movem.l (sp)+,d0-a7/a0-a6
%end

%routine fcr
  *movem.l d1-a7/a0-a6,-(sp)
  *moveq #0,d4
  *move.l #16_80808080,d7
  *move.l ethergla,a4
  *jsr fcommr
  *movem.l (sp)+,d1-a7/a0-a6
%end

  *lea eo,a0;  xcode(39)
  *lea ec,a0;  xcode(40)
  *lea ew,a0;  xcode(41)
  *lea er,a0;  xcode(42)
  *lea fc,a0;  xcode(43)
  *lea fcw,a0; xcode(44)
  *lea fcr,a0; xcode(45)

%End
