home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / lan / driver6s / head.asm < prev    next >
Assembly Source File  |  1990-03-15  |  20KB  |  883 lines

  1.     include    defs.asm
  2.  
  3. ;  Copyright, 1988-9, 1990, Russell Nelson
  4.  
  5. ;   This program is free software; you can redistribute it and/or modify
  6. ;   it under the terms of the GNU General Public License as published by
  7. ;   the Free Software Foundation, version 1.
  8. ;
  9. ;   This program is distributed in the hope that it will be useful,
  10. ;   but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. ;   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12. ;   GNU General Public License for more details.
  13. ;
  14. ;   You should have received a copy of the GNU General Public License
  15. ;   along with this program; if not, write to the Free Software
  16. ;   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17.  
  18. code    segment byte public
  19.     assume    cs:code, ds:code
  20.  
  21.     public    phd_environ
  22.     org    2ch
  23. phd_environ    dw    ?
  24.  
  25.     public    phd_dioa
  26.     org    80h
  27. phd_dioa    label    byte
  28.  
  29.     org    100h
  30. start:
  31.     jmp    start_1
  32.     extrn    start_1: near
  33.  
  34. ;we use our dioa for a stack space.  Very hard usage has shown that only
  35. ;  27 bytes were being used, so 128 should be sufficient.
  36. our_stack    label    byte
  37.  
  38.  
  39.     extrn    int_no: byte
  40.     public    packet_int_no, is_at, sys_features
  41. packet_int_no    db    ?,?,?,?        ; interrupt to communicate.
  42. is_at        db    0        ; =1 if we're on an AT.
  43. sys_features    db    0        ; 2h = MC   40h = 2nd 8259
  44.  
  45. functions    label    word
  46.     dw    f_not_implemented
  47.     dw    f_driver_info
  48.     dw    f_access_type
  49.     dw    f_release_type
  50.     dw    f_send_pkt
  51.     dw    f_terminate
  52.     dw    f_get_address
  53.     dw    f_reset_interface
  54.     dw    f_not_implemented
  55.     dw    f_not_implemented
  56.     dw    f_get_parameters
  57.     dw    f_as_send_pkt
  58.     dw    f_not_implemented
  59.     dw    f_not_implemented
  60.     dw    f_not_implemented
  61.     dw    f_not_implemented
  62.     dw    f_not_implemented
  63.     dw    f_not_implemented
  64.     dw    f_not_implemented
  65.     dw    f_not_implemented
  66.     dw    f_set_rcv_mode
  67.     dw    f_get_rcv_mode
  68.     dw    f_set_multicast_list
  69.     dw    f_get_multicast_list
  70.     dw    f_get_statistics
  71.     dw    f_set_address
  72.  
  73.     extrn    driver_class: byte
  74.     extrn    driver_type: byte
  75.     extrn    driver_name: byte
  76.     extrn    driver_function: byte
  77.     extrn    parameter_list: byte
  78.  
  79.     extrn    send_pkt: near
  80.     extrn    get_address: near
  81.     extrn    set_address: near
  82.     extrn    terminate: near
  83.     extrn    reset_interface: near
  84.     extrn    recv: near
  85.     extrn    recv_exiting: near
  86.  
  87.     extrn    rcv_modes: word        ;count of modes followed by mode handles.
  88.  
  89.     extrn    set_multicast_list: near
  90.  
  91. linc    macro    n            ; inc a 32 bit integer
  92.     local    a
  93.     inc    n            ;increment the low word
  94.     jne    a            ;go if not overflow
  95.     inc    n+2            ;increment the high word
  96. a:
  97.     endm
  98.  
  99. per_handle    struc
  100. in_use        db    0        ;non-zero if this handle is in use.
  101. packet_type    db    MAX_P_LEN dup(0);associated packet type.
  102. packet_type_len    dw    0        ;associated packet type length.
  103. receiver    dd    0        ;receiver handler.
  104. per_handle    ends
  105.  
  106. handles        per_handle max_handle dup(<>)
  107. end_handles    label    byte
  108.  
  109.     public    multicast_count, multicast_addrs, multicast_broad
  110. multicast_count    dw    0        ;count of stored multicast addresses.
  111. multicast_broad    db    0ffh,0ffh,0ffh,0ffh,0ffh,0ffh    ; entry for broadcast
  112. multicast_addrs    db    MAX_MULTICAST*EADDR_LEN dup(?)
  113.  
  114. have_my_address    db    0        ;nonzero if our address has been set.
  115. my_address    db    MAX_ADDR_LEN dup(?)
  116. my_address_len    dw    ?
  117.  
  118. rcv_mode_num    dw    3
  119.  
  120. free_handle    dw    0        ; temp, a handle not in use
  121. found_handle    dw    0        ; temp, handle for our packet
  122. receive_ptr    dd    0        ; the pkt receive service routine
  123.  
  124. statistics_list    label    dword
  125. packets_in    dw    ?,?
  126. packets_out    dw    ?,?
  127. bytes_in    dw    ?,?
  128. bytes_out    dw    ?,?
  129. errors_in    dw    ?,?
  130. errors_out    dw    ?,?
  131. packets_dropped    dw    ?,?        ;dropped due to no type handler.
  132.  
  133. savess        dw    ?        ;saved during the stack swap.
  134. savesp        dw    ?
  135.  
  136. regs    struc                ; stack offsets of incoming regs
  137. _ES    dw    ?
  138. _DS    dw    ?
  139. _BP    dw    ?
  140. _DI    dw    ?
  141. _SI    dw    ?
  142. _DX    dw    ?
  143. _CX    dw    ?
  144. _BX    dw    ?
  145. _AX    dw    ?
  146. _IP    dw    ?
  147. _CS    dw    ?
  148. _F    dw    ?            ; flags, Carry flag is bit 0
  149. regs    ends
  150.  
  151. CY    equ    0001h
  152. EI    equ    0200h
  153.  
  154.  
  155. bytes    struc                ; stack offsets of incoming regs
  156.     dw    ?            ; es, ds, bp, di, si are 16 bits
  157.     dw    ?
  158.     dw    ?
  159.     dw    ?
  160.     dw    ?
  161. _DL    db    ?
  162. _DH    db    ?
  163. _CL    db    ?
  164. _CH    db    ?
  165. _BL    db    ?
  166. _BH    db    ?
  167. _AL    db    ?
  168. _AH    db    ?
  169. bytes    ends
  170.  
  171.     public    our_isr, their_isr
  172. their_isr    dd    0        ; original owner of pkt driver int
  173.  
  174. our_isr:
  175.     jmp    our_isr_0        ;the required signature.
  176.     db    'PKT DRVR',0
  177. our_isr_0:
  178.     assume    ds:nothing
  179.     push    ax
  180.     push    bx
  181.     push    cx
  182.     push    dx
  183.     push    si
  184.     push    di
  185.     push    bp
  186.     push    ds
  187.     push    es
  188.     cld
  189.     mov    bx,cs            ;set up ds.
  190.     mov    ds,bx
  191.     assume    ds:code
  192.     mov    bp,sp            ;we use bp to access the original regs.
  193.     and    _F[bp],not CY        ;start by clearing the carry flag.
  194.     mov    bl,ah            ;jump to the correct function.
  195.     mov    bh,0
  196.     cmp    bx,25            ;only twenty five functions right now.
  197.     mov    dh,BAD_COMMAND        ;in case we find a bad number.
  198.     ja    our_isr_error
  199.     add    bx,bx            ;*2
  200.     call    functions[bx]
  201.     jnc    our_isr_return
  202. our_isr_error:
  203.     mov    _DH[bp],dh
  204.     or    _F[bp],CY        ;return their carry flag.
  205. our_isr_return:
  206.     pop    es
  207.     pop    ds
  208.     pop    bp
  209.     pop    di
  210.     pop    si
  211.     pop    dx
  212.     pop    cx
  213.     pop    bx
  214.     pop    ax
  215.     iret
  216.  
  217.  
  218. f_not_implemented:
  219.     mov    dh,BAD_COMMAND
  220.     stc
  221.     ret
  222.  
  223.  
  224. f_driver_info:
  225. ;    As of 1.08, the handle is optional, so we no longer verify it.
  226. ;    call    verify_handle
  227.     cmp    _AL[bp],0ffh        ; correct calling convention?
  228.     jne    f_driver_info_1        ; ne = incorrect, fail
  229.     mov    _BX[bp],majver        ;version
  230.     mov    al,driver_class
  231.     mov    _CH[bp],al
  232.     mov    al,driver_type
  233.     cbw
  234.     mov    _DX[bp],ax
  235.     mov    _CL[bp],0        ;number zero.
  236.     mov    _DS[bp],ds        ; point to our name in their ds:si
  237.     mov    _SI[bp],offset driver_name
  238.     mov    al,driver_function
  239.     mov    _AL[bp],al
  240.     clc
  241.     ret
  242. f_driver_info_1:
  243.     stc
  244.     ret
  245.  
  246.  
  247. f_set_rcv_mode:
  248.     call    verify_handle
  249.     mov    cx,_CX[bp]        ;Tell them how much room they have.
  250.     cmp    cx,rcv_modes        ;do they have this many modes?
  251.     jae    f_set_rcv_mode_1    ;no - must be a bad mode for us.
  252.     mov    bx,cx
  253.     add    bx,bx            ;we're accessing words, not bytes.
  254.     mov    ax,rcv_modes[bx]+2    ;get the handler for this mode.
  255.     or    ax,ax            ;do they have one?
  256.     je    f_set_rcv_mode_1    ;no - must be a bad mode for us.
  257.     mov    rcv_mode_num,cx        ;yes - remember the number and
  258.     call    ax            ;  call it.
  259.     clc
  260.     ret
  261. f_set_rcv_mode_1:
  262.     mov    dh,BAD_MODE
  263.     stc
  264.     ret
  265.  
  266.  
  267. f_get_rcv_mode:
  268.     call    verify_handle
  269.     mov    ax,rcv_mode_num        ;return the current receive mode.
  270.     mov    _AX[bp],ax
  271.     clc
  272.     ret
  273.  
  274.  
  275. f_set_multicast_list:
  276. ;    mov    cx,_CX[bp]        ;Tell them how much room they have.
  277.  
  278. ;verify that they supplied an even number of EADDR's.
  279.     mov    ax,cx
  280.     xor    dx,dx
  281.     mov    bx,EADDR_LEN
  282.     div    bx
  283.     or    dx,dx            ;zero remainder?
  284.     jne    f_set_multicast_list_2    ;no, we don't have an even number of
  285.                     ;  addresses.
  286.  
  287.     cmp    ax,MAX_MULTICAST    ;is this too many?
  288.     ja    f_set_multicast_list_3    ;yes - return NO_SPACE
  289. f_set_multicast_list_1:
  290.     mov    multicast_count,ax    ;remember the number of addresses.
  291.     push    cs
  292.     pop    es
  293.     mov    di,offset multicast_addrs
  294.     push    ds
  295.     mov    ds,_ES[bp]        ; get ds:si -> new list.
  296.     mov    si,_DI[bp]
  297.     push    cx
  298.     rep    movsb
  299.     pop    cx
  300.     pop    ds
  301.  
  302.     mov    si,offset multicast_addrs
  303.     call    set_multicast_list
  304.     ret
  305. f_set_multicast_list_2:
  306.     mov    dh,BAD_ADDRESS
  307.     stc
  308.     ret
  309. f_set_multicast_list_3:
  310.     mov    dh,NO_SPACE
  311.     stc
  312.     ret
  313.  
  314.  
  315. f_get_multicast_list:
  316.     mov    _ES[bp],ds        ;return what we have remembered.
  317.     mov    _DI[bp],offset multicast_addrs
  318.     mov    ax,EADDR_LEN        ;multiply the count by the length.
  319.     mul    multicast_count
  320.     mov    _CX[bp],ax        ;because they want total bytes.
  321.     clc
  322.     ret
  323.  
  324.  
  325. f_get_statistics:
  326.     call    verify_handle        ;just in case.
  327.     mov    _DS[bp],ds
  328.     mov    _SI[bp],offset statistics_list
  329.     clc
  330.     ret
  331.  
  332.  
  333. access_type_class:
  334.     mov    dh,NO_CLASS
  335.     stc
  336.     ret
  337.  
  338. access_type_type:
  339.     mov    dh,NO_TYPE
  340.     stc
  341.     ret
  342.  
  343. access_type_number:
  344.     mov    dh,NO_NUMBER
  345.     stc
  346.     ret
  347.  
  348. access_type_bad:
  349.     mov    dh,BAD_TYPE
  350.     stc
  351.     ret
  352.  
  353. access_type_space:
  354.     mov    dh,NO_SPACE
  355.     stc
  356.     ret
  357.  
  358. ;register caller of pkt TYPE
  359. f_access_type:
  360.     mov    al,driver_class
  361.     cmp    _AL[bp],al        ;our class?
  362.     jne    access_type_class    ;no.
  363.     cmp    _BX[bp],-1        ;generic type?
  364.     je    access_type_2        ;yes.
  365.     mov    al,driver_type
  366.     cbw
  367.     cmp    _BX[bp],ax        ;our type?
  368.     jne    access_type_type    ;no.
  369. access_type_2:
  370.     cmp    _DL[bp],0        ;generic number?
  371.     je    access_type_3
  372.     cmp    _DL[bp],1        ;our number?
  373.     jne    access_type_number
  374. access_type_3:
  375.     cmp    _CX[bp],MAX_P_LEN    ;is the type length too long?
  376.     ja    access_type_bad        ;yes - can't be ours.
  377.  
  378. ; now we do two things--look for an open handle, and check the existing
  379. ; handles to see if they're replicating a packet type.
  380.  
  381.     mov    free_handle,0        ;remember no free handle yet.
  382.     mov    bx,offset handles
  383. access_type_4:
  384.     cmp    [bx].in_use,0        ;is this handle in use?
  385.     je    access_type_5        ;no - don't check the type.
  386.     mov    es,_DS[bp]        ;get a pointer to their type
  387.     mov    di,_SI[bp]        ;  from their ds:si to our es:di
  388.     mov    cx,_CX[bp]        ;get the minimum of their length
  389.                     ;  and our length.  As currently
  390.                     ;  implemented, only one receiver
  391.                     ;  gets the packets, so we have to
  392.                     ;  ensure that the shortest prefix
  393.                     ;  is unique.
  394.     cmp    cx,[bx].packet_type_len    ;Are we less specific than they are?
  395.     jb    access_type_8        ;no.
  396.     mov    cx,[bx].packet_type_len    ;yes - use their count.
  397. access_type_8:
  398.     lea    si,[bx].packet_type
  399.     or    cx,cx            ; pass-all TYPE? (zero TYPE length)
  400.     jne    access_type_7        ; ne = no
  401.     mov    bx,offset handles+(max_handle -1)*(size per_handle)
  402.     jmp    short access_type_5    ; put pass-all last
  403. access_type_7:
  404.     repe    cmpsb
  405.     jne    short access_type_6    ;go look at the next one.
  406. access_type_inuse:
  407.     mov    dh,TYPE_INUSE        ;a handle has been assigned for TYPE
  408.     stc                ;and we can't assign another
  409.     ret
  410. access_type_5:                ;handle is not in use
  411.     cmp    free_handle,0        ;found a free handle yet?
  412.     jne    access_type_6        ;yes.
  413.     mov    free_handle,bx        ;remember a free handle
  414. access_type_6:
  415.     add    bx,(size per_handle)    ;go to the next handle.
  416.     cmp    bx,offset end_handles    ;examined all handles?
  417.     jb    access_type_4        ;no, continue.
  418.  
  419.     mov    bx,free_handle        ;did we find a free handle?
  420.     or    bx,bx
  421.     je    access_type_space    ;no - return error.
  422.  
  423.     mov    [bx].in_use,1        ;remember that we're using it.
  424.  
  425.     mov    ax,_DI[bp]        ;remember the receiver type.
  426.     mov    [bx].receiver.offs,ax
  427.     mov    ax,_ES[bp]
  428.     mov    [bx].receiver.segm,ax
  429.  
  430.     push    ds
  431.     mov    ax,ds
  432.     mov    es,ax
  433.     mov    ds,_DS[bp]        ;remember their type.
  434.     mov    si,_SI[bp]
  435.     mov    cx,_CX[bp]
  436.     mov    es:[bx].packet_type_len,cx    ; remember the TYPE length
  437.     lea    di,[bx].packet_type
  438.     rep    movsb
  439.     pop    ds
  440.  
  441.     mov    _AX[bp],bx        ;return the handle to them.
  442.  
  443.     clc
  444.     ret
  445.  
  446.  
  447. f_release_type:
  448.     call    verify_handle        ;mark this handle as being unused.
  449.     mov    [bx].in_use,0
  450.     clc
  451.     ret
  452.  
  453.  
  454. f_as_send_pkt:
  455. ;ds:si -> buffer, cx = length, es:di -> upcall.
  456.     test    driver_function,4    ;is this a high-performance driver?
  457.     jne    f_send_pkt_1        ;yes.
  458.     mov    dh,BAD_COMMAND        ;no - return an error.
  459.     stc
  460.     ret
  461.  
  462. f_send_pkt:
  463. ;ds:si -> buffer, cx = length
  464.     xor    di,di
  465.     mov    es,di
  466. f_send_pkt_1:
  467. ;ds:si -> buffer, cx = length, es:di -> upcall (only used if high-pref driver).
  468.     linc    packets_out
  469.     add    bytes_out.offs,cx    ;add up the received bytes.
  470.     adc    bytes_out.segm,0
  471.  
  472.     push    ds        ; set up proper ds for the buffer
  473.     mov    ds,_DS[bp]    ; address of buffer from caller's ds.
  474. ;following two instructions not needed because si and cx haven't been changed.
  475. ;    mov    si,_SI[bp]
  476. ;    mov    cx,_CX[bp]    ; count of bytes in the packet.
  477.  
  478.     call    send_pkt
  479.     pop    ds
  480.     ret
  481.  
  482.  
  483. f_terminate:
  484.     call    verify_handle        ; must have a handle
  485.  
  486. f_terminate_1:
  487.     mov    [bx].in_use,0        ; mark handle as free
  488.     mov    bx,offset handles    ; check that all handles are free
  489. f_terminate_2:
  490.     cmp    [bx].in_use,0        ; is this handle free?
  491.     jne    f_terminate_4        ; ne = no, so can't exit completely
  492.     add    bx,(size per_handle)    ; next handle
  493.     cmp    bx,offset end_handles    ; examined all handles?
  494.     jb    f_terminate_2        ; b = no, continue examination
  495.  
  496.     call    terminate        ;terminate the hardware.
  497. ;
  498. ; Now disable interrupts
  499. ;
  500.     mov    al,int_no
  501.     call    maskint
  502.  
  503. ;
  504. ; Now return the interrupt to their handler.
  505. ;
  506.     mov    ah,25h            ;get the old interrupt into es:bx
  507.     mov    al,int_no
  508.     add    al,8
  509.     cmp    al,8+8            ;is it a slave 8259 interrupt?
  510.     jb    f_terminate_3        ;no.
  511.     add    al,70h - (8+8)        ;map it to the real interrupt.
  512. f_terminate_3:
  513.     push    ds
  514.     lds    dx,their_recv_isr
  515.     int    21h
  516.     pop    ds
  517.  
  518.     mov    al,packet_int_no    ;release our_isr.
  519.     mov    ah,25h
  520.     push    ds
  521.     lds    dx,their_isr
  522.     int    21h
  523.     pop    ds
  524.  
  525. ;
  526. ; Now free our memory
  527. ;
  528.     push    cs
  529.     pop    es
  530.     mov    ah,49h
  531.     int    21h
  532. f_terminate_4:
  533.     clc
  534.     ret
  535.  
  536.  
  537.  
  538. f_get_address:
  539.     call    verify_handle
  540. ;    mov    es,_ES[bp]        ; get new one
  541. ;    mov    di,_DI[bp]        ; get pointer, es:di is ready
  542.     mov    cx,_CX[bp]        ;Tell them how much room they have.
  543.     cmp    have_my_address,0    ;has our address been set?
  544.     jne    get_address_set        ;yes - go report it.
  545.     call    get_address        ;no, can we get the address?
  546.     jc    get_address_space    ;no - we must not have enough space.
  547.     mov    _CX[bp],cx        ;Tell them how long our address is.
  548.     clc
  549.     ret
  550. get_address_set:
  551.     cmp    cx,my_address_len    ;is there enough room?
  552.     jb    get_address_space    ;no.
  553.     mov    cx,my_address_len    ;yes - get our address length.
  554.     mov    _CX[bp],cx        ;Tell them how long our address is.
  555.     mov    si,offset my_address    ;copy it into their area.
  556.     rep    movsb
  557.     clc
  558.     ret
  559.  
  560. get_address_space:
  561.     mov    dh,NO_SPACE
  562.     stc
  563.     ret
  564.  
  565.  
  566. f_set_address:
  567.     mov    bx,offset handles
  568.     mov    cl,0            ;number of handles in use.
  569. f_set_address_1:
  570.     add    cl,[bx].in_use        ;is this handle in use?
  571.     add    bx,(size per_handle)    ;go to the next handle.
  572.     cmp    bx,offset end_handles
  573.     jb    f_set_address_1
  574.  
  575.     cmp    cl,1            ;more than one handle in use?
  576.     ja    f_set_address_inuse    ;yes - we can't set the address
  577.  
  578.     mov    ds,_ES[bp]        ; set new one
  579.     assume    ds:nothing
  580.     mov    si,_DI[bp]        ; set pointer, ds:si is ready
  581. ;    mov    cx,_CX[bp]        ;Tell them how much address is being set.
  582.     call    set_address
  583. ;set_address restores ds.
  584.     jc    f_set_address_exit    ;Did it work?
  585.     mov    _CX[bp],cx        ;yes - return our address length.
  586.  
  587.     cmp    cx,MAX_ADDR_LEN        ;is it too long for us to remember?
  588.     ja    f_set_address_too_long    ;yes, return a too-long error.
  589.  
  590.     mov    ds,_ES[bp]        ; set new one
  591.     mov    si,_DI[bp]        ; set pointer, ds:si is ready
  592.     mov    ax,cs
  593.     mov    es,ax
  594.     mov    my_address_len,cx    ;remember how long our address is.
  595.     mov    di,offset my_address
  596.     rep    movsb
  597.     mov    have_my_address,1
  598.     mov    ds,ax            ;restoer ds.
  599.     assume    ds:code
  600.     clc
  601.     ret
  602. f_set_address_inuse:
  603.     mov    dh,CANT_SET
  604.     stc
  605.     ret
  606. f_set_address_too_long:
  607.     mov    dh,NO_SPACE
  608.     stc
  609. f_set_address_exit:
  610.     ret
  611.  
  612.  
  613. f_reset_interface:
  614.     call    verify_handle
  615.     call    reset_interface
  616.     clc
  617.     ret
  618.  
  619.  
  620. f_get_parameters:
  621. ;strictly speaking, this function only works for high-performance drivers.
  622.     test    driver_function,4    ;is this a high-performance driver?
  623.     jne    f_get_parameters_1    ;yes.
  624.     mov    dh,BAD_COMMAND        ;no - return an error.
  625.     stc
  626.     ret
  627. f_get_parameters_1:
  628.     mov    _ES[bp],cs
  629.     mov    _DI[bp],offset parameter_list
  630.     clc
  631.     ret
  632.  
  633.  
  634. verify_handle:
  635. ;Ensure that their handle is real.  If it isn't, we pop off our return
  636. ;address, and return to *their* return address with cy set.
  637.     mov    bx,_BX[bp]        ;get the handle they gave us
  638.     cmp    bx,offset handles
  639.     jb    verify_handle_bad    ;no - must be bad.
  640.     cmp    bx,offset end_handles
  641.     jae    verify_handle_bad    ;no - must be bad.
  642.     cmp    [bx].in_use,0        ;if it's not in use, it's bad.
  643.     je    verify_handle_bad
  644.     ret
  645. verify_handle_bad:
  646.     mov    dh,BAD_HANDLE
  647.     add    sp,2            ;pop off our return address.
  648.     stc
  649.     ret
  650.  
  651.  
  652.     public    set_recv_isr
  653. set_recv_isr:
  654.     mov    ah,35h            ;get the old interrupt into es:bx
  655.     mov    al,int_no        ; board's interrupt vector
  656.     add    al,8
  657.     cmp    al,8+8            ;is it a slave 8259 interrupt?
  658.     jb    set_recv_isr_1        ;no.
  659.     add    al,70h - 8 - 8        ;map it to the real interrupt.
  660. set_recv_isr_1:
  661.     int    21h
  662.     mov    their_recv_isr.offs,bx    ;remember the old seg:off.
  663.     mov    their_recv_isr.segm,es
  664.  
  665.     mov    ah,25h            ;now set our recv interrupt.
  666.     mov    dx,offset recv_isr
  667.     int    21h
  668.  
  669.     mov    al,int_no        ; Now enable interrupts
  670.     call    unmaskint
  671.  
  672.     ret
  673.  
  674.     public    count_in_err
  675. count_in_err:
  676.     assume    ds:nothing
  677.     linc    errors_in
  678.     ret
  679.  
  680.     public    count_out_err
  681. count_out_err:
  682.     assume    ds:nothing
  683.     linc    errors_out
  684.     ret
  685.  
  686. their_recv_isr    dd    0        ; original owner of board int
  687.  
  688. recv_isr:
  689.     push    ax
  690.     push    ds
  691.     mov    ax,cs            ;ds = cs.
  692.     mov    ds,ax
  693.     assume    ds:code
  694.  
  695.     mov    savesp,sp
  696.     mov    savess,ss
  697.  
  698.     mov    ss,ax
  699.     mov    sp,offset our_stack
  700.     cld
  701.     sti
  702.  
  703.     push    bx
  704.     push    cx
  705.     push    dx
  706.     push    si
  707.     push    di
  708.     push    bp
  709.     push    es
  710.  
  711.     call    recv
  712.  
  713.     cli                ;interrupts *must* be off between
  714.                     ;here and the stack restore, because
  715.                     ;if we have one of our interrupts
  716.                     ;pending, we would trash our stack.
  717. ;
  718. ; The following code is ruthlessly stolen from Phil Karn's NET package.
  719. ;
  720.     test    sys_features,40h ; 2nd 8259 installed?
  721.     jz    recv_isr_3    ; Only one 8259, so skip this stuff
  722.     mov    al,0bh        ; read in-service register from
  723.     out    0a0h,al        ; secondary 8259
  724.     nop            ; settling delay
  725.     nop
  726.     nop
  727.     in    al,0a0h        ; get it
  728.     or    al,al        ; Any bits set?
  729.     jz    recv_isr_3    ; nope, not a secondary interrupt
  730.     mov    al,20h        ; Get EOI instruction
  731.     out    0a0h,al        ; Secondary 8259 (PC/AT only)
  732. recv_isr_3:
  733.     mov    al,20h            ;acknowledge the interrupt.
  734.     out    20h,al
  735.  
  736.     pop    es
  737.     pop    bp
  738.     pop    di
  739.     pop    si
  740.     pop    dx
  741.     pop    cx
  742.     pop    bx
  743.  
  744.     mov    ss,savess
  745.     mov    sp,savesp
  746.  
  747.     call    recv_exiting        ;this routine can enable interrupts.
  748.  
  749.     pop    ds
  750.     pop    ax
  751.     iret
  752.  
  753.  
  754.     public    maskint
  755. maskint:
  756.     or    al,al            ;are they using a hardware interrupt?
  757.     je    maskint_1        ;no, don't mask off the timer!
  758.  
  759.     assume    ds:code
  760.     mov    dx,21h            ;assume the master 8259.
  761.     cmp    al,8            ;using the slave 8259 on an AT?
  762.     jb    mask_not_irq2
  763.     mov    dx,0a1h            ;go disable it on slave 8259
  764.     sub    al,8
  765. mask_not_irq2:
  766.     mov    cl,al
  767.  
  768.     in    al,dx            ;disable them on the correct 8259.
  769.     mov    ah,1            ;set the bit.
  770.     shl    ah,cl
  771.     or    al,ah
  772.     out    dx,al
  773. maskint_1:
  774.     ret
  775.  
  776.  
  777. unmaskint:
  778.     assume    ds:code
  779.     mov    dx,21h            ;assume the master 8259.
  780.     cmp    al,8            ;using the slave 8259 on an AT?
  781.     jb    unmask_not_irq2
  782.     mov    dx,0a1h            ;go enable it on slave 8259
  783.     sub    al,8
  784. unmask_not_irq2:
  785.     mov    cl,al
  786.  
  787.     in    al,dx            ;enable interrupts on the correct 8259.
  788.     mov    ah,1            ;clear the bit.
  789.     shl    ah,cl
  790.     not    ah
  791.     and    al,ah
  792.     out    dx,al
  793.  
  794.     ret
  795.  
  796.  
  797.     public    recv_find
  798. recv_find:
  799. ;called when we want to determine what to do with a received packet.
  800. ;enter with cx = packet length, es:di -> packet type.
  801. ;exit with es:di = 0 if the packet is not desired, or es:di -> packet buffer
  802. ;  to be filled by the driver.
  803.     assume    ds:code, es:nothing
  804.     push    cx
  805.  
  806.     mov    bx,offset handles
  807. recv_find_1:
  808.     cmp    [bx].in_use,0        ;is this handle in use?
  809.     je    recv_find_2        ;no - don't check the type.
  810.     mov    ax,[bx].receiver.offs    ;do they have a receiver?
  811.     or    ax,[bx].receiver.segm
  812.     je    recv_find_2        ;no - they're not serious about it.
  813.     mov    cx,[bx].packet_type_len    ;compare the packets.
  814.     lea    si,[bx].packet_type
  815.     jcxz    recv_find_3        ;if cx is zero, they want them all.
  816.     push    di
  817.     repe    cmpsb
  818.     pop    di
  819.     je    recv_find_3        ;we've got it!
  820. recv_find_2:
  821.     add    bx,(size per_handle)    ;go to the next handle.
  822.     cmp    bx,offset end_handles
  823.     jb    recv_find_1
  824.  
  825.     linc    packets_dropped
  826.  
  827.     pop    cx            ;we didn't find it -- discard it.
  828.     xor    di,di            ;"return" a null pointer.
  829.     mov    es,di
  830.     ret
  831. recv_find_3:
  832.     pop    cx            ; the packet_length
  833.  
  834.     linc    packets_in
  835.     add    bytes_in.offs,cx    ;add up the received bytes.
  836.     adc    bytes_in.segm,0
  837.  
  838.     mov    ax,[bx].receiver.offs
  839.     mov    receive_ptr.offs,ax
  840.     mov    ax,[bx].receiver.segm
  841.     mov    receive_ptr.segm,ax
  842.  
  843.     mov    found_handle,bx        ;remember what our handle was.
  844.     mov    ax,0            ;allocate request.
  845.     stc                ;with stc, flags must be an odd number
  846.     push    ax            ; save a number that cant be flags
  847.     pushf                ;save flags incase iret used.
  848.     call    receive_ptr        ;ask the client for a buffer.
  849.     ; on return, flags should be at top of stack. if an IRET has nbeen used,
  850.     ; then 0 will be at the top of the stack
  851.     pop    bx
  852.     cmp    bx,0
  853.     je    recv_find_4        ;0 is at top of stack
  854.     add    sp,2
  855. recv_find_4:
  856.     ret
  857.  
  858.  
  859.     public    recv_copy
  860. recv_copy:
  861. ;called after we have copied the packet into the buffer.
  862. ;enter with ds:si ->the packet, cx = length of the packet.
  863. ;preserve bx.
  864.     assume    ds:nothing, es:nothing
  865.     push    bx
  866.     mov    bx,found_handle
  867.     mov    ax,1            ;store request.
  868.     clc                ;with clc, flags must be an even number
  869.     push    ax            ; save a number that cant be flags
  870.     pushf                ;save flags incase iret used.
  871.     call    receive_ptr        ;ask the client for a buffer.
  872.     pop    bx
  873.     cmp    bx,1            ;if this is a 1, IRET was used.
  874.     je    recv_copy_1
  875.     pop    bx
  876. recv_copy_1:
  877.     pop    bx
  878.     ret
  879.  
  880. code    ends
  881.  
  882.     end    start
  883.