Little Big LAN Internal API

NETCLOCK Source code

        title netclock - LBL


cseg    segment public 'code'

        org 100h

        assume cs:cseg,ds:cseg,es:nothing

                             ;return code    0=good link
                             ;               1=link did not respond
                             ;               2=network not installed
                             ;               3=remote clock read was bad
                             ;               4=error writing local clock


entry   proc far

su1: jmp su1a

entry endp

waitime db 9  ;9 ticks
targetnode db 0
thisnode   db 0
retcode    db 0
msgmode    db 1


;       INT 14h   AH=0C0h     (or LBL Command 0)
;                 DX=0AB000H  (or LBL signature id)
;
;                 DS:SI-->   db  action (r/w)         +0
;                                .... .111 = check "alive"
;                                .... 1... = driver hit
;                                10.. .... = finished good (alive) 
;                                11.. .... = finished error (assume dead)
;                                00.. .... = if timeout, assume dead
;
;                            db  target node          +1
;                            db  channel              +2
;                            db  timeout              +3
;                            db  requesting node      +4
;                            db  type                 +5 (internal)
;                            db  target node          +6 (internal)


req db 7   ;0  action/flags
    db 0   ;1  target node
    db 0   ;2  channel
    db 0   ;3  timeout in ticks, 0 = no timeout
    db 0   ;4  requesting node (this node)
    db 0   ;5  type, set to 0
    db 0   ;6  internal
    db 0   ;7  reserved


subs proc near

su1a:
  call parms
  call get_sysreq
  jnc su1b

  mov dx,offset msg2
  jmp su3


su1b:
  call getnodename
  mov al,[si+1]
  mov cs:thisnode,al

  push cs
  pop ds
  mov si,offset req
  mov byte ptr [si],7
  mov al,targetnode
  mov [si+1],al
  mov byte ptr [si+2],1  ;channel 1  ... background fix:v1.0L
  mov al,waitime
  mov [si+3],al
  mov al,thisnode
  mov [si+4],al
  mov byte ptr [si+5],0   ;sendout mode

  mov dx,cs:netint_id
  mov ah,cs:netint_cmd
  call netint
  test cs:req,8           ;did any driver trap it?
  jnz w1                  ;no:    yes-->
                          ;error in drivers, on node# bad
  or cs:req,0C0h          ;force done, error
  jmp w1b

w1:
  test cs:req,80h   ;wait for done
  jz w1

  test cs:req,40h   ;is error?
  jnz w1b
  cmp cs:req+3,0FFh ;is nul tick?
  je su2            ;yes-->
  mov cs:req+3,1    ;force only 1 tick more

w1a:
  test cs:req,40h   ;wait timeout error
  jz w1a            ;(else will set bit later after exit!) 
  mov cs:req,80h
  jmp su2

w1b:
  mov cs:retcode,1


su2:
  push cs
  pop ds
  mov dx,offset msg0
  mov al,cs:retcode
  cmp al,0
  je su3

  mov dx,offset msg1

su3:
  cmp cs:retcode,0
  jne su3c

su3b:
  call readclock
  jc su3c

  call setclock


su3c:
  cmp cs:msgmode,1
  jne su4

  push cs
  pop ds
  mov ah,9
  int 21h

su4:
  mov ah,4ch
  mov al,cs:retcode
  int 21h

                             ;transfer description: R/W DEVICE
                             ;
                             ;REQUEST:
                             ;
                             ;target node         +0    HEADER
                             ;sending node        +1
                             ;module id           +2
                             ;transaction#        +3
                             ;command =  18       +4
                             ;
                             ;00                  +5    SPECIFIC
                             ;source device#      +6
                             ;targ device name    +7..14
                             ;write count         +15/16
                             ;read count          +17/18
                             ;write data          +19...
                             ;
                             ;
                             ;
                             ;ANSWER:
                             ;
                             ;target node         +0    HEADER
                             ;sending node        +1
                             ;module id           +2
                             ;transaction#        +3
                             ;command/code        +4
                             ;  92h = good
                             ;  D2h = bad
                             ;
                             ;00                  +5    SPECIFIC
                             ;source device#      +6
                             ;write status 0=ok   +7/8
                             ;count written       +9/10
                             ;read status         +11/12
                             ;count read          +13/14
                             ;read data           +15..


c_transmitter equ $ 

     db 0                ;action/flags        0
     db 0                ;routing link        1
     db 0                ;channel             2
     db 0                ;timeout             3
     dw 0                ;buffer ofs          4
     dw 0                ;       seg          6
     dw 0                ;count               8
     dw 0                ;current count       10
     dd 0                ;exec addr           12
     dw 0                ;link to companion   16
     dw 0                ; " seg              18
     dw 0                ;                    20
     dw 0                ;                    22
     dw 0                ;                    24 

