home *** CD-ROM | disk | FTP | other *** search
/ Netware Super Library / Netware Super Library.iso / drivers / nics / pktdrv7 / head.asm < prev    next >
Encoding:
Assembly Source File  |  1990-08-29  |  29.6 KB  |  1,230 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 word 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.     even                ;put the stack on a word boundary.
  34.  
  35. ;we use our dioa for a stack space.  Very hard usage has shown that only
  36. ;  27 bytes were being used, so 128 should be sufficient.
  37. our_stack    label    byte
  38.  
  39.  
  40.     extrn    int_no: byte
  41.     public    packet_int_no, is_at, sys_features, flagbyte
  42. packet_int_no    db    ?,?,?,?        ; interrupt to communicate.
  43. is_at        db    0        ; =1 if we're on an AT.
  44. sys_features    db    0        ; 2h = MC   40h = 2nd 8259
  45. flagbyte    db    0
  46.     even
  47.  
  48. functions    label    word
  49.     dw    f_not_implemented    ;0
  50.     dw    f_driver_info        ;1
  51.     dw    f_access_type        ;2
  52.     dw    f_release_type        ;3
  53.     dw    f_send_pkt        ;4
  54.     dw    f_terminate        ;5
  55.     dw    f_get_address        ;6
  56.     dw    f_reset_interface    ;7
  57.     dw    f_stop            ;8
  58.     dw    f_not_implemented    ;9
  59.     dw    f_get_parameters    ;10
  60.     dw    f_not_implemented    ;11
  61.     dw    f_as_send_pkt        ;12
  62.     dw    f_drop_pkt        ;13
  63.     dw    f_not_implemented    ;14
  64.     dw    f_not_implemented    ;15
  65.     dw    f_not_implemented    ;16
  66.     dw    f_not_implemented    ;17
  67.     dw    f_not_implemented    ;18
  68.     dw    f_not_implemented    ;19
  69.     dw    f_set_rcv_mode        ;20
  70.     dw    f_get_rcv_mode        ;21
  71.     dw    f_set_multicast_list    ;22
  72.     dw    f_get_multicast_list    ;23
  73.     dw    f_get_statistics    ;24
  74.     dw    f_set_address        ;25
  75.  
  76.     extrn    driver_class: byte
  77.     extrn    driver_type: byte
  78.     extrn    driver_name: byte
  79.     extrn    driver_function: byte
  80.     extrn    parameter_list: byte
  81.  
  82.     extrn    send_pkt: near
  83.     extrn    as_send_pkt: near
  84.     extrn    drop_pkt: near
  85.     extrn    get_address: near
  86.     extrn    set_address: near
  87.     extrn    terminate: near
  88.     extrn    reset_interface: near
  89.     extrn    xmit: near
  90.     extrn    recv: near
  91.     extrn    recv_exiting: near
  92.     extrn    etopen: near
  93.  
  94.     extrn    rcv_modes: word        ;count of modes followed by mode handles.
  95.  
  96.     extrn    set_multicast_list: near
  97.  
  98. linc    macro    n            ; inc a 32 bit integer
  99.     local    a
  100.     inc    n            ;increment the low word
  101.     jne    a            ;go if not overflow
  102.     inc    n+2            ;increment the high word
  103. a:
  104.     endm
  105.  
  106. per_handle    struc
  107. in_use        db    0        ;non-zero if this handle is in use.
  108. packet_type    db    MAX_P_LEN dup(0);associated packet type.
  109. packet_type_len    dw    0        ;associated packet type length.
  110. receiver    dd    0        ;receiver handler.
  111. receiver_sig    db    8 dup(?)    ;signature at the receiver handler.
  112. per_handle    ends
  113.  
  114. handles        per_handle max_handle dup(<>)
  115. end_handles    label    byte
  116.  
  117.     public    multicast_count, multicast_addrs, multicast_broad
  118. multicast_count    dw    0        ;count of stored multicast addresses.
  119. multicast_broad    db    0ffh,0ffh,0ffh,0ffh,0ffh,0ffh    ; entry for broadcast
  120. multicast_addrs    db    MAX_MULTICAST*EADDR_LEN dup(?)
  121.  
  122. have_my_address    db    0        ;nonzero if our address has been set.
  123. my_address    db    MAX_ADDR_LEN dup(?)
  124. my_address_len    dw    ?
  125.  
  126. rcv_mode_num    dw    3
  127.  
  128. free_handle    dw    0        ; temp, a handle not in use
  129. found_handle    dw    0        ; temp, handle for our packet
  130. receive_ptr    dd    0        ; the pkt receive service routine
  131.  
  132.     public    send_head, send_tail
  133. send_head    dd    0        ; head of transmit queue
  134. send_tail    dd    0        ; tail of transmit queue
  135.  
  136. statistics_list    label    dword
  137. packets_in    dw    ?,?
  138. packets_out    dw    ?,?
  139. bytes_in    dw    ?,?
  140. bytes_out    dw    ?,?
  141. errors_in    dw    ?,?
  142. errors_out    dw    ?,?
  143. packets_dropped    dw    ?,?        ;dropped due to no type handler.
  144.  
  145. savess        dw    ?        ;saved during the stack swap.
  146. savesp        dw    ?
  147.  
  148. regs    struc                ; stack offsets of incoming regs
  149. _ES    dw    ?
  150. _DS    dw    ?
  151. _BP    dw    ?
  152. _DI    dw    ?
  153. _SI    dw    ?
  154. _DX    dw    ?
  155. _CX    dw    ?
  156. _BX    dw    ?
  157. _AX    dw    ?
  158. _IP    dw    ?
  159. _CS    dw    ?
  160. _F    dw    ?            ; flags, Carry flag is bit 0
  161. regs    ends
  162.  
  163. CY    equ    0001h
  164. EI    equ    0200h
  165.  
  166.  
  167. bytes    struc                ; stack offsets of incoming regs
  168.     dw    ?            ; es, ds, bp, di, si are 16 bits
  169.     dw    ?
  170.     dw    ?
  171.     dw    ?
  172.     dw    ?
  173. _DL    db    ?
  174. _DH    db    ?
  175. _CL    db    ?
  176. _CH    db    ?
  177. _BL    db    ?
  178. _BH    db    ?
  179. _AL    db    ?
  180. _AH    db    ?
  181. bytes    ends
  182.  
  183.     public    our_isr, their_isr
  184. their_isr    dd    0        ; original owner of pkt driver int
  185.  
  186. our_isr:
  187.     jmp    our_isr_0        ;the required signature.
  188.     db    'PKT DRVR',0
  189. our_isr_0:
  190.     assume    ds:nothing
  191.     push    ax
  192.     push    bx
  193.     push    cx
  194.     push    dx
  195.     push    si
  196.     push    di
  197.     push    bp
  198.     push    ds
  199.     push    es
  200.     cld
  201.     mov    bx,cs            ;set up ds.
  202.     mov    ds,bx
  203.     assume    ds:code
  204.     mov    bp,sp            ;we use bp to access the original regs.
  205.     and    _F[bp],not CY        ;start by clearing the carry flag.
  206.  
  207.     test    flagbyte,CALLED_ETOPEN    ; have we initialized the card?
  208.     jnz    our_isr_cont        ; yes
  209.     push    ax            ; save lots of registers
  210.     push    bx
  211.     push    cx
  212.     push    dx
  213.     push    si
  214.     push    di
  215.     push    bp
  216.     push    ds
  217.     push    es
  218.  
  219.     call    etopen            ; init the card
  220.  
  221.     pop    es            ; restore lots of registers
  222.     pop    ds
  223.     pop    bp
  224.     pop    di
  225.     pop    si
  226.     pop    dx
  227.     pop    cx
  228.     pop    bx
  229.     pop    ax
  230.     mov    dh,CANT_RESET        ; (actually can't initialize)
  231.     jc    our_isr_error
  232.     or    flagbyte,CALLED_ETOPEN    ; remember this fact
  233.  our_isr_cont:
  234.  
  235.     mov    bl,ah            ;jump to the correct function.
  236.     mov    bh,0
  237.     cmp    bx,25            ;only twenty five functions right now.
  238.     mov    dh,BAD_COMMAND        ;in case we find a bad number.
  239.     ja    our_isr_error
  240.     add    bx,bx            ;*2
  241.     call    functions[bx]
  242.     jnc    our_isr_return
  243. our_isr_error:
  244.     mov    _DH[bp],dh
  245.     or    _F[bp],CY        ;return their carry flag.
  246. our_isr_return:
  247.     pop    es
  248.     pop    ds
  249.     pop    bp
  250.     pop    di
  251.     pop    si
  252.     pop    dx
  253.     pop    cx
  254.     pop    bx
  255.     pop    ax
  256.     iret
  257.  
  258.     public    re_enable_interrupts
  259. re_enable_interrupts:
  260. ; Possibly re-enable interrupts.  We put this here so that other routines
  261. ; don't need to know how we put things on the stack.
  262.     test    _F[bp], EI        ; Were interrupts enabled on pkt driver entry?
  263.     je    re_enable_interrupts_1    ; No.
  264.     sti                ; Yes, re-enable interrupts now.
  265. re_enable_interrupts_1:
  266.     ret
  267.  
  268.  
  269. f_not_implemented:
  270.     mov    dh,BAD_COMMAND
  271.     stc
  272.     ret
  273.  
  274.  
  275. f_driver_info:
  276. ;    As of 1.08, the handle is optional, so we no longer verify it.
  277. ;    call    verify_handle
  278.     cmp    _AL[bp],0ffh        ; correct calling convention?
  279.     jne    f_driver_info_1        ; ne = incorrect, fail
  280.     mov    _BX[bp],majver        ;version
  281.     mov    al,driver_class
  282.     mov    _CH[bp],al
  283.     mov    al,driver_type
  284.     cbw
  285.     mov    _DX[bp],ax
  286.     mov    _CL[bp],0        ;number zero.
  287.     mov    _DS[bp],ds        ; point to our name in their ds:si
  288.     mov    _SI[bp],offset driver_name
  289.     mov    al,driver_function
  290.     mov    _AL[bp],al
  291.     clc
  292.     ret
  293. f_driver_info_1:
  294.     stc
  295.     ret
  296.  
  297.  
  298. f_set_rcv_mode:
  299.     call    verify_handle
  300.     mov    cx,_CX[bp]        ;Tell them how much room they have.
  301.     cmp    cx,rcv_modes        ;do they have this many modes?
  302.     jae    f_set_rcv_mode_1    ;no - must be a bad mode for us.
  303.     mov    bx,cx
  304.     add    bx,bx            ;we're accessing words, not bytes.
  305.     mov    ax,rcv_modes[bx]+2    ;get the handler for this mode.
  306.     or    ax,ax            ;do they have one?
  307.     je    f_set_rcv_mode_1    ;no - must be a bad mode for us.
  308.     mov    rcv_mode_num,cx        ;yes - remember the number and
  309.     call    ax            ;  call it.
  310.     clc
  311.     ret
  312. f_set_rcv_mode_1:
  313.     mov    dh,BAD_MODE
  314.     stc
  315.     ret
  316.  
  317.  
  318. f_get_rcv_mode:
  319.     call    verify_handle
  320.     mov    ax,rcv_mode_num        ;return the current receive mode.
  321.     mov    _AX[bp],ax
  322.     clc
  323.     ret
  324.  
  325.  
  326. f_set_multicast_list:
  327. ;    mov    cx,_CX[bp]        ;Tell them how much room they have.
  328.  
  329. ;verify that they supplied an even number of EADDR's.
  330.     mov    ax,cx
  331.     xor    dx,dx
  332.     mov    bx,EADDR_LEN
  333.     div    bx
  334.     or    dx,dx            ;zero remainder?
  335.     jne    f_set_multicast_list_2    ;no, we don't have an even number of
  336.                     ;  addresses.
  337.  
  338.     cmp    ax,MAX_MULTICAST    ;is this too many?
  339.     ja    f_set_multicast_list_3    ;yes - return NO_SPACE
  340. f_set_multicast_list_1:
  341.     mov    multicast_count,ax    ;remember the number of addresses.
  342.     push    cs
  343.     pop    es
  344.     mov    di,offset multicast_addrs
  345.     push    ds
  346.     mov    ds,_ES[bp]        ; get ds:si -> new list.
  347.     mov    si,_DI[bp]
  348.     push    cx
  349.     rep    movsb
  350.     pop    cx
  351.     pop    ds
  352.  
  353.     mov    si,offset multicast_addrs
  354.     call    set_multicast_list
  355.     ret
  356. f_set_multicast_list_2:
  357.     mov    dh,BAD_ADDRESS
  358.     stc
  359.     ret
  360. f_set_multicast_list_3:
  361.     mov    dh,NO_SPACE
  362.     stc
  363.     ret
  364.  
  365.  
  366. f_get_multicast_list:
  367.     mov    _ES[bp],ds        ;return what we have remembered.
  368.     mov    _DI[bp],offset multicast_addrs
  369.     mov    ax,EADDR_LEN        ;multiply the count by the length.
  370.     mul    multicast_count
  371.     mov    _CX[bp],ax        ;because they want total bytes.
  372.     clc
  373.     ret
  374.  
  375.  
  376. f_get_statistics:
  377.     call    verify_handle        ;just in case.
  378.     mov    _DS[bp],ds
  379.     mov    _SI[bp],offset statistics_list
  380.     clc
  381.     ret
  382.  
  383.  
  384. access_type_class:
  385.     mov    dh,NO_CLASS
  386.     stc
  387.     ret
  388.  
  389. access_type_type:
  390.     mov    dh,NO_TYPE
  391.     stc
  392.     ret
  393.  
  394. access_type_number:
  395.     mov    dh,NO_NUMBER
  396.     stc
  397.     ret
  398.  
  399. access_type_bad:
  400.     mov    dh,BAD_TYPE
  401.     stc
  402.     ret
  403.  
  404. access_type_space:
  405.     mov    dh,NO_SPACE
  406.     stc
  407.     ret
  408.  
  409. ;register caller of pkt TYPE
  410. f_access_type:
  411.     mov    al,driver_class
  412.     cmp    _AL[bp],al        ;our class?
  413.     jne    access_type_class    ;no.
  414.     cmp    _BX[bp],-1        ;generic type?
  415.     je    access_type_2        ;yes.
  416.     mov    al,driver_type
  417.     cbw
  418.     cmp    _BX[bp],ax        ;our type?
  419.     jne    access_type_type    ;no.
  420. access_type_2:
  421.     cmp    _DL[bp],0        ;generic number?
  422.     je    access_type_3
  423.     cmp    _DL[bp],1        ;our number?
  424.     jne    access_type_number
  425. access_type_3:
  426.     cmp    _CX[bp],MAX_P_LEN    ;is the type length too long?
  427.     ja    access_type_bad        ;yes - can't be ours.
  428.  
  429. ; now we do two things--look for an open handle, and check the existing
  430. ; handles to see if they're replicating a packet type.
  431.  
  432.     mov    free_handle,0        ;remember no free handle yet.
  433.     mov    bx,offset handles
  434. access_type_4:
  435.     cmp    [bx].in_use,0        ;is this handle in use?
  436.     je    access_type_5        ;no - don't check the type.
  437.     mov    es,_DS[bp]        ;get a pointer to their type
  438.     mov    di,_SI[bp]        ;  from their ds:si to our es:di
  439.     mov    cx,_CX[bp]        ;get the minimum of their length
  440.                     ;  and our length.  As currently
  441.                     ;  implemented, only one receiver
  442.                     ;  gets the packets, so we have to
  443.                     ;  ensure that the shortest prefix
  444.                     ;  is unique.
  445.     cmp    cx,[bx].packet_type_len    ;Are we less specific than they are?
  446.     jb    access_type_8        ;no.
  447.     mov    cx,[bx].packet_type_len    ;yes - use their count.
  448. access_type_8:
  449.     lea    si,[bx].packet_type
  450.     or    cx,cx            ; pass-all TYPE? (zero TYPE length)
  451.     jne    access_type_7        ; ne = no
  452.     mov    bx,offset handles+(max_handle -1)*(size per_handle)
  453.     jmp    short access_type_5    ; put pass-all last
  454. access_type_7:
  455.     repe    cmpsb
  456.     jne    short access_type_6    ;go look at the next one.
  457. access_type_inuse:
  458.     mov    dh,TYPE_INUSE        ;a handle has been assigned for TYPE
  459.     stc                ;and we can't assign another
  460.     ret
  461. access_type_5:                ;handle is not in use
  462.     cmp    free_handle,0        ;found a free handle yet?
  463.     jne    access_type_6        ;yes.
  464.     mov    free_handle,bx        ;remember a free handle
  465. access_type_6:
  466.     add    bx,(size per_handle)    ;go to the next handle.
  467.     cmp    bx,offset end_handles    ;examined all handles?
  468.     jb    access_type_4        ;no, continue.
  469.  
  470.     mov    bx,free_handle        ;did we find a free handle?
  471.     or    bx,bx
  472.     je    access_type_space    ;no - return error.
  473.  
  474.     mov    [bx].in_use,1        ;remember that we're using it.
  475.  
  476.     mov    ax,_DI[bp]        ;remember the receiver type.
  477.     mov    [bx].receiver.offs,ax
  478.     mov    ax,_ES[bp]
  479.     mov    [bx].receiver.segm,ax
  480.  
  481.     push    ds
  482.     mov    ax,ds
  483.     mov    es,ax
  484.     mov    ds,_DS[bp]        ;remember their type.
  485.     mov    si,_SI[bp]
  486.     mov    cx,_CX[bp]
  487.     mov    es:[bx].packet_type_len,cx    ; remember the TYPE length
  488.     lea    di,[bx].packet_type
  489.     rep    movsb
  490.  
  491.     lds    si,es:[bx].receiver    ;copy the first 8 bytes
  492.     lea    di,[bx].receiver_sig    ; to the receiver signature.
  493.     mov    cx,8/2
  494.     rep    movsw
  495.  
  496.     pop    ds
  497.  
  498.     mov    _AX[bp],bx        ;return the handle to them.
  499.  
  500.     clc
  501.     ret
  502.  
  503.  
  504. f_release_type:
  505.     call    verify_handle        ;mark this handle as being unused.
  506.     mov    [bx].in_use,0
  507.     clc
  508.     ret
  509.  
  510.  
  511. f_send_pkt:
  512. ;ds:si -> buffer, cx = length
  513. ; XXX Should re-enable interrupts here, but some drivers are broken.
  514. ; Possibly re-enable interrupts.
  515. ;    test _F[bp], EI        ; Were interrupts enabled on pkt driver entry?
  516. ;    je    f_send_pkt_1    ; No.
  517. ;    sti            ; Yes, re-enable interrupts now.
  518. ;f_send_pkt_1:
  519.     push    ds        ; set up proper ds for the buffer
  520.     mov    ds,_DS[bp]    ; address of buffer from caller's ds.
  521.     assume    ds:nothing, es:nothing
  522. ;following two instructions not needed because si and cx haven't been changed.
  523. ;    mov    si,_SI[bp]
  524. ;    mov    cx,_CX[bp]    ; count of bytes in the packet.
  525.     linc    packets_out
  526.     add    bytes_out.offs,cx    ;add up the received bytes.
  527.     adc    bytes_out.segm,0
  528.  
  529. ; If -n option take Ethernet encapsulated Novell IPX packets (from BYU's 
  530. ; PDSHELL) and change them to be IEEE 802.3 encapsulated.
  531. EPROT_OFF    equ    EADDR_LEN*2
  532.     test    cs:flagbyte,N_OPTION
  533.     jz    f_send_pkt_2
  534.     cmp    ds:[si].EPROT_OFF,3781h ; if not Novell (prot 8137)
  535.     jne    f_send_pkt_2        ;  don't tread on it
  536.     push    ax            ; get scratch reg
  537.     mov    ax,[si].EPROT_OFF+4    ; get len
  538.     xchg    ah,al
  539.     inc    ax            ; make even (rounding up)
  540.     and    al,0feh
  541.     xchg    ah,al
  542.     mov    ds:[si].EPROT_OFF,ax    ; save in prot field
  543.     pop    ax            ; restore old contents
  544. f_send_pkt_2:
  545.     call    send_pkt
  546.     pop    ds
  547.     assume    ds:code
  548.     ret
  549.  
  550.  
  551. f_as_send_pkt:
  552. ;es:di -> iocb.
  553.     test    driver_function,4    ; is this a high-performance driver?
  554.     je    f_as_send_pkt_2        ; no.
  555. ; Possibly re-enable interrupts.
  556.     test _F[bp], EI            ; Were interrupts enabled on pkt driver entry?
  557.     je    f_as_send_pkt_1        ; No.
  558.     sti                ; Yes, re-enable interrupts now.
  559. f_as_send_pkt_1:
  560.     push    ds            ; set up proper ds for the buffer
  561.     lds    si,es:[di].buffer    ; ds:si -> buffer
  562.     assume    ds:nothing
  563.     mov    cx,es:[di].len        ; cx = length
  564.     linc    packets_out
  565.     add    bytes_out.offs,cx    ; add up the received bytes.
  566.     adc    bytes_out.segm,0
  567.  
  568. ;ds:si -> buffer, cx = length, es:di -> iocb.
  569.     call    as_send_pkt
  570.     pop    ds
  571.     assume    ds:code
  572.     ret
  573. f_as_send_pkt_2:
  574.     mov dh,    BAD_COMMAND        ; return an error.
  575.     stc
  576.     ret
  577.  
  578.  
  579. f_drop_pkt:
  580. ; es:di -> iocb.
  581.     test    driver_function,4    ; is this a high-performance driver?
  582.     je    f_as_send_pkt_1        ; no.
  583.     push    ds            ; Preserve ds
  584.     mov    si,offset send_head    ; Get head offset
  585. dp_loop:
  586.     mov    ax,ds:[si]        ; Get offset
  587.     mov    dx,ds:[si+2]        ; Get segment
  588.     mov    bx,ax
  589.     or    bx,dx            ; End of list?
  590.     je    dp_endlist        ; Yes
  591.     cmp    ax,di            ; Offsets equal?
  592.     jne    dp_getnext        ; No
  593.     mov    bx,es
  594.     cmp    dx,bx            ; Segments equal?
  595.     jne    dp_getnext        ; No
  596.     call    drop_pkt        ; Pass to driver
  597.     les    di,es:[di].next        ; Get next segment:offset
  598.     mov    ds:[si],di        ; Set next offset
  599.     mov    ds:[si+2],es        ; Set next segment
  600.     pop    ds            ; Restore ds
  601.     clc
  602.     ret
  603. dp_getnext:
  604.     mov    ds,dx            ; Get next segment
  605.     mov    si,ax            ; Get next iocb offset
  606.     lea    si,ds:[si].next        ; Get next iocb next ptr offset
  607.     jmp    dp_loop            ; Try again
  608. dp_endlist:
  609.     pop    ds            ; Restore ds
  610.     mov    dh,BAD_IOCB        ; Return error
  611.     stc                ; Set carry
  612.     ret
  613.  
  614.  
  615. f_terminate:
  616.     call    verify_handle        ; must have a handle
  617.  
  618. f_terminate_1:
  619.     mov    [bx].in_use,0        ; mark handle as free
  620.     mov    bx,offset handles    ; check that all handles are free
  621. f_terminate_2:
  622.     cmp    [bx].in_use,0        ; is this handle free?
  623.     jne    f_terminate_4        ; ne = no, so can't exit completely
  624.     add    bx,(size per_handle)    ; next handle
  625.     cmp    bx,offset end_handles    ; examined all handles?
  626.     jb    f_terminate_2        ; b = no, continue examination
  627.  
  628.     call    terminate        ;terminate the hardware.
  629. ;
  630. ; Now disable interrupts
  631. ;
  632.     mov    al,int_no
  633.     or    al,al            ;are they using a hardware interrupt?
  634.     je    f_terminate_no_irq    ;no.
  635.     call    maskint
  636.  
  637. ;
  638. ; Now return the interrupt to their handler.
  639. ;
  640.     mov    ah,25h            ;get the old interrupt into es:bx
  641.     mov    al,int_no
  642.     add    al,8
  643.     cmp    al,8+8            ;is it a slave 8259 interrupt?
  644.     jb    f_terminate_3        ;no.
  645.     add    al,70h - (8+8)        ;map it to the real interrupt.
  646. f_terminate_3:
  647.     push    ds
  648.     lds    dx,their_recv_isr
  649.     int    21h
  650.     pop    ds
  651.  
  652. f_terminate_no_irq:
  653.     mov    al,packet_int_no    ;release our_isr.
  654.     mov    ah,25h
  655.     push    ds
  656.     lds    dx,their_isr
  657.     int    21h
  658.     pop    ds
  659.  
  660. ;
  661. ; Now free our memory
  662. ;
  663.     push    cs
  664.     pop    es
  665.     mov    ah,49h
  666.     int    21h
  667.     clc
  668.     ret
  669. f_terminate_4:
  670.     mov    dh, CANT_TERMINATE
  671.     stc
  672.     ret
  673.  
  674.  
  675.  
  676. f_get_address:
  677.     call    verify_handle
  678. ;    mov    es,_ES[bp]        ; get new one
  679. ;    mov    di,_DI[bp]        ; get pointer, es:di is ready
  680.     mov    cx,_CX[bp]        ;Tell them how much room they have.
  681.     cmp    have_my_address,0    ;has our address been set?
  682.     jne    get_address_set        ;yes - go report it.
  683.     call    get_address        ;no, can we get the address?
  684.     jc    get_address_space    ;no - we must not have enough space.
  685.     mov    _CX[bp],cx        ;Tell them how long our address is.
  686.     clc
  687.     ret
  688. get_address_set:
  689.     cmp    cx,my_address_len    ;is there enough room?
  690.     jb    get_address_space    ;no.
  691.     mov    cx,my_address_len    ;yes - get our address length.
  692.     mov    _CX[bp],cx        ;Tell them how long our address is.
  693.     mov    si,offset my_address    ;copy it into their area.
  694.     rep    movsb
  695.     clc
  696.     ret
  697.  
  698. get_address_space:
  699.     mov    dh,NO_SPACE
  700.     stc
  701.     ret
  702.  
  703.  
  704. f_set_address:
  705.     mov    bx,offset handles
  706.     mov    cl,0            ;number of handles in use.
  707. f_set_address_1:
  708.     add    cl,[bx].in_use        ;is this handle in use?
  709.     add    bx,(size per_handle)    ;go to the next handle.
  710.     cmp    bx,offset end_handles
  711.     jb    f_set_address_1
  712.  
  713.     cmp    cl,1            ;more than one handle in use?
  714.     ja    f_set_address_inuse    ;yes - we can't set the address
  715.  
  716.     mov    ds,_ES[bp]        ; set new one
  717.     assume    ds:nothing
  718.     mov    si,_DI[bp]        ; set pointer, ds:si is ready
  719. ;    mov    cx,_CX[bp]        ;Tell them how much address is being set.
  720.     call    set_address
  721. ;set_address restores ds.
  722.     jc    f_set_address_exit    ;Did it work?
  723.     mov    _CX[bp],cx        ;yes - return our address length.
  724.  
  725.     cmp    cx,MAX_ADDR_LEN        ;is it too long for us to remember?
  726.     ja    f_set_address_too_long    ;yes, return a too-long error.
  727.  
  728.     mov    ds,_ES[bp]        ; set new one
  729.     mov    si,_DI[bp]        ; set pointer, ds:si is ready
  730.     mov    ax,cs
  731.     mov    es,ax
  732.     mov    my_address_len,cx    ;remember how long our address is.
  733.     mov    di,offset my_address
  734.     rep    movsb
  735.     mov    have_my_address,1
  736.     mov    ds,ax            ;restoer ds.
  737.     assume    ds:code
  738.     clc
  739.     ret
  740. f_set_address_inuse:
  741.     mov    dh,CANT_SET
  742.     stc
  743.     ret
  744. f_set_address_too_long:
  745.     mov    dh,NO_SPACE
  746.     stc
  747. f_set_address_exit:
  748.     ret
  749.  
  750.  
  751. f_reset_interface:
  752.     call    verify_handle
  753.     call    reset_interface
  754.     clc
  755.     ret
  756.  
  757.  
  758. ; Stop the packet driver doing upcalls. Also a following terminate will
  759. ; always succed (no in use handles any longer).
  760. f_stop:
  761.     mov    bx,offset handles
  762. f_stop_2:
  763.     mov    [bx].in_use,0
  764.     add    bx,(size per_handle)    ; next handle
  765.     cmp    bx,offset end_handles
  766.     jb    f_stop_2
  767.     clc
  768.     ret
  769.  
  770.  
  771. f_get_parameters:
  772. ;strictly speaking, this function only works for high-performance drivers.
  773.     test    driver_function,4    ;is this a high-performance driver?
  774.     jne    f_get_parameters_1    ;yes.
  775.     mov    dh,BAD_COMMAND        ;no - return an error.
  776.     stc
  777.     ret
  778. f_get_parameters_1:
  779.     mov    _ES[bp],cs
  780.     mov    _DI[bp],offset parameter_list
  781.     clc
  782.     ret
  783.  
  784.  
  785. verify_handle:
  786. ;Ensure that their handle is real.  If it isn't, we pop off our return
  787. ;address, and return to *their* return address with cy set.
  788.     mov    bx,_BX[bp]        ;get the handle they gave us
  789.     cmp    bx,offset handles
  790.     jb    verify_handle_bad    ;no - must be bad.
  791.     cmp    bx,offset end_handles
  792.     jae    verify_handle_bad    ;no - must be bad.
  793.     cmp    [bx].in_use,0        ;if it's not in use, it's bad.
  794.     je    verify_handle_bad
  795.     ret
  796. verify_handle_bad:
  797.     mov    dh,BAD_HANDLE
  798.     add    sp,2            ;pop off our return address.
  799.     stc
  800.     ret
  801.  
  802.  
  803.     public    set_recv_isr
  804. set_recv_isr:
  805.     mov    ah,35h            ;get the old interrupt into es:bx
  806.     mov    al,int_no        ; board's interrupt vector
  807.     or    al,al
  808.     je    set_isr_no_irq
  809.     add    al,8
  810.     cmp    al,8+8            ;is it a slave 8259 interrupt?
  811.     jb    set_recv_isr_1        ;no.
  812.     add    al,70h - 8 - 8        ;map it to the real interrupt.
  813. set_recv_isr_1:
  814.     int    21h
  815.     mov    their_recv_isr.offs,bx    ;remember the old seg:off.
  816.     mov    their_recv_isr.segm,es
  817.  
  818.     mov    ah,25h            ;now set our recv interrupt.
  819.     mov    dx,offset recv_isr
  820.     int    21h
  821.  
  822.     mov    al,int_no        ; Now enable interrupts
  823.     call    unmaskint
  824.  
  825. set_isr_no_irq:
  826.     ret
  827.  
  828.     public    count_in_err
  829. count_in_err:
  830.     assume    ds:nothing
  831.     linc    errors_in
  832.     ret
  833.  
  834.     public    count_out_err
  835. count_out_err:
  836.     assume    ds:nothing
  837.     linc    errors_out
  838.     ret
  839.  
  840. their_recv_isr    dd    0        ; original owner of board int
  841.  
  842. recv_isr:
  843.   if 0
  844.     push    ax
  845.     push    ds
  846.     mov    ax,cs            ;ds = cs.
  847.     mov    ds,ax
  848.     assume    ds:code
  849.  
  850.     mov    savesp,sp
  851.     mov    savess,ss
  852.  
  853.     mov    ss,ax
  854.     mov    sp,offset our_stack
  855.     cld
  856.     sti
  857.  
  858.     push    bx
  859.     push    cx
  860.     push    dx
  861.     push    si
  862.     push    di
  863.     push    bp
  864.     push    es
  865.  
  866.     call    recv
  867.  
  868.     cli                ;interrupts *must* be off between
  869.                     ;here and the stack restore, because
  870.                     ;if we have one of our interrupts
  871.                     ;pending, we would trash our stack.
  872. ;
  873. ; The following code is ruthlessly stolen from Phil Karn's NET package.
  874. ;
  875.     test    sys_features,40h ; 2nd 8259 installed?
  876.     jz    recv_isr_3    ; Only one 8259, so skip this stuff
  877.     mov    al,0bh        ; read in-service register from
  878.     out    0a0h,al        ; secondary 8259
  879.     nop            ; settling delay
  880.     nop
  881.     nop
  882.     in    al,0a0h        ; get it
  883.     or    al,al        ; Any bits set?
  884.     jz    recv_isr_3    ; nope, not a secondary interrupt
  885.     mov    al,20h        ; Get EOI instruction
  886.     out    0a0h,al        ; Secondary 8259 (PC/AT only)
  887. recv_isr_3:
  888.     mov    al,20h            ;acknowledge the interrupt.
  889.     out    20h,al
  890.  
  891.     pop    es
  892.     pop    bp
  893.     pop    di
  894.     pop    si
  895.     pop    dx
  896.     pop    cx
  897.     pop    bx
  898.  
  899.     mov    ss,savess
  900.     mov    sp,savesp
  901.  
  902.     call    recv_exiting        ;this routine can enable interrupts.
  903.  
  904.     pop    ds
  905.     pop    ax
  906.   else
  907. ; In order to achieve back-to-back packet transmissions, we handle the
  908. ; latency-critical portion of transmit interrupts first.  The xmit
  909. ; interrupt routine should only start the next transmission, but do
  910. ; no other work.  It may only touch ax and dx (the only register necessary
  911. ; for doing "out" instructions) unless it first pushes any other registers
  912. ; itself.
  913.     push    ax
  914.     push    dx
  915.     call    xmit
  916.  
  917. ; Now switch stacks, push remaining registers, and do remaining interrupt work.
  918.     push    ds
  919.     mov    ax,cs            ;ds = cs.
  920.     mov    ds,ax
  921.     assume    ds:code
  922.  
  923.     mov    savesp,sp
  924.     mov    savess,ss
  925.  
  926.     mov    ss,ax
  927.     mov    sp,offset our_stack
  928.     cld
  929.  
  930.     push    bx
  931.     push    cx
  932.     push    si
  933.     push    di
  934.     push    bp
  935.     push    es
  936.  
  937. ; Chips & Technologies 8259 clone chip seems to be very broken.  If you
  938. ; send it a Non Specific EOI command, it clears all In Service Register
  939. ; bits instead of just the one with the highest priority (as the Intel
  940. ; chip does and clones should do).  This bug causes our interrupt
  941. ; routine to be reentered if: 1. we reenable processor interrupts;
  942. ; 2. we reenable device interrupts; 3. a timer or other higher priority
  943. ; device interrupt now comes in; 4. the new interrupting device uses
  944. ; a Non Specific EOI; 5. our device interrupts again.  Because of
  945. ; this bug, we now completely mask our interrupts around the call
  946. ; to "recv", the real device interrupt handler.  This allows us
  947. ; to send an EOI instruction to the 8259 early, before we actually
  948. ; reenable device interrupts.  Since the interrupt is masked, we
  949. ; are still guaranteed not to get another interrupt from our device
  950. ; until the interrupt handler returns.  This has another benefit:
  951. ; we now no longer prevent other devices from interrupting while our
  952. ; interrupt handler is running.  This is especially useful if we have
  953. ; other (multiple) packet drivers trying to do low-latency transmits.
  954.     mov    al,int_no    ; Disable further device interrupts
  955.     call    maskint
  956.  
  957. ;
  958. ; The following code is ruthlessly stolen from Phil Karn's NET package.
  959. ;
  960.     test    sys_features,TWO_8259 ; 2nd 8259 installed?
  961.     jz    recv_isr_3    ; Only one 8259, so skip this stuff
  962.     mov    al,0bh        ; read in-service register from
  963.     out    0a0h,al        ; secondary 8259
  964.     nop            ; settling delay
  965.     nop
  966.     nop
  967.     in    al,0a0h        ; get it
  968.     or    al,al        ; Any bits set?
  969.     jz    recv_isr_3    ; nope, not a secondary interrupt
  970.     mov    al,20h        ; Get EOI instruction
  971.     out    0a0h,al        ; Secondary 8259 (PC/AT only)
  972. recv_isr_3:
  973.     mov    al,20h            ;acknowledge the interrupt.
  974.     out    20h,al
  975.  
  976. ;    sti                ; Interrupts are now completely safe
  977.     call    recv
  978.  
  979.     cli                ;interrupts *must* be off between
  980.                     ;here and the stack restore, because
  981.                     ;if we have one of our interrupts
  982.                     ;pending, we would trash our stack.
  983.     mov    al,int_no    ; Now reenable device interrupts
  984.     call    unmaskint
  985.  
  986.     pop    es
  987.     pop    bp
  988.     pop    di
  989.     pop    si
  990.     pop    cx
  991.     pop    bx
  992.  
  993.     mov    ss,savess
  994.     mov    sp,savesp
  995.  
  996.     call    recv_exiting        ;this routine can enable interrupts.
  997. ; DDP - This is a BIG mistake.  This routine SHOULD NOT enable interrupts.
  998. ;    doing so can cause interrupt recursion and blow your stack.
  999. ;    Processor interrupts SHOULD NOT be enabled after enabling device
  1000. ;    interrupts until after the "iret".  You will lose atleast 12 bytes
  1001. ;    on the stack for each recursion.
  1002.  
  1003.     pop    ds
  1004.     assume    ds:nothing
  1005.     pop    dx
  1006.     pop    ax
  1007.   endif
  1008.     iret
  1009.  
  1010.  
  1011.     public    maskint
  1012. maskint:
  1013.     or    al,al            ;are they using a hardware interrupt?
  1014.     je    maskint_1        ;no, don't mask off the timer!
  1015.  
  1016.     assume    ds:code
  1017.     mov    dx,21h            ;assume the master 8259.
  1018.     cmp    al,8            ;using the slave 8259 on an AT?
  1019.     jb    mask_not_irq2
  1020.     mov    dx,0a1h            ;go disable it on slave 8259
  1021.     sub    al,8
  1022. mask_not_irq2:
  1023.     mov    cl,al
  1024.  
  1025.     in    al,dx            ;disable them on the correct 8259.
  1026.     mov    ah,1            ;set the bit.
  1027.     shl    ah,cl
  1028.     or    al,ah
  1029.     out    dx,al
  1030. maskint_1:
  1031.     ret
  1032.  
  1033.  
  1034. unmaskint:
  1035.     assume    ds:code
  1036.     mov    dx,21h            ;assume the master 8259.
  1037.     mov    cl,al
  1038.     cmp    cl,8            ;using the slave 8259 on an AT?
  1039.     jb    unmask_not_irq2        ;no
  1040.     in    al,dx            ;get master mask
  1041.     and    al,not (1 shl 2)    ; and clear slave cascade bit in mask
  1042.     out    dx,al            ;set new master mask (enable slave int)
  1043.     mov    dx,0a1h            ;go enable int on slave 8259
  1044.     sub    cl,8
  1045. unmask_not_irq2:
  1046.  
  1047.     in    al,dx            ;enable interrupts on the correct 8259.
  1048.     mov    ah,1            ;clear the bit.
  1049.     shl    ah,cl
  1050.     not    ah
  1051.     and    al,ah
  1052.     out    dx,al
  1053.  
  1054.     ret
  1055.  
  1056.  
  1057.     public    recv_find
  1058. recv_find:
  1059. ;called when we want to determine what to do with a received packet.
  1060. ;enter with cx = packet length, es:di -> packet type.
  1061. ;exit with es:di = 0 if the packet is not desired, or es:di -> packet buffer
  1062. ;  to be filled by the driver.
  1063.     assume    ds:code, es:nothing
  1064.     push    cx
  1065.  
  1066. ; If -n option take IEEE 802.3 encapsulated packets that could be Novell IPX 
  1067. ; and make them Ethernet encapsulated Novell IPX packets (for PDSHELL).
  1068.     test    flagbyte,N_OPTION
  1069.     jz    not_n_op
  1070.     push    ax            ; get scratch reg
  1071.     mov    ax,es:[di]        ; get length word
  1072.     xchg    ah,al
  1073.     cmp    ax,GIANT        ; if > GIANT
  1074.     ja    recv_find_0        ;  then it is a protocol
  1075.     cmp    es:2[di],0ffffh     ; if next word not ffff
  1076.     jne    recv_find_0        ;  then not Novell
  1077.     mov    es:[di],3781h        ; make Novell protocol (8137)
  1078. recv_find_0:
  1079.     pop    ax            ; restore old contents
  1080. not_n_op:
  1081.  
  1082.     mov    bx,offset handles
  1083. recv_find_1:
  1084.     cmp    [bx].in_use,0        ;is this handle in use?
  1085.     je    recv_find_2        ;no - don't check the type.
  1086.     mov    ax,[bx].receiver.offs    ;do they have a receiver?
  1087.     or    ax,[bx].receiver.segm
  1088.     je    recv_find_2        ;no - they're not serious about it.
  1089.     mov    cx,[bx].packet_type_len    ;compare the packets.
  1090.     lea    si,[bx].packet_type
  1091.     jcxz    recv_find_3        ;if cx is zero, they want them all.
  1092.     push    di
  1093.     repe    cmpsb
  1094.     pop    di
  1095.     je    recv_find_3        ;we've got it!
  1096. recv_find_2:
  1097.     add    bx,(size per_handle)    ;go to the next handle.
  1098.     cmp    bx,offset end_handles
  1099.     jb    recv_find_1
  1100.  
  1101.     linc    packets_dropped
  1102.  
  1103.     pop    cx            ;we didn't find it -- discard it.
  1104. recv_find_5:
  1105.     xor    di,di            ;"return" a null pointer.
  1106.     mov    es,di
  1107.     ret
  1108. recv_find_3:
  1109.     pop    cx            ; the packet_length
  1110.  
  1111.     linc    packets_in
  1112.     add    bytes_in.offs,cx    ;add up the received bytes.
  1113.     adc    bytes_in.segm,0
  1114.  
  1115.     les    di,[bx].receiver    ;remember the receiver upcall.
  1116.     mov    receive_ptr.offs,di
  1117.     mov    receive_ptr.segm,es
  1118.  
  1119.     test    flagbyte,W_OPTION    ;did they select the Windows option?
  1120.     je    recv_find_6        ;no, don't check for the upcall.
  1121.  
  1122. ; does the receiver signature match whats currently in memory?  if not,
  1123. ; jump to fake return
  1124.     push    si
  1125.     push    cx
  1126.     lea    si,[bx].receiver_sig
  1127.     mov    cx,8/2
  1128.     repe    cmpsw
  1129.     pop    cx
  1130.     pop    si
  1131.     jne    recv_find_5
  1132. recv_find_6:
  1133.  
  1134.     mov    found_handle,bx        ;remember what our handle was.
  1135.     mov    ax,0            ;allocate request.
  1136.     stc                ;with stc, flags must be an odd number
  1137.     push    ax            ; save a number that cant be flags
  1138.     pushf                ;save flags incase iret used.
  1139.     call    receive_ptr        ;ask the client for a buffer.
  1140.     ; on return, flags should be at top of stack. if an IRET has nbeen used,
  1141.     ; then 0 will be at the top of the stack
  1142.     pop    bx
  1143.     cmp    bx,0
  1144.     je    recv_find_4        ;0 is at top of stack
  1145.     add    sp,2
  1146. recv_find_4:
  1147.     ret
  1148.  
  1149.  
  1150.     public    recv_copy
  1151. recv_copy:
  1152. ;called after we have copied the packet into the buffer.
  1153. ;enter with ds:si ->the packet, cx = length of the packet.
  1154. ;preserve bx.
  1155.     assume    ds:nothing, es:nothing
  1156.     push    bx
  1157.     mov    bx,found_handle
  1158.     mov    ax,1            ;store request.
  1159.     clc                ;with clc, flags must be an even number
  1160.     push    ax            ; save a number that cant be flags
  1161.     pushf                ;save flags incase iret used.
  1162.     call    receive_ptr        ;ask the client for a buffer.
  1163.     pop    bx
  1164.     cmp    bx,1            ;if this is a 1, IRET was used.
  1165.     je    recv_copy_1
  1166.     pop    bx
  1167. recv_copy_1:
  1168.     pop    bx
  1169.     ret
  1170.  
  1171.     public    send_queue
  1172. send_queue:
  1173. ; Queue an iocb.
  1174. ; Enter with es:di -> iocb, interrupts disabled.
  1175. ; Destroys ds:si.
  1176.     assume    ds:nothing, es:nothing
  1177.     mov    es:[di].next.offs,0    ; Zero next offset
  1178.     mov    es:[di].next.segm,0    ; Zero next segment
  1179.     mov    si,send_head.offs    ; Queue empty?
  1180.     or    si,send_head.segm
  1181.     jnz    sq_notempty        ; No
  1182.     mov    send_head.offs,di    ; Set head offset
  1183.     mov    send_head.segm,es    ; Set head segment
  1184.     jmp    sq_settail
  1185. sq_notempty:                ; Queue is not empty
  1186.     lds    si,send_tail        ; Get tail segment:offset
  1187.     mov    ds:[si].next.offs,di    ; Set next offset
  1188.     mov    ds:[si].next.segm,es    ; Set next segment
  1189. sq_settail:
  1190.     mov    send_tail.offs,di    ; Set tail offset
  1191.     mov    send_tail.segm,es    ; Set tail segment
  1192.     ret
  1193.  
  1194.  
  1195.     public    send_dequeue
  1196. send_dequeue:
  1197. ; Dequeue an iocb and possibly call its upcall.
  1198. ; Enter with device or processor interrupts disabled, ah = return code.
  1199. ; Exits with es:di -> iocb; destroys ds:si, ax, bx, cx, dx, bp.
  1200.     assume    ds:nothing, es:nothing
  1201.     les    di,send_head        ; Get head segment:offset
  1202.     lds    si,es:[di].next        ; Get next segment:offset
  1203.     mov    send_head.offs, si    ; Set head offset
  1204.     mov    send_head.segm, ds    ; Set head segment
  1205.     or    es:flags[di], DONE    ; Mark done
  1206.     mov    es:ret_code[di], ah    ; Set retcode
  1207.     test    es:[di].flags,CALLME    ; Does he want an upcall?
  1208.     je    send_dequeue_1        ; No.
  1209.     push    es            ; Push iocb segment
  1210.     push    di            ;  and offset
  1211.     clc                ; Clear carry.
  1212.     mov    ax,1            ; Push a number that cant be flags.
  1213.     push    ax
  1214.     pushf                ; Save flags in case iret used.
  1215.     call    es:[di].upcall        ; Call the client.
  1216.     pop    ax            ; Pop first word.
  1217.     cmp    ax,1            ; If this is a 1, IRET was used.
  1218.     je    send_dequeue_2        ; Far return used.
  1219.     add    sp,2            ; Pop flags.
  1220. send_dequeue_2:
  1221.     pop    di            ; Pop iocb segment
  1222.     pop    es            ;  and offset
  1223. send_dequeue_1:
  1224.     ret
  1225.  
  1226.  
  1227. code    ends
  1228.  
  1229.     end    start
  1230.