home *** CD-ROM | disk | FTP | other *** search
/ C/C++ User's Journal & Wi…eveloper's Journal Tools / C-C__Users_Journal_and_Windows_Developers_Journal_Tools_1997.iso / gsidemo / head.asm < prev    next >
Encoding:
Assembly Source File  |  1994-09-30  |  37.8 KB  |  1,448 lines

  1.     include    defs.asm
  2.  
  3.  
  4.  
  5. ;  Copyright, 1988-1993, Russell Nelson, Crynwr Software
  6.  
  7.  
  8.  
  9. ;   This program is free software; you can redistribute it and/or modify
  10.  
  11. ;   it under the terms of the GNU General Public License as published by
  12.  
  13. ;   the Free Software Foundation, version 1.
  14.  
  15. ;
  16.  
  17. ;   This program is distributed in the hope that it will be useful,
  18.  
  19. ;   but WITHOUT ANY WARRANTY; without even the implied warranty of
  20.  
  21. ;   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  22.  
  23. ;   GNU General Public License for more details.
  24.  
  25. ;
  26.  
  27. ;   You should have received a copy of the GNU General Public License
  28.  
  29. ;   along with this program; if not, write to the Free Software
  30.  
  31. ;   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  32.  
  33.  
  34.  
  35. code    segment word public
  36.  
  37.     assume    cs:code, ds:code
  38.  
  39.  
  40.  
  41.     public    phd_environ
  42.  
  43.     org    2ch
  44.  
  45. phd_environ    dw    ?
  46.  
  47.  
  48.  
  49.     public    phd_dioa
  50.  
  51.     org    80h
  52.  
  53. phd_dioa    label    byte
  54.  
  55.  
  56.  
  57.     org    100h
  58.  
  59. start:
  60.  
  61.     jmp    start_1
  62.  
  63.     extrn    start_1: near
  64.  
  65.     db    "PK"
  66.  
  67.     extrn    branding_msg: byte
  68.  
  69.     dw    branding_msg
  70.  
  71.  
  72.  
  73.     even                ;put the stack on a word boundary.
  74.  
  75.     dw    128 dup(?)        ;128 words of stack.
  76.  
  77. our_stack    label    byte
  78.  
  79.  
  80.  
  81.  
  82.  
  83.     extrn    int_no: byte
  84.  
  85.  
  86.  
  87.     public    entry_point, sys_features, flagbyte, is_186, is_286, is_386
  88.  
  89. entry_point    db    ?,?,?,?        ; interrupt to communicate.
  90.  
  91. sys_features    db    0        ; 2h = MC   40h = 2nd 8259
  92.  
  93. is_186        db    0        ;=0 if 808[68], =1 if 80[123]86.
  94.  
  95. is_286        db    0        ;=0 if 80[1]8[68], =1 if 80[234]86.
  96.  
  97. is_386        db    0        ;=0 if 80[12]8[68], =1 if 80[34]86.
  98.  
  99. flagbyte    db    0
  100.  
  101. original_mask    db    0        ;=0 if interrupt was originally on.
  102.  
  103.     even
  104.  
  105.  
  106.  
  107. functions    label    word
  108.  
  109.     dw    f_not_implemented    ;0
  110.  
  111.     dw    f_driver_info        ;1
  112.  
  113.     dw    f_access_type        ;2
  114.  
  115.     dw    f_release_type        ;3
  116.  
  117.     dw    f_send_pkt        ;4
  118.  
  119.     dw    f_terminate        ;5
  120.  
  121.     dw    f_get_address        ;6
  122.  
  123.     dw    f_reset_interface    ;7
  124.  
  125.     dw    f_stop            ;8
  126.  
  127.     dw    f_not_implemented    ;9
  128.  
  129.     dw    f_get_parameters    ;10
  130.  
  131.     dw    f_not_implemented    ;11
  132.  
  133.     dw    f_as_send_pkt        ;12
  134.  
  135.     dw    f_drop_pkt        ;13
  136.  
  137.     dw    f_not_implemented    ;14
  138.  
  139.     dw    f_not_implemented    ;15
  140.  
  141.     dw    f_not_implemented    ;16
  142.  
  143.     dw    f_not_implemented    ;17
  144.  
  145.     dw    f_not_implemented    ;18
  146.  
  147.     dw    f_not_implemented    ;19
  148.  
  149.     dw    f_set_rcv_mode        ;20
  150.  
  151.     dw    f_get_rcv_mode        ;21
  152.  
  153.     dw    f_set_multicast_list    ;22
  154.  
  155.     dw    f_get_multicast_list    ;23
  156.  
  157.     dw    f_get_statistics    ;24
  158.  
  159.     dw    f_set_address        ;25
  160.  
  161.  
  162.  
  163. ;external data supplied by device-dependent module:
  164.  
  165.     extrn    driver_class: byte
  166.  
  167.     extrn    driver_type: byte
  168.  
  169.     extrn    driver_name: byte
  170.  
  171.     extrn    driver_function: byte
  172.  
  173.     extrn    parameter_list: byte
  174.  
  175.     extrn    rcv_modes: word        ;count of modes followed by mode handles.
  176.  
  177.  
  178.  
  179. ;external code supplied by device-dependent module:
  180.  
  181.     extrn    send_pkt: near
  182.  
  183.     extrn    as_send_pkt: near
  184.  
  185.     extrn    drop_pkt: near
  186.  
  187.     extrn    set_address: near
  188.  
  189.     extrn    terminate: near
  190.  
  191.     extrn    reset_interface: near
  192.  
  193.     extrn    xmit: near
  194.  
  195.     extrn    recv: near
  196.  
  197.     extrn    etopen: near
  198.  
  199.     extrn    set_multicast_list: near
  200.  
  201.     extrn    timer_isr: near
  202.  
  203.  
  204.  
  205. per_handle    struc
  206.  
  207. in_use        db    0        ;non-zero if this handle is in use.
  208.  
  209. packet_type    db    MAX_P_LEN dup(0);associated packet type.
  210.  
  211. packet_type_len    dw    0        ;associated packet type length.
  212.  
  213. receiver    dd    0        ;receiver handler.
  214.  
  215. receiver_sig    db    8 dup(?)    ;signature at the receiver handler.
  216.  
  217. class        db    ?        ;interface class
  218.  
  219. per_handle    ends
  220.  
  221.  
  222.  
  223. handles        per_handle MAX_HANDLE dup(<>)
  224.  
  225. end_handles    label    byte
  226.  
  227.  
  228.  
  229.     public    multicast_count, multicast_addrs, multicast_broad
  230.  
  231. multicast_count    dw    0        ;count of stored multicast addresses.
  232.  
  233. multicast_broad    db    0ffh,0ffh,0ffh,0ffh,0ffh,0ffh    ; entry for broadcast
  234.  
  235. multicast_addrs    db    MAX_MULTICAST*EADDR_LEN dup(?)
  236.  
  237.  
  238.  
  239. ;the device-dependent code reads the board's address from ROM in the
  240.  
  241. ;initialization code.
  242.  
  243.     public    address_len, rom_address, my_address
  244.  
  245. address_len    dw    EADDR_LEN        ;default to Ethernet.
  246.  
  247. rom_address    db    MAX_ADDR_LEN dup(?)    ;our address in ROM.
  248.  
  249. my_address    db    MAX_ADDR_LEN dup(?)    ;our current address.
  250.  
  251.  
  252.  
  253. rcv_mode_num    dw    3
  254.  
  255.  
  256.  
  257. free_handle    dw    0        ; temp, a handle not in use
  258.  
  259. found_handle    dw    0        ; temp, handle for our packet
  260.  
  261. receive_ptr    dd    0        ; the pkt receive service routine
  262.  
  263.  
  264.  
  265.     public    send_head, send_tail
  266.  
  267. send_head    dd    0        ; head of transmit queue
  268.  
  269. send_tail    dd    0        ; tail of transmit queue
  270.  
  271.  
  272.  
  273. statistics_list    label    dword
  274.  
  275. packets_in    dw    ?,?
  276.  
  277. packets_out    dw    ?,?
  278.  
  279. bytes_in    dw    ?,?
  280.  
  281. bytes_out    dw    ?,?
  282.  
  283. errors_in    dw    ?,?
  284.  
  285. errors_out    dw    ?,?
  286.  
  287. packets_dropped    dw    ?,?        ;dropped due to no type handler.
  288.  
  289.  
  290.  
  291. savespss    label    dword
  292.  
  293. savesp        dw    ?        ;saved during the stack swap.
  294.  
  295. savess        dw    ?
  296.  
  297.  
  298.  
  299.     public    their_timer
  300.  
  301. their_timer    dd    0        ;original owner of timer int
  302.  
  303. their_recv_isr    dd    0        ;original owner of board int.
  304.  
  305.  
  306.  
  307. ;
  308.  
  309. ; The following structure is used to access the registers pushed by the
  310.  
  311. ; packet driver interrupt handler.  Don't change this structure without also
  312.  
  313. ; changing the "bytes" structure given below.
  314.  
  315. ;
  316.  
  317. regs    struc                ; stack offsets of incoming regs
  318.  
  319. _ES    dw    ?
  320.  
  321. _DS    dw    ?
  322.  
  323. _BP    dw    ?
  324.  
  325. _DI    dw    ?
  326.  
  327. _SI    dw    ?
  328.  
  329. _DX    dw    ?
  330.  
  331. _CX    dw    ?
  332.  
  333. _BX    dw    ?
  334.  
  335. _AX    dw    ?
  336.  
  337. _IP    dw    ?
  338.  
  339. _CS    dw    ?
  340.  
  341. _F    dw    ?            ; flags, Carry flag is bit 0
  342.  
  343. regs    ends
  344.  
  345.  
  346.  
  347. ;
  348.  
  349. ; bits in the _F register.
  350.  
  351. ;
  352.  
  353. CY    equ    0001h
  354.  
  355. EI    equ    0200h
  356.  
  357.  
  358.  
  359.  
  360.  
  361. ;
  362.  
  363. ; This structure is a bytewise version of the "regs" structure above.
  364.  
  365. ;
  366.  
  367. bytes    struc                ; stack offsets of incoming regs
  368.  
  369.     dw    ?            ; es, ds, bp, di, si are 16 bits
  370.  
  371.     dw    ?
  372.  
  373.     dw    ?
  374.  
  375.     dw    ?
  376.  
  377.     dw    ?
  378.  
  379. _DL    db    ?
  380.  
  381. _DH    db    ?
  382.  
  383. _CL    db    ?
  384.  
  385. _CH    db    ?
  386.  
  387. _BL    db    ?
  388.  
  389. _BH    db    ?
  390.  
  391. _AL    db    ?
  392.  
  393. _AH    db    ?
  394.  
  395. bytes    ends
  396.  
  397.  
  398.  
  399.     public    their_isr
  400.  
  401. their_isr    dd    0        ; original owner of pkt driver int
  402.  
  403.  
  404.  
  405.     public    our_isr
  406.  
  407. our_isr:
  408.  
  409.     jmp    short our_isr_0        ;the required signature.
  410.  
  411.     nop
  412.  
  413.     db    'PKT DRVR',0
  414.  
  415.  
  416.  
  417.  
  418.  
  419. our_isr_open:
  420.  
  421.     push    ax            ; save lots of registers
  422.  
  423.     push    bx
  424.  
  425.     push    cx
  426.  
  427.     push    dx
  428.  
  429.     push    si
  430.  
  431.     push    di
  432.  
  433.     push    bp
  434.  
  435.     push    ds
  436.  
  437.     push    es
  438.  
  439.  
  440.  
  441.     call    etopen            ; init the card
  442.  
  443.     jc    our_isr_no_init
  444.  
  445.  
  446.  
  447.     mov    si,offset rom_address    ;copy their original address to
  448.  
  449.     movseg    es,ds
  450.  
  451.     mov    di,offset my_address    ;  their current address.
  452.  
  453.     mov    cx,MAX_ADDR_LEN/2
  454.  
  455.     rep    movsw
  456.  
  457.  
  458.  
  459.     cmp    rcv_modes+2[3*2],0    ;does mode 3 exist?
  460.  
  461.     stc                ;make sure we generate an error!
  462.  
  463.     je    our_isr_no_init        ;no.
  464.  
  465.     call    rcv_modes+2[3*2]    ;  call it.
  466.  
  467.     clc
  468.  
  469.  
  470.  
  471. our_isr_no_init:
  472.  
  473.     pop    es            ; restore lots of registers
  474.  
  475.     pop    ds
  476.  
  477.     pop    bp
  478.  
  479.     pop    di
  480.  
  481.     pop    si
  482.  
  483.     pop    dx
  484.  
  485.     pop    cx
  486.  
  487.     pop    bx
  488.  
  489.     pop    ax
  490.  
  491.     mov    dh,CANT_RESET        ; (actually can't initialize)
  492.  
  493.     jc    our_isr_error
  494.  
  495.     or    flagbyte,CALLED_ETOPEN    ; remember this fact
  496.  
  497.     jmp    short our_isr_cont
  498.  
  499.  
  500.  
  501.  
  502.  
  503. our_isr_0:
  504.  
  505.     assume    ds:nothing
  506.  
  507.     push    ax
  508.  
  509.     push    bx
  510.  
  511.     push    cx
  512.  
  513.     push    dx
  514.  
  515.     push    si
  516.  
  517.     push    di
  518.  
  519.     push    bp
  520.  
  521.     push    ds
  522.  
  523.     push    es
  524.  
  525.     cld
  526.  
  527.     mov    bx,cs            ;set up ds.
  528.  
  529.     mov    ds,bx
  530.  
  531.     assume    ds:code
  532.  
  533.     mov    bp,sp            ;we use bp to access the original regs.
  534.  
  535.     and    _F[bp],not CY        ;start by clearing the carry flag.
  536.  
  537.  
  538.  
  539.   if 0
  540.  
  541.     test    _F[bp],EI        ;were interrupt on?
  542.  
  543.     jz    our_isr_ei        ;no, don't turn them back on.
  544.  
  545.     sti                ;yes, turn them back on.
  546.  
  547. our_isr_ei:
  548.  
  549.   endif
  550.  
  551.  
  552.  
  553.     test    flagbyte,CALLED_ETOPEN    ; have we initialized the card?
  554.  
  555.     jz    our_isr_open        ; no
  556.  
  557. our_isr_cont:
  558.  
  559.     mov    bl,ah            ;jump to the correct function.
  560.  
  561.     xor    bh,bh
  562.  
  563.     cmp    bx,25            ;only twenty five functions right now.
  564.  
  565.     ja    f_bad_command
  566.  
  567.     add    bx,bx            ;*2
  568.  
  569. ;
  570.  
  571. ; The functions are called with all the original registers except
  572.  
  573. ; BX, DH, and BP.  They do not need to preserve any of them.  If the
  574.  
  575. ; function returns with cy clear, all is well.  Otherwise dh=error number.
  576.  
  577. ;
  578.  
  579.     call    functions[bx]
  580.  
  581.     assume    ds:nothing
  582.  
  583.     jc    our_isr_error
  584.  
  585. our_isr_return:
  586.  
  587.     pop    es
  588.  
  589.     pop    ds
  590.  
  591.     pop    bp
  592.  
  593.     pop    di
  594.  
  595.     pop    si
  596.  
  597.     pop    dx
  598.  
  599.     pop    cx
  600.  
  601.     pop    bx
  602.  
  603.     pop    ax
  604.  
  605.     iret
  606.  
  607.  
  608.  
  609. our_isr_error:
  610.  
  611.     assume    ds:nothing
  612.  
  613.     mov    bp,sp            ;we use bp to access the original regs.
  614.  
  615.     mov    _DH[bp],dh
  616.  
  617.     or    _F[bp],CY        ;return their carry flag.
  618.  
  619.     jmp    short our_isr_return
  620.  
  621.  
  622.  
  623. f_bad_command:
  624.  
  625.     assume    ds:code
  626.  
  627.     extrn    bad_command_intercept: near
  628.  
  629.     mov    bx,_BX[bp]
  630.  
  631.     call    bad_command_intercept
  632.  
  633.     mov    _BX[bp],bx
  634.  
  635.     mov    _DX[bp],dx
  636.  
  637.     jnc    our_isr_return
  638.  
  639.     jmp    our_isr_error
  640.  
  641.  
  642.  
  643.     public    re_enable_interrupts
  644.  
  645. re_enable_interrupts:
  646.  
  647. ; Possibly re-enable interrupts.  We put this here so that other routines
  648.  
  649. ; don't need to know how we put things on the stack.
  650.  
  651.     test    _F[bp], EI        ; Were interrupts enabled on pkt driver entry?
  652.  
  653.     je    re_enable_interrupts_1    ; No.
  654.  
  655.     sti                ; Yes, re-enable interrupts now.
  656.  
  657. re_enable_interrupts_1:
  658.  
  659.     ret
  660.  
  661.  
  662.  
  663.  
  664.  
  665. f_not_implemented:
  666.  
  667.     mov    dh,BAD_COMMAND
  668.  
  669.     stc
  670.  
  671.     ret
  672.  
  673.  
  674.  
  675.  
  676.  
  677. f_driver_info:
  678.  
  679. ;    As of 1.08, the handle is optional, so we no longer verify it.
  680.  
  681. ;    call    verify_handle
  682.  
  683.     cmp    _AL[bp],0ffh        ; correct calling convention?
  684.  
  685.     jne    f_driver_info_1        ; ne = incorrect, fail
  686.  
  687.  
  688.  
  689.                     ;For enhanced PD, if they call
  690.  
  691.     cmp    _BX[bp],offset handles    ;with a handle, give them the
  692.  
  693.                     ;class they think it is
  694.  
  695.     jb    default_handle
  696.  
  697.     cmp    _BX[bp],offset end_handles ;otherwise default to first class
  698.  
  699.     jae    default_handle
  700.  
  701.     mov    bx, _BX[bp]
  702.  
  703.     cmp    [bx].in_use,0        ;if it's not in use, it's bad.
  704.  
  705.     je    default_handle
  706.  
  707.     mov    al, [bx].class
  708.  
  709.     mov    _CH[bp], al
  710.  
  711.     jmp    short got_handle
  712.  
  713.  
  714.  
  715. default_handle:
  716.  
  717.     mov    al,driver_class
  718.  
  719.     mov    _CH[bp],al
  720.  
  721. got_handle:
  722.  
  723.  
  724.  
  725.     mov    _BX[bp],majver        ;version
  726.  
  727.     mov    al,driver_type
  728.  
  729.     cbw
  730.  
  731.     mov    _DX[bp],ax
  732.  
  733.     mov    _CL[bp],0        ;number zero.
  734.  
  735.     mov    _DS[bp],ds        ; point to our name in their ds:si
  736.  
  737.     mov    _SI[bp],offset driver_name
  738.  
  739.     mov    al,driver_function
  740.  
  741.     mov    _AL[bp],al
  742.  
  743.     clc
  744.  
  745.     ret
  746.  
  747. f_driver_info_1:
  748.  
  749.     stc
  750.  
  751.     ret
  752.  
  753.  
  754.  
  755.  
  756.  
  757. f_set_rcv_mode:
  758.  
  759.     call    verify_handle
  760.  
  761.     cmp    cx,rcv_mode_num        ;are we already using that mode?
  762.  
  763.     je    f_set_rcv_mode_4    ;yes, no need to check anything.
  764.  
  765.  
  766.  
  767.     mov    dx,bx            ;remember our handle.
  768.  
  769.  
  770.  
  771.     call    count_handles        ;is ours the only open handle?
  772.  
  773.     cmp    cl,1
  774.  
  775.     jne    f_set_rcv_mode_1    ;no, don't change the receive mode.
  776.  
  777.  
  778.  
  779.     mov    cx,_CX[bp]        ;get the desired receive mode.
  780.  
  781.     cmp    cx,rcv_modes        ;do they have this many modes?
  782.  
  783.     jae    f_set_rcv_mode_1    ;no - must be a bad mode for us.
  784.  
  785.     mov    bx,cx
  786.  
  787.     add    bx,bx            ;we're accessing words, not bytes.
  788.  
  789.     mov    ax,rcv_modes[bx]+2    ;get the handler for this mode.
  790.  
  791.     or    ax,ax            ;do they have one?
  792.  
  793.     je    f_set_rcv_mode_1    ;no - must be a bad mode for us.
  794.  
  795.     mov    rcv_mode_num,cx        ;yes - remember the number and
  796.  
  797.     call    ax            ;  call it.
  798.  
  799. f_set_rcv_mode_4:
  800.  
  801.     clc
  802.  
  803.     ret
  804.  
  805. f_set_rcv_mode_1:
  806.  
  807.     mov    dh,BAD_MODE
  808.  
  809.     stc
  810.  
  811.     ret
  812.  
  813.  
  814.  
  815.  
  816.  
  817. f_get_rcv_mode:
  818.  
  819.     call    verify_handle
  820.  
  821.     mov    ax,rcv_mode_num        ;return the current receive mode.
  822.  
  823.     mov    _AX[bp],ax
  824.  
  825.     clc
  826.  
  827.     ret
  828.  
  829.  
  830.  
  831.  
  832.  
  833. f_set_multicast_list:
  834.  
  835. ;following instruction not needed because cx hasn't been changed.
  836.  
  837. ;    mov    cx,_CX[bp]        ;Tell them how much room they have.
  838.  
  839.  
  840.  
  841. ;verify that they supplied an even number of EADDR's.
  842.  
  843.     mov    ax,cx
  844.  
  845.     xor    dx,dx
  846.  
  847.     mov    bx,EADDR_LEN
  848.  
  849.     div    bx
  850.  
  851.     or    dx,dx            ;zero remainder?
  852.  
  853.     jne    f_set_multicast_list_2    ;no, we don't have an even number of
  854.  
  855.                     ;  addresses.
  856.  
  857.  
  858.  
  859.     cmp    ax,MAX_MULTICAST    ;is this too many?
  860.  
  861.     ja    f_set_multicast_list_3    ;yes - return NO_SPACE
  862.  
  863. f_set_multicast_list_1:
  864.  
  865.     mov    multicast_count,ax    ;remember the number of addresses.
  866.  
  867.     movseg    es,cs
  868.  
  869.     mov    di,offset multicast_addrs
  870.  
  871.     push    ds
  872.  
  873.     mov    ds,_ES[bp]        ; get ds:si -> new list.
  874.  
  875.     mov    si,_DI[bp]
  876.  
  877.     push    cx
  878.  
  879.     rep    movsb
  880.  
  881.     pop    cx
  882.  
  883.     pop    ds
  884.  
  885.  
  886.  
  887.     mov    si,offset multicast_addrs
  888.  
  889.     call    set_multicast_list
  890.  
  891.     ret
  892.  
  893. f_set_multicast_list_2:
  894.  
  895.     mov    dh,BAD_ADDRESS
  896.  
  897.     stc
  898.  
  899.     ret
  900.  
  901. f_set_multicast_list_3:
  902.  
  903.     mov    dh,NO_SPACE
  904.  
  905.     stc
  906.  
  907.     ret
  908.  
  909.  
  910.  
  911.  
  912.  
  913. f_get_multicast_list:
  914.  
  915.     mov    _ES[bp],ds        ;return what we have remembered.
  916.  
  917.     mov    _DI[bp],offset multicast_addrs
  918.  
  919.     mov    ax,EADDR_LEN        ;multiply the count by the length.
  920.  
  921.     mul    multicast_count
  922.  
  923.     mov    _CX[bp],ax        ;because they want total bytes.
  924.  
  925.     clc
  926.  
  927.     ret
  928.  
  929.  
  930.  
  931.  
  932.  
  933. f_get_statistics:
  934.  
  935.     call    verify_handle        ;just in case.
  936.  
  937.     mov    _DS[bp],ds
  938.  
  939.     mov    _SI[bp],offset statistics_list
  940.  
  941.     clc
  942.  
  943.     ret
  944.  
  945.  
  946.  
  947.  
  948.  
  949. access_type_class:
  950.  
  951.     mov    dh,NO_CLASS
  952.  
  953.     stc
  954.  
  955.     ret
  956.  
  957.  
  958.  
  959. access_type_type:
  960.  
  961.     mov    dh,NO_TYPE
  962.  
  963.     stc
  964.  
  965.     ret
  966.  
  967.  
  968.  
  969. access_type_number:
  970.  
  971.     mov    dh,NO_NUMBER
  972.  
  973.     stc
  974.  
  975.     ret
  976.  
  977.  
  978.  
  979. access_type_bad:
  980.  
  981.     mov    dh,BAD_TYPE
  982.  
  983.     stc
  984.  
  985.     ret
  986.  
  987.  
  988.  
  989. ;register caller of pkt TYPE
  990.  
  991. f_access_type:
  992.  
  993.     mov    bx, offset driver_class
  994.  
  995. access_type_9:
  996.  
  997.     mov    al, [bx]        ;get the next class.
  998.  
  999.     inc    bx
  1000.  
  1001.     or    al,al            ;end of the list?
  1002.  
  1003.     je    access_type_class    ;class failed (story of my life)
  1004.  
  1005.     cmp    _AL[bp],al        ;our class?
  1006.  
  1007.     jne    access_type_9        ;no, try again
  1008.  
  1009. access_type_1:
  1010.  
  1011.     cmp    _BX[bp],-1        ;generic type?
  1012.  
  1013.     je    access_type_2        ;yes.
  1014.  
  1015.     mov    al,driver_type
  1016.  
  1017.     cbw
  1018.  
  1019.     cmp    _BX[bp],ax        ;our type?
  1020.  
  1021.     jne    access_type_type    ;no.
  1022.  
  1023. access_type_2:
  1024.  
  1025.     cmp    _DL[bp],0        ;generic number?
  1026.  
  1027.     je    access_type_3
  1028.  
  1029.     cmp    _DL[bp],1        ;our number?
  1030.  
  1031.     jne    access_type_number
  1032.  
  1033. access_type_3:
  1034.  
  1035.     cmp    _CX[bp],MAX_P_LEN    ;is the type length too long?
  1036.  
  1037.     ja    access_type_bad        ;yes - can't be ours.
  1038.  
  1039.  
  1040.  
  1041. ; now we do two things--look for an open handle, and check the existing
  1042.  
  1043. ; handles to see if they're replicating a packet type.
  1044.  
  1045.  
  1046.  
  1047.     mov    free_handle,0        ;remember no free handle yet.
  1048.  
  1049.     mov    bx,offset handles
  1050.  
  1051. access_type_4:
  1052.  
  1053.     cmp    [bx].in_use,0        ;is this handle in use?
  1054.  
  1055.     je    access_type_5        ;no - don't check the type.
  1056.  
  1057.     mov    al, _AL[bp]        ;is this handle the same class as
  1058.  
  1059.     cmp    al, [bx].class        ;  they're want?
  1060.  
  1061.     jne    short access_type_6
  1062.  
  1063.     mov    es,_DS[bp]        ;get a pointer to their type
  1064.  
  1065.     mov    di,_SI[bp]        ;  from their ds:si to our es:di
  1066.  
  1067.     mov    cx,_CX[bp]        ;get the minimum of their length
  1068.  
  1069.                     ;  and our length.  As currently
  1070.  
  1071.                     ;  implemented, only one receiver
  1072.  
  1073.                     ;  gets the packets, so we have to
  1074.  
  1075.                     ;  ensure that the shortest prefix
  1076.  
  1077.                     ;  is unique.
  1078.  
  1079.     cmp    cx,[bx].packet_type_len    ;Are we less specific than they are?
  1080.  
  1081.     jb    access_type_8        ;no.
  1082.  
  1083.     mov    cx,[bx].packet_type_len    ;yes - use their count.
  1084.  
  1085. access_type_8:
  1086.  
  1087.     lea    si,[bx].packet_type
  1088.  
  1089.     or    cx,cx            ; pass-all TYPE? (zero TYPE length)
  1090.  
  1091.     jne    access_type_7        ; ne = no
  1092.  
  1093.     mov    bx,offset handles+(MAX_HANDLE-1)*(size per_handle)
  1094.  
  1095.     jmp    short access_type_5    ; put pass-all last
  1096.  
  1097. access_type_7:
  1098.  
  1099.     repe    cmpsb
  1100.  
  1101.     jne    short access_type_6    ;go look at the next one.
  1102.  
  1103. access_type_inuse:
  1104.  
  1105.     mov    dh,TYPE_INUSE        ;a handle has been assigned for TYPE
  1106.  
  1107.     stc                ;and we can't assign another
  1108.  
  1109.     ret
  1110.  
  1111. access_type_5:                ;handle is not in use
  1112.  
  1113.     cmp    free_handle,0        ;found a free handle yet?
  1114.  
  1115.     jne    access_type_6        ;yes.
  1116.  
  1117.     mov    free_handle,bx        ;remember a free handle
  1118.  
  1119. access_type_6:
  1120.  
  1121.     add    bx,(size per_handle)    ;go to the next handle.
  1122.  
  1123.     cmp    bx,offset end_handles    ;examined all handles?
  1124.  
  1125.     jb    access_type_4        ;no, continue.
  1126.  
  1127.  
  1128.  
  1129.     mov    bx,free_handle        ;did we find a free handle?
  1130.  
  1131.     or    bx,bx
  1132.  
  1133.     je    access_type_space    ;no - return error.
  1134.  
  1135.  
  1136.  
  1137.     mov    ax,_DI[bp]        ;remember the receiver type.
  1138.  
  1139.     mov    [bx].receiver.offs,ax
  1140.  
  1141.     mov    ax,_ES[bp]
  1142.  
  1143.     mov    [bx].receiver.segm,ax
  1144.  
  1145.  
  1146.  
  1147.     push    ds
  1148.  
  1149.     mov    ax,ds
  1150.  
  1151.     mov    es,ax
  1152.  
  1153.     mov    ds,_DS[bp]        ;remember their type.
  1154.  
  1155.     mov    si,_SI[bp]
  1156.  
  1157.     mov    cx,_CX[bp]
  1158.  
  1159.     mov    es:[bx].packet_type_len,cx    ; remember the TYPE length
  1160.  
  1161.     lea    di,[bx].packet_type
  1162.  
  1163.     rep    movsb
  1164.  
  1165.  
  1166.  
  1167.     lds    si,es:[bx].receiver    ;copy the first 8 bytes
  1168.  
  1169.     lea    di,[bx].receiver_sig    ; to the receiver signature.
  1170.  
  1171.     mov    cx,8/2
  1172.  
  1173.     rep    movsw
  1174.  
  1175.  
  1176.  
  1177.     pop    ds
  1178.  
  1179.  
  1180.  
  1181.     mov    al, _AL[bp]
  1182.  
  1183.     mov    [bx].class, al
  1184.  
  1185.  
  1186.  
  1187.     mov    [bx].in_use,1        ;remember that we're using it.
  1188.  
  1189.  
  1190.  
  1191.     mov    _AX[bp],bx        ;return the handle to them.
  1192.  
  1193.  
  1194.  
  1195.     clc
  1196.  
  1197.     ret
  1198.  
  1199.  
  1200.  
  1201.  
  1202.  
  1203. access_type_space:
  1204.  
  1205.     mov    dh,NO_SPACE
  1206.  
  1207.     stc
  1208.  
  1209.     ret
  1210.  
  1211.  
  1212.  
  1213. f_release_type:
  1214.  
  1215.     call    verify_handle        ;mark this handle as being unused.
  1216.  
  1217.     mov    [bx].in_use,0
  1218.  
  1219.  
  1220.  
  1221.     call    count_handles        ;All handles gone now?
  1222.  
  1223.     cmp    cl,0
  1224.  
  1225.     jne    f_release_type_1    ;no, don't change the receive mode.
  1226.  
  1227.  
  1228.  
  1229.   if 0
  1230.  
  1231.     cmp    rcv_modes+2[3*2],0    ;does mode 3 exist?
  1232.  
  1233.     je    f_release_type_1    ;no.
  1234.  
  1235.     mov    rcv_mode_num,3        ;yes - remember the number and
  1236.  
  1237.     call    rcv_modes+2[3*2]    ;  call it.
  1238.  
  1239.   endif
  1240.  
  1241. f_release_type_1:
  1242.  
  1243.     clc
  1244.  
  1245.     ret
  1246.  
  1247.  
  1248.  
  1249.  
  1250.  
  1251. f_send_pkt:
  1252.  
  1253. ;ds:si -> buffer, cx = length
  1254.  
  1255. ; XXX Should re-enable interrupts here, but some drivers are broken.
  1256.  
  1257. ; Possibly re-enable interrupts.
  1258.  
  1259. ;    test _F[bp], EI        ; Were interrupts enabled on pkt driver entry?
  1260.  
  1261. ;    je    f_send_pkt_1    ; No.
  1262.  
  1263. ;    sti            ; Yes, re-enable interrupts now.
  1264.  
  1265. ;f_send_pkt_1:
  1266.  
  1267.  
  1268.  
  1269. ;following two instructions not needed because si and cx haven't been changed.
  1270.  
  1271. ;    mov    si,_SI[bp]
  1272.  
  1273. ;    mov    cx,_CX[bp]    ; count of bytes in the packet.
  1274.  
  1275.     add2    packets_out,1
  1276.  
  1277.     add2    bytes_out,cx        ;add up the received bytes.
  1278.  
  1279.  
  1280.  
  1281.     mov    ds,_DS[bp]    ; address of buffer from caller's ds.
  1282.  
  1283.     assume    ds:nothing, es:nothing
  1284.  
  1285.  
  1286.  
  1287. ; If -n option take Ethernet encapsulated Novell IPX packets (from BYU's 
  1288.  
  1289. ; PDSHELL) and change them to be IEEE 802.3 encapsulated.
  1290.  
  1291. EPROT_OFF    equ    EADDR_LEN*2
  1292.  
  1293.     test    cs:flagbyte,N_OPTION
  1294.  
  1295.     jnz    f_send_pkt_2
  1296.  
  1297.     call    send_pkt
  1298.  
  1299.     ret
  1300.  
  1301.  
  1302.  
  1303. f_send_pkt_2:
  1304.  
  1305.     cmp    ds:[si].EPROT_OFF,3781h ; if not Novell (prot 8137)
  1306.  
  1307.     jne    f_send_pkt_3        ;  don't tread on it
  1308.  
  1309.     push    ax            ; get scratch reg
  1310.  
  1311.     mov    ax,[si].EPROT_OFF+4    ; get len
  1312.  
  1313.     xchg    ah,al
  1314.  
  1315.     inc    ax            ; make even (rounding up)
  1316.  
  1317.     and    al,0feh
  1318.  
  1319.     xchg    ah,al
  1320.  
  1321.     mov    ds:[si].EPROT_OFF,ax    ; save in prot field
  1322.  
  1323.     pop    ax            ; restore old contents
  1324.  
  1325. f_send_pkt_3:
  1326.  
  1327.     call    send_pkt
  1328.  
  1329.     ret
  1330.  
  1331.     assume    ds:code
  1332.  
  1333.  
  1334.  
  1335.  
  1336.  
  1337. f_as_send_pkt:
  1338.  
  1339. ;es:di -> iocb.
  1340.  
  1341.     test    driver_function,4    ; is this a high-performance driver?
  1342.  
  1343.     je    f_as_send_pkt_2        ; no.
  1344.  
  1345. ; Possibly re-enable interrupts.
  1346.  
  1347.     test _F[bp], EI            ; Were interrupts enabled on pkt driver entry?
  1348.  
  1349.     je    f_as_send_pkt_1        ; No.
  1350.  
  1351.     sti                ; Yes, re-enable interrupts now.
  1352.  
  1353. f_as_send_pkt_1:
  1354.  
  1355.     push    ds            ; set up proper ds for the buffer
  1356.  
  1357.     lds    si,es:[di].buffer    ; ds:si -> buffer
  1358.  
  1359.     assume    ds:nothing
  1360.  
  1361.     mov    cx,es:[di].len        ; cx = length
  1362.  
  1363.     add2    packets_out,1
  1364.  
  1365.     add2    bytes_out,cx        ; add up the received bytes.
  1366.  
  1367.  
  1368.  
  1369. ;ds:si -> buffer, cx = length, es:di -> iocb.
  1370.  
  1371.     call    as_send_pkt
  1372.  
  1373.     pop    ds
  1374.  
  1375.     assume    ds:code
  1376.  
  1377.     ret
  1378.  
  1379. f_as_send_pkt_2:
  1380.  
  1381.     mov dh,    BAD_COMMAND        ; return an error.
  1382.  
  1383.     stc
  1384.  
  1385.     ret
  1386.  
  1387.  
  1388.  
  1389.  
  1390.  
  1391. f_drop_pkt:
  1392.  
  1393. ; es:di -> iocb.
  1394.  
  1395.     test    driver_function,4    ; is this a high-performance driver?
  1396.  
  1397.     je    f_as_send_pkt_2        ; no.
  1398.  
  1399.     push    ds            ; Preserve ds
  1400.  
  1401.     mov    si,offset send_head    ; Get head offset
  1402.  
  1403. dp_loop:
  1404.  
  1405.     mov    ax,ds:[si]        ; Get offset
  1406.  
  1407.     mov    dx,ds:[si+2]        ; Get segment
  1408.  
  1409.     mov    bx,ax
  1410.  
  1411.     or    bx,dx            ; End of list?
  1412.  
  1413.     je    dp_endlist        ; Yes
  1414.  
  1415.     cmp    ax,di            ; Offsets equal?
  1416.  
  1417.     jne    dp_getnext        ; No
  1418.  
  1419.     mov    bx,es
  1420.  
  1421.     cmp    dx,bx            ; Segments equal?
  1422.  
  1423.     jne    dp_getnext        ; No
  1424.  
  1425.     call    drop_pkt        ; Pass to driver
  1426.  
  1427.     les    di,es:[di].next        ; Get next segment:offset
  1428.  
  1429.     mov    ds:[si],di        ; Set next offset
  1430.  
  1431.     mov    ds:[si+2],es        ; Set next segment
  1432.  
  1433.     pop    ds            ; Restore ds
  1434.  
  1435.     clc
  1436.  
  1437.     ret
  1438.  
  1439. dp_getnext:
  1440.  
  1441.     mov    ds,dx            ; Get next segment
  1442.  
  1443.     mov    si,ax            ; Get next iocb offset
  1444.  
  1445.     lea    si,ds:[si].next        ; Get next iocb next ptr offset
  1446.  
  1447.     jmp    dp_loop            ; Try again
  1448.  
  1449. dp_endlist:
  1450.  
  1451.     pop    ds            ; Restore ds
  1452.  
  1453.     mov    dh,BAD_IOCB        ; Return error
  1454.  
  1455.     stc                ; Set carry
  1456.  
  1457.     ret
  1458.  
  1459.  
  1460.  
  1461.  
  1462.  
  1463. f_terminate:
  1464.  
  1465.     call    verify_handle        ; must have a handle
  1466.  
  1467.  
  1468.  
  1469.     mov    [bx].in_use,0        ; mark handle as free
  1470.  
  1471.     call    count_handles        ; all handles gone?
  1472.  
  1473.     or    cl,cl
  1474.  
  1475.     jne    f_terminate_4        ; no, can't exit completely
  1476.  
  1477.  
  1478.  
  1479. ;
  1480.  
  1481. ; Now disable interrupts
  1482.  
  1483. ;
  1484.  
  1485.     mov    al,int_no
  1486.  
  1487.     or    al,al            ;are they using a hardware interrupt?
  1488.  
  1489.     je    f_terminate_no_irq    ;no.
  1490.  
  1491.     cmp    original_mask,0        ;was it enabled?
  1492.  
  1493.     je    f_terminate_no_mask    ;yes, don't mask it now.
  1494.  
  1495.     call    maskint
  1496.  
  1497. f_terminate_no_mask:
  1498.  
  1499.  
  1500.  
  1501. ;
  1502.  
  1503. ; Now return the interrupt to their handler.
  1504.  
  1505. ;
  1506.  
  1507.     mov    ah,25h            ;get the old interrupt into es:bx
  1508.  
  1509.     mov    al,int_no
  1510.  
  1511.     add    al,8
  1512.  
  1513.     cmp    al,8+8            ;is it a slave 8259 interrupt?
  1514.  
  1515.     jb    f_terminate_3        ;no.
  1516.  
  1517.     add    al,70h - (8+8)        ;map it to the real interrupt.
  1518.  
  1519. f_terminate_3:
  1520.  
  1521.     push    ds
  1522.  
  1523.     lds    dx,their_recv_isr
  1524.  
  1525.     int    21h
  1526.  
  1527.     pop    ds
  1528.  
  1529.  
  1530.  
  1531. f_terminate_no_irq:
  1532.  
  1533.     cmp    their_timer.segm,0    ;did we hook the timer interrupt?
  1534.  
  1535.     je    f_terminate_no_timer
  1536.  
  1537.  
  1538.  
  1539.     mov    ax,2508h        ;restore the timer interrupt.
  1540.  
  1541.     push    ds
  1542.  
  1543.     lds    dx,their_timer
  1544.  
  1545.     int    21h
  1546.  
  1547.     pop    ds
  1548.  
  1549.  
  1550.  
  1551. f_terminate_no_timer:
  1552.  
  1553.  
  1554.  
  1555.     call    terminate        ;terminate the hardware.
  1556.  
  1557.  
  1558.  
  1559.     mov    al,entry_point    ;release our_isr.
  1560.  
  1561.     mov    ah,25h
  1562.  
  1563.     push    ds
  1564.  
  1565.     lds    dx,their_isr
  1566.  
  1567.     int    21h
  1568.  
  1569.     pop    ds
  1570.  
  1571.  
  1572.  
  1573. ;
  1574.  
  1575. ; Now free our memory
  1576.  
  1577. ;
  1578.  
  1579.     movseg    es,cs
  1580.  
  1581.     mov    ah,49h
  1582.  
  1583.     int    21h
  1584.  
  1585.     clc
  1586.  
  1587.     ret
  1588.  
  1589. f_terminate_4:
  1590.  
  1591.     mov    dh, CANT_TERMINATE
  1592.  
  1593.     stc
  1594.  
  1595.     ret
  1596.  
  1597.  
  1598.  
  1599.  
  1600.  
  1601. f_get_address:
  1602.  
  1603. ;    call    verify_handle
  1604.  
  1605. ;    mov    es,_ES[bp]        ; get new one
  1606.  
  1607. ;    mov    di,_DI[bp]        ; get pointer, es:di is ready
  1608.  
  1609. ;    mov    cx,_CX[bp]        ;Tell them how much room they have.
  1610.  
  1611.     cmp    cx,address_len        ;is there enough room for our address?
  1612.  
  1613.     jb    get_address_space    ;no.
  1614.  
  1615.     mov    cx,address_len        ;yes - get our address length.
  1616.  
  1617.     mov    _CX[bp],cx        ;Tell them how long our address is.
  1618.  
  1619.     mov    si,offset my_address    ;copy it into their area.
  1620.  
  1621.     rep    movsb
  1622.  
  1623.     clc
  1624.  
  1625.     ret
  1626.  
  1627.  
  1628.  
  1629. get_address_space:
  1630.  
  1631.     mov    dh,NO_SPACE
  1632.  
  1633.     stc
  1634.  
  1635.     ret
  1636.  
  1637.  
  1638.  
  1639.  
  1640.  
  1641. f_set_address:
  1642.  
  1643.     call    count_handles
  1644.  
  1645.     cmp    cl,1            ;more than one handle in use?
  1646.  
  1647.     ja    f_set_address_inuse    ;yes - we can't set the address
  1648.  
  1649.  
  1650.  
  1651.     mov    cx,_CX[bp]        ;get the desired address length.
  1652.  
  1653.     cmp    ch,0
  1654.  
  1655.     cmp    cl,parameter_list[3]    ;is it the right length?
  1656.  
  1657.     ja    f_set_address_too_long    ;no.
  1658.  
  1659.  
  1660.  
  1661.     mov    ds,_ES[bp]        ; set new one
  1662.  
  1663.     assume    ds:nothing
  1664.  
  1665.     mov    si,_DI[bp]        ; set pointer, ds:si is ready
  1666.  
  1667.     mov    ax,cs
  1668.  
  1669.     mov    es,ax
  1670.  
  1671.     mov    di,offset my_address
  1672.  
  1673.     rep    movsb
  1674.  
  1675.     mov    ds,ax            ;restore ds.
  1676.  
  1677.     assume    ds:code
  1678.  
  1679.  
  1680.  
  1681.     mov    cx,_CX[bp]        ;get the desired address length.
  1682.  
  1683.     mov    si,offset my_address
  1684.  
  1685.     call    set_address
  1686.  
  1687.     jc    f_set_address_err    ;Did it work?
  1688.  
  1689.  
  1690.  
  1691.     mov    cl,parameter_list[3]
  1692.  
  1693.     xor    ch,ch
  1694.  
  1695.     mov    _CX[bp],cx        ;yes - return our address length.
  1696.  
  1697.  
  1698.  
  1699.     clc
  1700.  
  1701.     ret
  1702.  
  1703. f_set_address_inuse:
  1704.  
  1705.     mov    dh,CANT_SET
  1706.  
  1707.     stc
  1708.  
  1709.     ret
  1710.  
  1711. f_set_address_too_long:
  1712.  
  1713.     mov    dh,NO_SPACE
  1714.  
  1715.     stc
  1716.  
  1717.     ret
  1718.  
  1719. f_set_address_err:
  1720.  
  1721. ;we get here with cy set - leave it set.
  1722.  
  1723.     mov    si,offset rom_address    ;we can't set the address, restore
  1724.  
  1725.     mov    di,offset my_address    ;  to original.
  1726.  
  1727.     mov    cx,MAX_ADDR_LEN/2
  1728.  
  1729.     rep    movsw
  1730.  
  1731.     ret
  1732.  
  1733.  
  1734.  
  1735.  
  1736.  
  1737. f_reset_interface:
  1738.  
  1739.     call    verify_handle
  1740.  
  1741.     call    reset_interface
  1742.  
  1743.     clc
  1744.  
  1745.     ret
  1746.  
  1747.  
  1748.  
  1749.  
  1750.  
  1751. ; Stop the packet driver doing upcalls. Also a following terminate will
  1752.  
  1753. ; always succed (no in use handles any longer).
  1754.  
  1755. f_stop:
  1756.  
  1757.     mov    bx,offset handles
  1758.  
  1759. f_stop_2:
  1760.  
  1761.     mov    [bx].in_use,0
  1762.  
  1763.     add    bx,(size per_handle)    ; next handle
  1764.  
  1765.     cmp    bx,offset end_handles
  1766.  
  1767.     jb    f_stop_2
  1768.  
  1769.     clc
  1770.  
  1771.     ret
  1772.  
  1773.  
  1774.  
  1775.  
  1776.  
  1777. f_get_parameters:
  1778.  
  1779. ;strictly speaking, this function only works for high-performance drivers.
  1780.  
  1781.     test    driver_function,4    ;is this a high-performance driver?
  1782.  
  1783.     jne    f_get_parameters_1    ;yes.
  1784.  
  1785.     mov    dh,BAD_COMMAND        ;no - return an error.
  1786.  
  1787.     stc
  1788.  
  1789.     ret
  1790.  
  1791. f_get_parameters_1:
  1792.  
  1793.     mov    _ES[bp],cs
  1794.  
  1795.     mov    _DI[bp],offset parameter_list
  1796.  
  1797.     clc
  1798.  
  1799.     ret
  1800.  
  1801.  
  1802.  
  1803.  
  1804.  
  1805. count_handles:
  1806.  
  1807. ;exit with cl = number of handles currently in use.
  1808.  
  1809.     mov    bx,offset handles
  1810.  
  1811.     mov    cl,0            ;number of handles in use.
  1812.  
  1813. count_handles_1:
  1814.  
  1815.     add    cl,[bx].in_use        ;is this handle in use?
  1816.  
  1817.     add    bx,(size per_handle)    ;go to the next handle.
  1818.  
  1819.     cmp    bx,offset end_handles
  1820.  
  1821.     jb    count_handles_1
  1822.  
  1823.     ret
  1824.  
  1825.  
  1826.  
  1827.  
  1828.  
  1829. verify_handle:
  1830.  
  1831. ;Ensure that their handle is real.  If it isn't, we pop off our return
  1832.  
  1833. ;address, and return to *their* return address with cy set.
  1834.  
  1835.     mov    bx,_BX[bp]        ;get the handle they gave us
  1836.  
  1837.     cmp    bx,offset handles
  1838.  
  1839.     jb    verify_handle_bad    ;no - must be bad.
  1840.  
  1841.     cmp    bx,offset end_handles
  1842.  
  1843.     jae    verify_handle_bad    ;no - must be bad.
  1844.  
  1845.     cmp    [bx].in_use,1        ;if it's not in use, it's bad.
  1846.  
  1847.     jne    verify_handle_bad
  1848.  
  1849.     ret
  1850.  
  1851. verify_handle_bad:
  1852.  
  1853.     mov    dh,BAD_HANDLE
  1854.  
  1855.     add    sp,2            ;pop off our return address.
  1856.  
  1857.     stc
  1858.  
  1859.     ret
  1860.  
  1861.  
  1862.  
  1863.  
  1864.  
  1865.     public    set_recv_isr
  1866.  
  1867. set_recv_isr:
  1868.  
  1869.     mov    ah,35h            ;get the old interrupt into es:bx
  1870.  
  1871.     mov    al,int_no        ; board's interrupt vector
  1872.  
  1873.     or    al,al
  1874.  
  1875.     je    set_isr_no_irq
  1876.  
  1877.     add    al,8
  1878.  
  1879.     cmp    al,8+8            ;is it a slave 8259 interrupt?
  1880.  
  1881.     jb    set_recv_isr_1        ;no.
  1882.  
  1883.     add    al,70h - 8 - 8        ;map it to the real interrupt.
  1884.  
  1885. set_recv_isr_1:
  1886.  
  1887.     int    21h
  1888.  
  1889.     mov    their_recv_isr.offs,bx    ;remember the old seg:off.
  1890.  
  1891.     mov    their_recv_isr.segm,es
  1892.  
  1893.  
  1894.  
  1895.     mov    ah,25h            ;now set our recv interrupt.
  1896.  
  1897.     mov    dx,offset recv_isr
  1898.  
  1899.     int    21h
  1900.  
  1901.  
  1902.  
  1903.     cmp    byte ptr timer_isr,0cfh    ;is there just an iret at their handler?
  1904.  
  1905.     je    set_isr_no_timer    ;yes, don't bother hooking the timer.
  1906.  
  1907.  
  1908.  
  1909.     mov    ax,3508h        ;get the old interrupt into es:bx
  1910.  
  1911.     int    21h
  1912.  
  1913.     mov    their_timer.offs,bx    ;remember the old seg:off.
  1914.  
  1915.     mov    their_timer.segm,es
  1916.  
  1917.  
  1918.  
  1919.     mov    ah,25h            ;now set our recv interrupt.
  1920.  
  1921.     mov    dx,offset timer_isr
  1922.  
  1923.     int    21h
  1924.  
  1925.  
  1926.  
  1927. set_isr_no_timer:
  1928.  
  1929.     mov    al,int_no        ; Now enable interrupts
  1930.  
  1931.     call    unmaskint
  1932.  
  1933.     mov    original_mask,al
  1934.  
  1935.  
  1936.  
  1937. set_isr_no_irq:
  1938.  
  1939.     ret
  1940.  
  1941.  
  1942.  
  1943.     public    count_in_err
  1944.  
  1945. count_in_err:
  1946.  
  1947.     assume    ds:nothing
  1948.  
  1949.     add2    errors_in,1
  1950.  
  1951.     ret
  1952.  
  1953.  
  1954.  
  1955.     public    count_out_err
  1956.  
  1957. count_out_err:
  1958.  
  1959.     assume    ds:nothing
  1960.  
  1961.     add2    errors_out,1
  1962.  
  1963.     ret
  1964.  
  1965.  
  1966.  
  1967. recv_isr_frame    struc
  1968.  
  1969. recv_isr_ds    dw    ?
  1970.  
  1971. recv_isr_dx    dw    ?
  1972.  
  1973. recv_isr_ax    dw    ?
  1974.  
  1975. recv_isr_ip    dw    ?
  1976.  
  1977. recv_isr_cs    dw    ?
  1978.  
  1979. recv_isr_f    dw    ?
  1980.  
  1981. recv_isr_frame    ends
  1982.  
  1983.  
  1984.  
  1985. ;
  1986.  
  1987. ; I have had a problem with some hardware which under extreme LAN loading
  1988.  
  1989. ; conditions will re-enter the recv_isr. Since the 8259 interrupts for
  1990.  
  1991. ; the card are masked off, and the card's interrupt mask register is 
  1992.  
  1993. ; cleared (in 8390.asm at least) disabling the card from interrupting, this
  1994.  
  1995. ; is clearly a hardware problem. Due to the low frequencey of occurance, and
  1996.  
  1997. ; extreme conditions under which this happens, it is not lilely to be fixed
  1998.  
  1999. ; in hardware any time soon, plus retrofitting of hardware in the field will
  2000.  
  2001. ; not happen. To protect the driver from the adverse effects of this I am
  2002.  
  2003. ; adding a simple re-entrancy trap here.  - gft - 910617
  2004.  
  2005. ;
  2006.  
  2007.  
  2008.  
  2009. in_recv_isr    db     0    ; flag to trap re-entrancy
  2010.  
  2011.  
  2012.  
  2013. recv_isr:
  2014.  
  2015.     cmp    in_recv_isr, 0
  2016.  
  2017.     jne    recv_iret
  2018.  
  2019.  
  2020.  
  2021.     mov    in_recv_isr, 1
  2022.  
  2023.  
  2024.  
  2025. ; I realize this re-entrancy trap is not perfect, you could be re-entered
  2026.  
  2027. ; anytime before the above instruction. However since the stacks have not
  2028.  
  2029. ; been swapped re-entrancy here will only appear to be a spurious interrupt.
  2030.  
  2031. ; - gft - 910617
  2032.  
  2033.  
  2034.  
  2035. ; In order to achieve back-to-back packet transmissions, we handle the
  2036.  
  2037. ; latency-critical portion of transmit interrupts first.  The xmit
  2038.  
  2039. ; interrupt routine should only start the next transmission, but do
  2040.  
  2041. ; no other work.  It may only touch ax and dx (the only register necessary
  2042.  
  2043. ; for doing "out" instructions) unless it first pushes any other registers
  2044.  
  2045. ; itself.
  2046.  
  2047.     push    ax
  2048.  
  2049.     push    dx
  2050.  
  2051.     call    xmit
  2052.  
  2053.  
  2054.  
  2055. ; Now switch stacks, push remaining registers, and do remaining interrupt work.
  2056.  
  2057.     push    ds
  2058.  
  2059.     mov    ax,cs            ;ds = cs.
  2060.  
  2061.     mov    ds,ax
  2062.  
  2063.     assume    ds:code
  2064.  
  2065.  
  2066.  
  2067.     mov    savesp,sp
  2068.  
  2069.     mov    savess,ss
  2070.  
  2071.  
  2072.  
  2073.     mov    ss,ax
  2074.  
  2075.     mov    sp,offset our_stack
  2076.  
  2077.     cld
  2078.  
  2079.  
  2080.  
  2081.     push    bx
  2082.  
  2083.     push    cx
  2084.  
  2085.     push    si
  2086.  
  2087.     push    di
  2088.  
  2089.     push    bp
  2090.  
  2091.     push    es
  2092.  
  2093.  
  2094.  
  2095. ; The following comment is wrong in that we now do a specific EOI command,
  2096.  
  2097. ; and because we don't enable interrupts (even though we should).
  2098.  
  2099.  
  2100.  
  2101. ; Chips & Technologies 8259 clone chip seems to be very broken.  If you
  2102.  
  2103. ; send it a Non Specific EOI command, it clears all In Service Register
  2104.  
  2105. ; bits instead of just the one with the highest priority (as the Intel
  2106.  
  2107. ; chip does and clones should do).  This bug causes our interrupt
  2108.  
  2109. ; routine to be reentered if: 1. we reenable processor interrupts;
  2110.  
  2111. ; 2. we reenable device interrupts; 3. a timer or other higher priority
  2112.  
  2113. ; device interrupt now comes in; 4. the new interrupting device uses
  2114.  
  2115. ; a Non Specific EOI; 5. our device interrupts again.  Because of
  2116.  
  2117. ; this bug, we now completely mask our interrupts around the call
  2118.  
  2119. ; to "recv", the real device interrupt handler.  This allows us
  2120.  
  2121. ; to send an EOI instruction to the 8259 early, before we actually
  2122.  
  2123. ; reenable device interrupts.  Since the interrupt is masked, we
  2124.  
  2125. ; are still guaranteed not to get another interrupt from our device
  2126.  
  2127. ; until the interrupt handler returns.  This has another benefit:
  2128.  
  2129. ; we now no longer prevent other devices from interrupting while our
  2130.  
  2131. ; interrupt handler is running.  This is especially useful if we have
  2132.  
  2133. ; other (multiple) packet drivers trying to do low-latency transmits.
  2134.  
  2135.     mov    al,int_no    ; Disable further device interrupts
  2136.  
  2137.     call    maskint
  2138.  
  2139.  
  2140.  
  2141. ; The following is from Bill Rust, <wjr@ftp.com>
  2142.  
  2143. ; this code dismisses the interrupt at the 8259. if the interrupt number
  2144.  
  2145. ;  is > 8 then it requires fondling two PICs instead of just one.
  2146.  
  2147.     mov    al, int_no    ; get hardware int #
  2148.  
  2149.     or    al,al        ; if it's zero, then there is no IRQ to ack.
  2150.  
  2151.     je    recv_isr_3    ; so skip the EOI processing.
  2152.  
  2153.     cmp    al, 8        ; see if its on secondary PIC
  2154.  
  2155.     jg    recv_isr_4
  2156.  
  2157.     add    al, 60h        ; make specific EOI dismissal
  2158.  
  2159.     out    20h, al
  2160.  
  2161.     jmp    short recv_isr_3    ; all done
  2162.  
  2163. recv_isr_4:
  2164.  
  2165.     add    al,60h - 8    ; make specific EOI (# between 9 & 15).
  2166.  
  2167.     out    0a0h,al        ; Secondary 8259 (PC/AT only)
  2168.  
  2169.     mov    al,62h        ; Acknowledge on primary 8259.
  2170.  
  2171.     out    20h,al
  2172.  
  2173. recv_isr_3:
  2174.  
  2175.  
  2176.  
  2177. ;    sti                ; Interrupts are now completely safe
  2178.  
  2179.     call    recv
  2180.  
  2181.  
  2182.  
  2183.     cli                ;interrupts *must* be off between
  2184.  
  2185.                     ;here and the stack restore, because
  2186.  
  2187.                     ;if we have one of our interrupts
  2188.  
  2189.                     ;pending, we would trash our stack.
  2190.  
  2191.  
  2192.  
  2193.     mov    al,int_no    ; Now reenable device interrupts
  2194.  
  2195.     call    unmaskint
  2196.  
  2197.  
  2198.  
  2199.     pop    es
  2200.  
  2201.     pop    bp
  2202.  
  2203.     pop    di
  2204.  
  2205.     pop    si
  2206.  
  2207.     pop    cx
  2208.  
  2209.     pop    bx
  2210.  
  2211.  
  2212.  
  2213.     mov    ss,savess
  2214.  
  2215.     mov    sp,savesp
  2216.  
  2217.  
  2218.  
  2219.     pop    ds
  2220.  
  2221.     assume    ds:nothing
  2222.  
  2223.     pop    dx
  2224.  
  2225.     pop    ax
  2226.  
  2227.     mov    in_recv_isr, 0    ; clear the re-entrancy flag - gft - 901617
  2228.  
  2229. recv_iret:
  2230.  
  2231.     iret
  2232.  
  2233.  
  2234.  
  2235. recv_exiting_flag    db    0    ;nonzero if recv_exiting will be run.
  2236.  
  2237. recv_exiting_addr    dd    ?
  2238.  
  2239.  
  2240.  
  2241.     public    schedule_exiting
  2242.  
  2243. schedule_exiting:
  2244.  
  2245. ;call this routine to schedule a subroutine that gets run after the
  2246.  
  2247. ;recv_isr.  This is done by stuffing routine's address in place
  2248.  
  2249. ;of the recv_isr iret's address.  This routine should push the flags when it
  2250.  
  2251. ;is entered, and should jump to recv_exiting_exit to leave.
  2252.  
  2253. ;enter with ax = address of routine to run.
  2254.  
  2255.     cmp    recv_exiting_flag,0    ;is it already scheduled?
  2256.  
  2257.     jne    schedule_exiting_1    ;yes, don't do it again!
  2258.  
  2259.     inc    recv_exiting_flag    ;set the flag.
  2260.  
  2261.     les    di,savespss        ;make es:di -> their stack.
  2262.  
  2263.     xchg    ax,es:[di].recv_isr_ip    ;stuff our routine's address in,
  2264.  
  2265.     mov    recv_exiting_addr.offs,ax    ;and save the original address.
  2266.  
  2267.     mov    ax,cs
  2268.  
  2269.     xchg    ax,es:[di].recv_isr_cs
  2270.  
  2271.     mov    recv_exiting_addr.segm,ax
  2272.  
  2273. schedule_exiting_1:
  2274.  
  2275.     ret
  2276.  
  2277.  
  2278.  
  2279.     public    recv_exiting_exit
  2280.  
  2281. recv_exiting_exit:
  2282.  
  2283. ;recv_exiting jumps here to exit, after pushing the flags.
  2284.  
  2285.     cli                ;protect the following semaphore.
  2286.  
  2287.     mov    recv_exiting_flag,0
  2288.  
  2289.     push    recv_exiting_addr.segm
  2290.  
  2291.     push    recv_exiting_addr.offs
  2292.  
  2293.     iret
  2294.  
  2295.  
  2296.  
  2297.  
  2298.  
  2299.     public    maskint
  2300.  
  2301. maskint:
  2302.  
  2303.     or    al,al            ;are they using a hardware interrupt?
  2304.  
  2305.     je    maskint_1        ;no, don't mask off the timer!
  2306.  
  2307.  
  2308.  
  2309.     assume    ds:code
  2310.  
  2311.     mov    dx,21h            ;assume the master 8259.
  2312.  
  2313.     cmp    al,8            ;using the slave 8259 on an AT?
  2314.  
  2315.     jb    mask_not_irq2
  2316.  
  2317.     mov    dx,0a1h            ;go disable it on slave 8259
  2318.  
  2319.     sub    al,8
  2320.  
  2321. mask_not_irq2:
  2322.  
  2323.     mov    cl,al
  2324.  
  2325.  
  2326.  
  2327.     in    al,dx            ;disable them on the correct 8259.
  2328.  
  2329.     mov    ah,1            ;set the bit.
  2330.  
  2331.     shl    ah,cl
  2332.  
  2333.     or    al,ah
  2334.  
  2335. ;
  2336.  
  2337. ; 500ns Stall required here, per INTEL documentation for eisa machines
  2338.  
  2339. ; - gft - 910617
  2340.  
  2341. ;
  2342.  
  2343.     push    ax
  2344.  
  2345.     in    al,61h    ; 1.5 - 3 uS should be plenty
  2346.  
  2347.     in    al,61h
  2348.  
  2349.     in    al,61h
  2350.  
  2351.     pop    ax
  2352.  
  2353.     out    dx,al
  2354.  
  2355. maskint_1:
  2356.  
  2357.     ret
  2358.  
  2359.  
  2360.  
  2361.  
  2362.  
  2363.     public    unmaskint
  2364.  
  2365. unmaskint:
  2366.  
  2367. ;exit with cl = 0 if the interrupt had been enabled.
  2368.  
  2369.     assume    ds:code
  2370.  
  2371.     mov    dx,21h            ;assume the master 8259.
  2372.  
  2373.     mov    cl,al
  2374.  
  2375.     cmp    cl,8            ;using the slave 8259 on an AT?
  2376.  
  2377.     jb    unmask_not_irq2        ;no
  2378.  
  2379.     in    al,dx            ;get master mask
  2380.  
  2381.     push    ax
  2382.  
  2383.     in    al,61h            ;wait lots of time.
  2384.  
  2385.     in    al,61h
  2386.  
  2387.     in    al,61h
  2388.  
  2389.     pop    ax
  2390.  
  2391.     and    al,not (1 shl 2)    ; and clear slave cascade bit in mask
  2392.  
  2393.     out    dx,al            ;set new master mask (enable slave int)
  2394.  
  2395. ;
  2396.  
  2397. ; 500ns Stall required here, per INTEL documentation for eisa machines
  2398.  
  2399. ; - gft - 910617
  2400.  
  2401. ;
  2402.  
  2403.     push    ax
  2404.  
  2405.     in    al,61h    ; 1.5 - 3 uS should be plenty
  2406.  
  2407.     in    al,61h
  2408.  
  2409.     in    al,61h
  2410.  
  2411.     pop    ax
  2412.  
  2413.     mov    dx,0a1h            ;go enable int on slave 8259
  2414.  
  2415.     sub    cl,8
  2416.  
  2417. unmask_not_irq2:
  2418.  
  2419.  
  2420.  
  2421.     in    al,dx            ;enable interrupts on the correct 8259.
  2422.  
  2423.     mov    ah,1            ;clear the bit.
  2424.  
  2425.     shl    ah,cl
  2426.  
  2427.     mov    cl,al            ;remember the original mask.
  2428.  
  2429.     and    cl,ah
  2430.  
  2431.     not    ah
  2432.  
  2433.     and    al,ah
  2434.  
  2435. ;
  2436.  
  2437. ; 500ns Stall required here, per INTEL documentation for eisa machines
  2438.  
  2439. ; - gft - 910617
  2440.  
  2441. ;
  2442.  
  2443.     push    ax
  2444.  
  2445.     in    al,61h    ; 1.5 - 3 uS should be plenty
  2446.  
  2447.     in    al,61h
  2448.  
  2449.     in    al,61h
  2450.  
  2451.     pop    ax
  2452.  
  2453.     out    dx,al
  2454.  
  2455.  
  2456.  
  2457.     ret
  2458.  
  2459.  
  2460.  
  2461.  
  2462.  
  2463.     public    recv_locate
  2464.  
  2465. recv_locate:
  2466.  
  2467. ;called when we want to determine what to do with a received packet.
  2468.  
  2469. ;enter with es:di -> packet type, dl = packet class.
  2470.  
  2471. ;exit with cy if the packet is not desired, or nc if we know its type.
  2472.  
  2473.     assume    ds:code, es:nothing
  2474.  
  2475.  
  2476.  
  2477. ; If -n option take IEEE 802.3 encapsulated packets that could be Novell IPX 
  2478.  
  2479. ; and make them Ethernet encapsulated Novell IPX packets (for PDSHELL).
  2480.  
  2481.     test    flagbyte,N_OPTION
  2482.  
  2483.     jz    not_n_op
  2484.  
  2485.  
  2486.  
  2487. ; Make IEEE 802.3-like packets that could be Novell IPX into BlueBook class
  2488.  
  2489. ; Novell type 8137 packets.
  2490.  
  2491.     cmp    dl,IEEE8023        ;Is this an IEEE 802.3 packet?
  2492.  
  2493.     jne    recv_not_802_3        ;no
  2494.  
  2495.     cmp    word ptr es:[di],0ffffh    ;if this word not ffff
  2496.  
  2497.     jne    recv_not_8137        ;  then not Novell
  2498.  
  2499.     sub    di,2            ; back it up to the 8137 word.
  2500.  
  2501.     mov    es:[di],3781h        ; fake as Novell protocol (8137)
  2502.  
  2503.     mov    dl,BLUEBOOK
  2504.  
  2505.     jmp    short recv_not_8137
  2506.  
  2507. recv_not_802_3:
  2508.  
  2509. ; Convert incoming Ethernet type 8137 IPX packets to type 8138, as with -n in 
  2510.  
  2511. ; effect we can't send type 8137, and it will only confuse Netware.
  2512.  
  2513.     cmp    dl,BLUEBOOK        ;Is this a BLUEBOOK packet?
  2514.  
  2515.     jne    recv_not_8137        ;no, don't change it.
  2516.  
  2517.     cmp    word ptr es:[di],3781h    ;Is it an 8137 packet?
  2518.  
  2519.     jne    recv_not_8137        ;no, don't change it.
  2520.  
  2521.     mov    es:[di],word ptr 3881h    ;yes, mung it slightly.
  2522.  
  2523. recv_not_8137:
  2524.  
  2525. not_n_op:
  2526.  
  2527.  
  2528.  
  2529.     mov    bx,offset handles
  2530.  
  2531. recv_find_1:
  2532.  
  2533.     cmp    [bx].in_use,0        ;is this handle in use?
  2534.  
  2535.     je    recv_find_2        ;no - don't check the type.
  2536.  
  2537.  
  2538.  
  2539.     mov    ax,[bx].receiver.offs    ;do they have a receiver?
  2540.  
  2541.     or    ax,[bx].receiver.segm
  2542.  
  2543.     je    recv_find_2        ;no - they're not serious about it.
  2544.  
  2545.  
  2546.  
  2547. ;per request by the UK people, we match on IEEE 802.3 classes, then types.
  2548.  
  2549. ;for all others, we match on type, then class.  This lets their software work
  2550.  
  2551. ;without breaking BLUEBOOK type length=0 clients.
  2552.  
  2553.     cmp    [bx].class,IEEE8023    ;is this an IEEE 802.3 handle
  2554.  
  2555.     jne    recv_find_7        ;no.
  2556.  
  2557.     cmp    dl,IEEE8023        ;is the packet also IEEE 802.3?
  2558.  
  2559.     jne    recv_find_2        ;no, give up on it now.
  2560.  
  2561. recv_find_7:
  2562.  
  2563.  
  2564.  
  2565.     mov    cx,[bx].packet_type_len    ;compare the packets.
  2566.  
  2567.     lea    si,[bx].packet_type
  2568.  
  2569.     jcxz    recv_find_3        ;if cx is zero, they want them all.
  2570.  
  2571.  
  2572.  
  2573.     cmp    [bx].class, dl        ;is this the right class?
  2574.  
  2575.     jne    recv_find_2        ;no- don't bother
  2576.  
  2577.  
  2578.  
  2579.     push    di
  2580.  
  2581.     repe    cmpsb
  2582.  
  2583.     pop    di
  2584.  
  2585.     je    recv_find_3        ;we've got it!
  2586.  
  2587. recv_find_2:
  2588.  
  2589.     add    bx,(size per_handle)    ;go to the next handle.
  2590.  
  2591.     cmp    bx,offset end_handles
  2592.  
  2593.     jb    recv_find_1
  2594.  
  2595.  
  2596.  
  2597.     add2    packets_dropped,1    ;count it as dropped.
  2598.  
  2599.     stc
  2600.  
  2601.     ret
  2602.  
  2603. recv_find_3:
  2604.  
  2605.     mov    found_handle,bx        ;remember what our handle was.
  2606.  
  2607.     clc
  2608.  
  2609.     ret
  2610.  
  2611.  
  2612.  
  2613.  
  2614.  
  2615.     public    recv_find, recv_found
  2616.  
  2617. recv_find:
  2618.  
  2619. ;called when we want to determine what to do with a received packet.
  2620.  
  2621. ;enter with cx = packet length, es:di -> packet type, dl = packet class.
  2622.  
  2623. ;exit with es:di = 0 if the packet is not desired, or es:di -> packet buffer
  2624.  
  2625. ;  to be filled by the driver.
  2626.  
  2627.     assume    ds:code, es:nothing
  2628.  
  2629.     push    cx            ;preserve packet length.
  2630.  
  2631.     call    recv_locate        ;search for the packet type.
  2632.  
  2633.     pop    cx
  2634.  
  2635.     jc    recv_find_5        ;we didn't find it -- discard it.
  2636.  
  2637. ;
  2638.  
  2639. recv_found:
  2640.  
  2641. ;called to do the first upcall.
  2642.  
  2643. ;exit with es:di = 0 if the packet is not desired, or es:di -> packet buffer
  2644.  
  2645. ;  to be filled by the driver.
  2646.  
  2647.  
  2648.  
  2649.     add2    packets_in,1
  2650.  
  2651.     add2    bytes_in,cx        ;add up the received bytes.
  2652.  
  2653.  
  2654.  
  2655.     mov    bx,found_handle
  2656.  
  2657.     les    di,[bx].receiver    ;remember the receiver upcall.
  2658.  
  2659.     mov    receive_ptr.offs,di
  2660.  
  2661.     mov    receive_ptr.segm,es
  2662.  
  2663.  
  2664.  
  2665.     test    flagbyte,W_OPTION    ;did they select the Windows option?
  2666.  
  2667.     je    recv_find_6        ;no, don't check for the upcall.
  2668.  
  2669.  
  2670.  
  2671. ; does the receiver signature match whats currently in memory?  if not,
  2672.  
  2673. ; jump to fake return
  2674.  
  2675.     push    si
  2676.  
  2677.     push    cx
  2678.  
  2679.     lea    si,[bx].receiver_sig
  2680.  
  2681.     mov    cx,8/2
  2682.  
  2683.     repe    cmpsw
  2684.  
  2685.     pop    cx
  2686.  
  2687.     pop    si
  2688.  
  2689.     je    recv_find_6
  2690.  
  2691. recv_find_5:
  2692.  
  2693.     xor    di,di            ;"return" a null pointer.
  2694.  
  2695.     mov    es,di
  2696.  
  2697.     ret
  2698.  
  2699. recv_find_6:
  2700.  
  2701.  
  2702.  
  2703.     mov    ax,0            ;allocate request.
  2704.  
  2705.     stc                ;with stc, flags must be an odd number
  2706.  
  2707.     push    ax            ; save a number that cant be flags
  2708.  
  2709.     pushf                ;save flags in case iret used.
  2710.  
  2711.     call    receive_ptr        ;ask the client for a buffer.
  2712.  
  2713.     ; on return, flags should be at top of stack. if an IRET has been used,
  2714.  
  2715.     ; then 0 will be at the top of the stack
  2716.  
  2717.     pop    bx
  2718.  
  2719.     cmp    bx,0
  2720.  
  2721.     je    recv_find_4        ;0 is at top of stack
  2722.  
  2723.     add    sp,2
  2724.  
  2725. recv_find_4:
  2726.  
  2727.     ret
  2728.  
  2729.  
  2730.  
  2731.  
  2732.  
  2733.     public    recv_copy
  2734.  
  2735. recv_copy:
  2736.  
  2737. ;called after we have copied the packet into the buffer.
  2738.  
  2739. ;enter with ds:si ->the packet, cx = length of the packet.
  2740.  
  2741. ;preserve bx.
  2742.  
  2743.     assume    ds:nothing, es:nothing
  2744.  
  2745.  
  2746.  
  2747.     push    bx
  2748.  
  2749.     mov    bx,found_handle
  2750.  
  2751.     mov    ax,1            ;store request.
  2752.  
  2753.     clc                ;with clc, flags must be an even number
  2754.  
  2755.     push    ax            ; save a number that can't be flags
  2756.  
  2757.     pushf                ;save flags incase iret used.
  2758.  
  2759.     call    receive_ptr        ;ask the client for a buffer.
  2760.  
  2761.     pop    bx
  2762.  
  2763.     cmp    bx,1            ;if this is a 1, IRET was used.
  2764.  
  2765.     je    recv_copy_1
  2766.  
  2767.     pop    bx
  2768.  
  2769. recv_copy_1:
  2770.  
  2771.     pop    bx
  2772.  
  2773.     ret
  2774.  
  2775.  
  2776.  
  2777.     public    send_queue
  2778.  
  2779. send_queue:
  2780.  
  2781. ; Queue an iocb.
  2782.  
  2783. ; Enter with es:di -> iocb, interrupts disabled.
  2784.  
  2785. ; Destroys ds:si.
  2786.  
  2787.     assume    ds:nothing, es:nothing
  2788.  
  2789.     mov    es:[di].next.offs,0    ; Zero next offset
  2790.  
  2791.     mov    es:[di].next.segm,0    ; Zero next segment
  2792.  
  2793.     mov    si,send_head.offs    ; Queue empty?
  2794.  
  2795.     or    si,send_head.segm
  2796.  
  2797.     jnz    sq_notempty        ; No
  2798.  
  2799.     mov    send_head.offs,di    ; Set head offset
  2800.  
  2801.     mov    send_head.segm,es    ; Set head segment
  2802.  
  2803.     jmp    short sq_settail
  2804.  
  2805. sq_notempty:                ; Queue is not empty
  2806.  
  2807.     lds    si,send_tail        ; Get tail segment:offset
  2808.  
  2809.     mov    ds:[si].next.offs,di    ; Set next offset
  2810.  
  2811.     mov    ds:[si].next.segm,es    ; Set next segment
  2812.  
  2813. sq_settail:
  2814.  
  2815.     mov    send_tail.offs,di    ; Set tail offset
  2816.  
  2817.     mov    send_tail.segm,es    ; Set tail segment
  2818.  
  2819.     ret
  2820.  
  2821.  
  2822.  
  2823.  
  2824.  
  2825.     public    send_dequeue
  2826.  
  2827. send_dequeue:
  2828.  
  2829. ; Dequeue an iocb and possibly call its upcall.
  2830.  
  2831. ; Enter with device or processor interrupts disabled, ah = return code.
  2832.  
  2833. ; Exits with es:di -> iocb; destroys ds:si, ax, bx, cx, dx, bp.
  2834.  
  2835.     assume    ds:nothing, es:nothing
  2836.  
  2837.     les    di,send_head        ; Get head segment:offset
  2838.  
  2839.     lds    si,es:[di].next        ; Get next segment:offset
  2840.  
  2841.     mov    send_head.offs, si    ; Set head offset
  2842.  
  2843.     mov    send_head.segm, ds    ; Set head segment
  2844.  
  2845.     or    es:flags[di], DONE    ; Mark done
  2846.  
  2847.     mov    es:ret_code[di], ah    ; Set retcode
  2848.  
  2849.     test    es:[di].flags,CALLME    ; Does he want an upcall?
  2850.  
  2851.     je    send_dequeue_1        ; No.
  2852.  
  2853.     push    es            ; Push iocb segment
  2854.  
  2855.     push    di            ;  and offset
  2856.  
  2857.     clc                ; Clear carry.
  2858.  
  2859.     mov    ax,1            ; Push a number that cant be flags.
  2860.  
  2861.     push    ax
  2862.  
  2863.     pushf                ; Save flags in case iret used.
  2864.  
  2865.     call    es:[di].upcall        ; Call the client.
  2866.  
  2867.     pop    ax            ; Pop first word.
  2868.  
  2869.     cmp    ax,1            ; If this is a 1, IRET was used.
  2870.  
  2871.     je    send_dequeue_2        ; Far return used.
  2872.  
  2873.     add    sp,2            ; Pop flags.
  2874.  
  2875. send_dequeue_2:
  2876.  
  2877.     pop    di            ; Pop iocb segment
  2878.  
  2879.     pop    es            ;  and offset
  2880.  
  2881. send_dequeue_1:
  2882.  
  2883.     ret
  2884.  
  2885.  
  2886.  
  2887.  
  2888.  
  2889. code    ends
  2890.  
  2891.  
  2892.  
  2893.     end    start
  2894.  
  2895.