reqpacket db 00          ;+0  target node     filled in by net21
          db 00          ;+1  sending node    "
          db 00          ;+2  module id       "
          db 00          ;+3  transaction#    "
          db 00          ;+4  command 18

          db 0          ;+5  type 00
          db 0          ;+6  source device#
          db "CLOCK$  " ;+7..14  target name
          dw 0          ;+15 write count
          dw 0          ;+17 read count
taddr     db 6 dup (0) ;+19 buffer
          db 0,0

devicenum   db 255
;........................... read from remote clock  ........................

readclock:
  mov si,offset reqpacket

  mov al,cs:targetnode       ;set target node
  mov [si],al
  mov byte ptr [si+4],18     ;command = CHAR I/O
  mov byte ptr [si+5],0      ;always 0
  mov al,cs:devicenum        ;set this device number
  mov [si+6],al

  mov ax,6
  mov [si+17],ax             ;set read count = 6 bytes
  mov word ptr [si+15],0     ;no write count

  mov di,offset c_transmitter ;es:di--> requestor
  push cs
  pop es

  mov word ptr es:[di+4],offset reqpacket ;set ptr to packet
  mov es:[di+6],cs
  mov byte ptr es:[di],0Eh   ;command = char i/o transfer
  mov word ptr es:[di+8],20  ;set packet count


  call wait_answer           ;send it, wait answer 
  jc read4                   ;if error-->
  
  lds si,dword ptr es:[di+4] ;ds:si--> answer packet
  test byte ptr [si],40h     ;is error in receiver?
  jc read4                   ;yes-->
  mov ax,[si+11]             ;get read status
  test ax,8000h
  jnz read3


  mov cx,[si+13]             ;get count transfered
  cmp cx,6
  jne read4

  lea si,[si+15]             ;ds:si--> bytes returned
  mov word ptr cs:rqh+14,si  ;setup seg:ofs of transfer addr
  mov word ptr cs:rqh+16,ds

  clc
  ret

read3:

read4:
  mov dx,offset msg6
  mov cs:retcode,3           ;return code (3) = error reading remote clock
  stc
  ret


lcall dw 0,0

                       ;DOS request header:
rqh     db 22          ;+0   len
        db 0           ;+1   unit
        db 4           ;+2   command = READ
        dw 0           ;+3   status
        db 8 dup(0)    ;+5   reserved   .... ....
        db 0           ;+13  
        dw taddr       ;+14  transfer addr
        dw 0           ;+16
        dw 6           ;+18  count
        dw 0           ;+20

;. . . . . . . . . . . . . . got good read of remote clock . . . . . . . . . .

setclock:
  mov ah,52h                 ;get DOS var list
  int 21h
  lds si,dword ptr es:[bx+8] ;ds:si--> local clock$ device
  push cs                    ;es:bx--> request header
  pop es
  mov bx,offset rqh
  mov byte ptr es:[bx+2],8   ;command = write
  mov word ptr es:[bx+3],0   ;zero status
  mov word ptr es:[bx+18],6  ;6 byte transfer


  mov ax,[si+6]              ;get strategy address
  mov cs:lcall,ax            ;form long call dword
  mov cs:lcall+2,ds
  call dword ptr cs:lcall    ;do strategy

  mov ax,[si+8]              ;get interrupt address
  mov cs:lcall,ax            ;form long call dword
  call dword ptr cs:lcall    ;do interrupt

  mov ax,es:[bx+3]           ;get status
  test ax,8000h              ;any errors?
  jz t2d                     ;yes:   no-->
  mov dx,offset msg7         ;print "ERROR WRITING LOCAL CLOCK"
  mov cs:retcode,4           ;return code (4) = error writing local clock
  ret

t2d:
  mov dx,offset msg0
  ret



event1 db 16 dup(0)  ;***
;........................... Wait for device to finish .......................

                             ;es:di--> raw transfer requestor (tmt)
                             ;cx = timeout

wait_answer:
  call swap_ptrs             ;ds:si--> raw transfer requestor (tmt)
  call netlink_0             ;start it
  call swap_ptrs             ;es:di--> raw transfer requestor
 
  les di,dword ptr es:[di+16] ;es:di--> answer requestor companion

  mov cx,200                 ;100 ticks

  mov si,cs
  mov ds,si
  mov si,offset event1       ;ds:si--> timeout event
  mov byte ptr [si],0        ;clear mode/flags
  mov [si+1],cx              ;set event countdown
  call netlink_2             ;start countdown
  sti

;. . . . . . . . . . . . . . LOOP: waiting
wait_ans2:
  test byte ptr es:[di],80h  ;is answer back?
  jnz wait_ans3              ;no:   yes-->
  test byte ptr cs:c_transmitter,40h ;is error in tmtr?
  jnz wait_ans2a             ;no:   yes-->
  test byte ptr [si],80h     ;is timeout?
  jz wait_ans2               ;yes:    no-->

wait_ans2a:
  call wait_time             ;forcs tick counter to end  fix:v1.0m
  stc                        ;ret error
  ret

wait_ans3:
  call wait_time             ;forcs tick counter to end  fix:v1.0m
  clc
  ret

;fix:v1.0m    add to kill tick service

wait_time:
  mov word ptr [si+1],9      ;set event countdown = 1 tick

wait_time2:
  test byte ptr [si],80h     ;is timeout?
  jz wait_time2              ;yes:    no-->

  push es
  pop ds
  mov si,di
  mov byte ptr [si],3        ;clear rcvr
  call netlink_0             ;
  push cs
  pop ds
  mov si,offset req
  mov byte ptr [si],2        ;clr tmtr
  call netlink_0             ;

  ret


;.......................... swap_ptrs ...................................

swap_ptrs:
  push di
  push si
  pop di
  pop si

;........................... swap_esds ...................................

swap_esds:
  push es
  push ds
  pop es
  pop ds
  ret


netintc:
  mov dx,cs:netint_id
  jmp netint

;........................... netlink_0 .......................................

netlink_0:
  push dx
  push ax
  mov ah,cs:netint_cmd
  call netintc
  pop ax
  pop dx
  ret

;........................... netlink_2 .......................................

netlink_2:
  push dx
  push ax 
  mov ah,cs:netint_cmd+2
  call netintc
  pop ax
  pop dx
  ret



msg0 db "CLOCK SET TO NETWORK TIME.",13,10,"$"
msg1 db "NETWORK CLOCK Node is DEAD.",13,10,"$"
msg2 db "NETWORK is not properly installed!",13,10,"$"
msg6 db "ERROR READING NETWORK CLOCK",13,10,"$"
msg7 db "ERROR WRITING LOCAL CLOCK",13,10,"$"

;........................... Get setup parameters ............................

parms:
  cld
  push cs
  pop es
  push cs
  pop ds
  xor cx,cx                  ;cx will = # of chars in line
  mov si,81h                 ;ds:si --> command line
  mov cl,[si-1]              ;get count

parms1:
  call nxtchar               ;get next char
  jnc parms1a                ;if no more, return
  ret

parms1a:

parms2:
  cmp al,"N"                 ;*****  is NODE:x ? *****
  jne parms3
  call nxtchar
  cmp al,"O"
  jne parms2a
  call nxtchar
  cmp al,"D"
  jne parms2a
  call nxtchar
  cmp al,"E"
  jne parms2a
  call nxtchar
  cmp al,":"
  jne parms2a

  call getnum
  mov cs:targetnode,dl
  jmp parms1

parms2a:
  jmp parms1a

parms3:
  cmp al,"W"                 ;*****  is WAIT:x ? *****
  jne parms4
  call nxtchar
  cmp al,"A"
  jne parms3a
  call nxtchar
  cmp al,"I"
  jne parms3a
  call nxtchar
  cmp al,"T"
  jne parms3a
  call nxtchar
  cmp al,":"
  jne parms3a

  call getnum
  mov cs:waitime,dl
  jmp parms1

parms3a:
  jmp parms1a


parms4:
  jmp parms1





netint_vec db 14h     ;0
netint_id  dw 0AB00h  ;1/2
           db 5       ;3
netint_cmd db 0C0h    ;4
           db 0C1h    ;5
           db 0C2h    ;6
           db 0C3h    ;7
           db 0C4h    ;8

netint_fix equ $+1

netint:
  int 14h
  ret


;........................... get_sysreq .......................................

                             ;The Little Big LAN will be able to use any
                             ;interrupt to pass LAN system requests.  NET00000
                             ;keeps that information so that all drivers
                             ;can lookup the system request interrupt.
                             ;The device name NET0 is used.
net0name db "NET0",0
net0cmd1 db 1

get_sysreq:
  push cs
  pop ds
  mov dx,offset net0name     ;ds:dx--> device to read
  mov ax,3D02h               ;open for read/write
  int 21h
  jnc get_srq2               ;open ok-->
  mov cs:retcode,2
  ret

get_srq2:
  mov bx,ax                  ;bx=handle
;- - - - - - - - - - - -     ;can't be in cooked mode !!!
  mov ax,4400h               ;get device info
  int 21h
  test dl,80h                ;must be char device
  jz get_srq4                ;if not-->
  or dl,20h                  ;binary mode
  xor dh,dh                  ;dos fails if dh<>0!!!
  mov ax,4401h               ;set device info
  int 21h
;- - - - - - - - - - - -
  push cs
  pop ds
  mov dx,offset net0cmd1     ;command = set "read sysreq mode"
  mov cx,1                   ;1 byte
  mov ah,40h                 ;write to device
  int 21h
  jc get_srq4

  mov cx,9                   ;9 bytes
  push cs
  pop ds
  mov dx,offset netint_vec
  mov ah,3Fh                 ;read sysreq info
  int 21h
  jc get_srq4

  mov al,cs:netint_vec       ;fix INT XX code
  or al,al                   ;can't be INT 0!
  jz get_srq4

  mov byte ptr cs:netint_fix,al
  mov ah,3Eh                 ;close
  int 21h
  clc
  ret

get_srq4:
  mov ah,3Eh                 ;close
  int 21h
  stc
  ret

;........................... getnodename ....................................

getnodename:
  push cs
  pop ds
  mov si,offset requestor
  mov byte ptr [si],1     ;get node info
  mov ah,netint_cmd+4
  mov dx,netint_id
  call netint
  test byte ptr [si],40h     ;error?
  jz gnn2                    ;yes:   no-->

  stc
  ret

gnn2:
  xor ah,ah
  mov al,[si+1]              ;get node#
  or al,al                   ;is any?
  jnz gnn3                   ;no:   yes-->

gnn3:
  mov [si+1],al              ;set node

  ret
  

requestor equ $

  db 64 dup (0)


;........................... Get next char ...................................

nxtchar:
  jcxz nc10                  ;if no more chars in buffer-->
  lodsb                      ;get next char
  dec cx                     ;decrement count remaining
  cmp al,13                  ;is CR ?
  jz nc9                     ;no:             yes-->
  cmp al,"a"                 ;force to CAPs
  jc nc8
  cmp al,"z"+1
  jnc nc8
  xor al,20h

nc8:
  clc                        ;return good
  ret

nc9:
  dec si                     ;dont go passed CR
  xor cx,cx                  ;no more chars

nc10:
  stc                        ;return, none found
  ret

;........................... Get number .....................................

getnum:
  xor dx,dx                  ;init number = 0

gn1:
  jcxz gn9                   ;are any chars left?  no-->        fix:12/13/89
  lodsb                      ;yes, get next one                 changed to new
  dec cx                     ;dec # left
  mov ah,al                  ;save char
  sub ah,"0"                 ;adjust ascii to number
  jc gn8                     ;was char < "0" ?   yes-->
  cmp ah,10                  ;is char  > "9" ?   
  jnc gn8                    ;                   yes-->

  push ax
  mov ax,10                  ;decimal shift left
  mul dx
  mov dx,ax
  pop ax
  add dl,ah                  ;add in ones
  adc dh,0
  jmp gn1                    ;see if more

gn8:
  dec si                     ;restore buffer ptr
  inc cx                     ;restore # remaining

gn9:
  ret

;........................... gethexnum .......................................

gethexnum:
  xor dx,dx

gh1:
  call nxtchar
  jc gh9

  mov ah,al

  sub al,"0"
  jc gh8
  cmp al,10
  jc gh4
  add al,"0"
  sub al,"A"
  jc gh8
  cmp al,6
  jnc gh8
  add al,10

gh4:
  shl dx,1
  shl dx,1
  shl dx,1
  shl dx,1
  add dl,al
  adc dh,0
  jmp gh1
  

gh8:
  dec si
  inc cx

gh9:
  ret


uptr dw 0



;........................... ishexdigit ...................................

ishexdigit:
  sub al,"A"                 ;is char A..F ?
  jc ihd9
  cmp al,6
  jnc ihd9                   ;yes:      no-->
  add al,10                  ;al = A..F hex nibble
  clc
  ret

ihd9:
  add al,"A"
  stc
  ret

;........................... isdecdigit ...................................

isdecdigit:
  sub al,"0"                 ;is char out of range  (too small) ?
  jc idd9                    ;no:   yes-->
  cmp al,10                  ;is char 0..9?
  jnc idd9                   ;yes     no-->

  clc
  ret

idd9:
  add al,"0"
  stc
  ret

;........................... getanynum ....................................

getanynum:
  push si                    ;save $ ptr
  push cx
                             ;find eos
geta1:
  call nxtchar
  jc geta2
  call isdecdigit
  jnc geta1
  call ishexdigit
  jnc geta1

geta2:
  pop cx                     ;restore ptr
  pop si

  cmp al,"H"                 ;did number end on "H"ex ?
  je geta3                   ;no:    yes-->

  call getnum
  ret

geta3:
  call gethexnum
  call nxtchar
  ret



subs endp


cseg ends
     end su1

Top of Programmer Stuff -or- Main Table of Contents -or- Top of Form