home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / archives / packetdrivers.tar.gz / pd.tar / src / pi.asm < prev    next >
Assembly Source File  |  1995-06-25  |  35KB  |  1,507 lines

  1. ;   PC/FTP Packet Driver source, conforming to version 1.09 of the spec,
  2. ;   for the Ottawa PI card.
  3. ;   Dave Perry, VE3IFB, October 16, 1991
  4. ;   Portions (C) Copyright 1991, 1992 David G Perry
  5. ;   Copyright, 1988, 1989, 1990, 1991 Russell Nelson
  6.  
  7. ;   This program is free software; you can redistribute it and/or modify
  8. ;   it under the terms of the GNU General Public License as published by
  9. ;   the Free Software Foundation, version 1.
  10. ;
  11. ;   This program is distributed in the hope that it will be useful,
  12. ;   but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. ;   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. ;   GNU General Public License for more details.
  15. ;
  16. ;   You should have received a copy of the GNU General Public License
  17. ;   along with this program; if not, write to the Free Software
  18. ;   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  
  20. ; Change history:
  21. ; October 16, 1991 (dp) - Creation
  22. ; January 8, 1992 (dp) - Fixed bug in set_acc_delay (rewritten).
  23. ;    - Improved high speed performance by decreasing the amount
  24. ;      of time DMA is disabled in scc routines.
  25. ;    - Added new options to command line to allow more clocking
  26. ;      options (see documentation file).
  27. ;    - Added transmit buffer queue.
  28. ;    - Added command line option to specify number and size of
  29. ;      DMA buffers.
  30. ;    - Optional support for "pseudo" ethernet class
  31. ;    - Fixed bug in internal clocking mode
  32.  
  33.     include 8530inc.asm
  34.     include piinc.asm
  35.  
  36. ETHER    equ    1    ; This driver will "pretend" the PI card is an ethernet
  37.             ; card. I have used this method to run QVT/NET
  38.             ; using back-to-back PI cards between
  39.             ; two PCs. Do not use this feature on a radio link,
  40.             ; as no call signs would be transmitted.
  41.             ; To use it, reassemble with MYCLASS equ ETHER
  42.             ; and etheraddr = desired ethernet address
  43.  
  44. AX25    equ    9    ; Driver class
  45. MYCLASS    equ    AX25
  46.  
  47. PITYPE    equ    1    ; Driver type
  48.  
  49. ; transmitter states
  50. IDLE        equ    0 ; Transmitter off
  51. TXDELAY        equ    1 ; Sending leading flags
  52. ACTIVE        equ    2 ; Transmitter on, sending data
  53. UNDERRUN    equ    3 ; Transmitter on, flushing CRC
  54. FLAGOUT        equ    4 ; CRC sent - attempt to start next frame
  55. DEFER        equ    5 ; DCD Active - DEFER Transmit
  56. CRCOUT        equ    6 ; Waiting for CRC bytes to clear the fifo
  57.  
  58. DEFAULTBUFSIZE    equ    2048
  59.  
  60. version    equ    2
  61.  
  62.     include    defs.asm
  63.  
  64. code    segment    word public
  65.     assume    cs:code, ds:code
  66.  
  67. etheraddr    db    00h,00h,00h,00h,00h,00h
  68.  
  69. tstate    db    0
  70.  
  71. ; Short pointers to DMA buffers.
  72. rxbufptr    dw    0 ; Current rx buffer
  73. altbufptr    dw    0 ; Alternate receive buffer
  74. bufptr1        dw    0 ; DMA approved buffer
  75. bufptr2        dw    0 ; DMA approved buffer
  76. txbufptr    dw    0 ; Current tx buffer
  77. freelist    dw    0 ; Head of free list
  78. txqueue        dw    0 ; Head of transmit queue
  79.  
  80. txlength    dw    0 ; Save area for length of incoming packet
  81.  
  82.     public    acc_delay
  83. acc_delay dw    0,0
  84. diff        dw    0,0
  85. tick1        dw    0,0
  86. tick2        dw    0,0
  87. tx_tc    dw    0,0 ; Time constant for baud rate generator (transmit)
  88. rx_tc    dw    0,0 ; Time constant for baud rate generator (receive)
  89. random        db    0        ; Pseudo random number
  90.  
  91. ; The following values may be overridden from the command line.
  92. ; If they are omitted from the command line, these defaults are used.
  93. ; All of them occupy 4 bytes to satisfy the call to get_number.
  94.     public    int_no, io_addr, dma_channel
  95. int_no        db    7,0,0,0        ; HW Interrupt
  96. io_addr        dw    0380h,0        ; I/O address for card (jumpers)
  97. dma_channel    db    1,0,0,0     ; DMA channel for card (jumpers)
  98. speed        dw    0,0        ; Baud rate (0 for external clock)
  99. txdelayparm    dw    15,0        ; TX delay (length of flags before data)
  100. persist        dw    128,0        ; P - persistance probability out of 256
  101. slottime    dw    10,0        ; Slot time for backoff
  102. tailtime    dw    1,0        ; Depends on baud rate
  103. clkmode        dw    0,0        ; Clocking mode
  104. bufsiz        dw    DEFAULTBUFSIZE,0; Buffer size
  105. numbufs        dw    5,0        ; Number of buffers
  106.  
  107. ; The following 3 values are calculated at initialization and depend
  108. ; on which DMA channel has been selected
  109. page_addr    dw    83h        ; To be calculated from dma channel
  110. dma_dest    dw    2        ; Defaults are for channel 1
  111. dma_wcr        dw    3
  112.  
  113.     public    driver_class, driver_type, driver_name, driver_function, parameter_list
  114. driver_class    db    MYCLASS,0    ; null terminated list of classes.(ax25)
  115. driver_type    db    PITYPE        ;Assigned by FTP Software Inc.
  116. driver_name    db    'pi',0        ;name of the driver.
  117. driver_function    db    1        ;Only basic functionality
  118. parameter_list    label    byte
  119.     db    1    ;major rev of packet driver
  120.     db    9    ;minor rev of packet driver
  121.     db    14    ;length of parameter list
  122.     db    0    ;length of MAC-layer address
  123. parm_mtu    label    word
  124.     dw    DEFAULTBUFSIZE    ; MTU, including MAC headers
  125.     dw    MAX_MULTICAST * EADDR_LEN    ;buffer size of multicast addrs
  126.     dw    0    ;(# of back-to-back MTU rcvs) - 1
  127.     dw    0    ;(# of successive xmits) - 1
  128. int_num    dw    0    ;Interrupt # to hook for post-EOI
  129.             ;processing, 0 == none,
  130.  
  131.     public    rcv_modes
  132. rcv_modes    dw    4        ;number of receive modes in our table.
  133.         dw    0,0,0,rcv_mode_3
  134.  
  135. ; Switch receive buffers so we can quickly set up DMA again
  136.     public    switchbuffers
  137. switchbuffers:
  138.     mov    ax,rxbufptr
  139.     cmp    ax,bufptr1
  140.     jnz    sw_1
  141.     mov    ax,bufptr2
  142.     mov    rxbufptr,ax
  143.     mov    ax,bufptr1
  144.     mov    altbufptr,ax
  145.     ret
  146. sw_1:
  147.     mov    ax,bufptr1
  148.     mov    rxbufptr,ax
  149.     mov    ax,bufptr2
  150.     mov    altbufptr,ax
  151.     ret
  152.  
  153.     public bad_command_intercept
  154. bad_command_intercept:
  155. ;called with ah=command, unknown to the skeleton.
  156. ;exit with nc if okay, cy, dh=error if not.
  157.     mov    dh,BAD_COMMAND
  158.     stc
  159.     ret
  160.  
  161.     public    as_send_pkt
  162. ; The Asynchronous Transmit Packet routine.
  163. ; Enter with es:di -> i/o control block, ds:si -> packet, cx = packet length,
  164. ;   interrupts possibly enabled.
  165. ; Exit with nc if ok, or else cy if error, dh set to error number.
  166. ;   es:di and interrupt enable flag preserved on exit.
  167. as_send_pkt:
  168.     ret
  169.  
  170.     public    drop_pkt
  171. ; Drop a packet from the queue.
  172. ; Enter with es:di -> iocb.
  173. drop_pkt:
  174.     assume    ds:nothing
  175.     ret
  176.  
  177.     public    xmit
  178. ; Process a transmit interrupt with the least possible latency to achieve
  179. ;   back-to-back packet transmissions.
  180. ; May only use ax and dx.
  181. xmit:
  182.     assume    ds:nothing
  183.     ret
  184.  
  185. ; Append buffer pointed to by ax to queue specified by bx
  186.     public    enqueue
  187. enqueue:
  188.     pushf
  189.     cli
  190.     push    si
  191.     push    bp
  192.  
  193.     mov    si,cs:bufsiz
  194.     mov    bp,ax
  195.     mov    word ptr cs:[bp+si],0    ; Make sure next pointer is null
  196.  
  197.     cmp    word ptr cs:[bx],0    ; Is list empty?
  198.     jne    en1            ; No - find the end
  199.     mov    cs:[bx],ax        ; Yes - add it
  200.  
  201.     pop    bp
  202.     pop    si
  203.     popf
  204.     ret
  205.  
  206. en1:    mov    bp,word ptr cs:[bx] ; get pointer to first element
  207. en2:
  208.     cmp    word ptr cs:[bp+si],0    ; Is next pointer null?
  209.     je    en3        ; Yes, append our buffer
  210.     mov    bp,cs:[bp+si]    ; No - advance to next element
  211.     jmp    en2    
  212. en3:    mov    cs:[bp+si],ax
  213.  
  214.     pop    bp
  215.     pop    si
  216.     popf
  217.     ret
  218.  
  219.     public    dequeue
  220. dequeue:
  221.     pushf
  222.     cli
  223.     push    si
  224.     mov    si,cs:bufsiz
  225.     cmp    word ptr cs:[bx],0    ; Is list empty?
  226.     jne    deq1
  227.     xor    ax,ax        ; Yes, return error
  228.     pop    si
  229.     popf
  230.     stc
  231.     ret
  232. deq1:
  233.     push    bp
  234.     mov    bp,cs:[bx]        ; No, dequeue buffer
  235.     mov    ax,cs:[bp+si]
  236.     mov    cs:[bx],ax
  237.     mov    ax,bp
  238.  
  239.     pop    bp
  240.     pop    si
  241.     popf
  242.     clc
  243.     ret
  244.  
  245. ; Check to see if we should transmit or DEFER
  246. ; Return: Carry set - DEFER
  247.     public check_dcd
  248. check_dcd:
  249. ; Check DCD - see if we should DEFER transmission
  250.     cmp    tstate,FLAGOUT
  251.     je    go        ; The transmitter is already on - don't defer
  252.     mov    bx,R0+RES_EXT_INT
  253.     call    wrtscc
  254.     mov    bx,R0+RES_EXT_INT
  255.     call    wrtscc
  256.     mov    bx,R0
  257.     call    rdscc
  258.     test    al,DCD
  259.     jne    check_dcd_1    ; Carrier detected - we have to DEFER
  260.  
  261.  
  262.     mov    al,21        ; Generate pseudo random number
  263.     mul    cs:random
  264.     add    ax,53
  265.     mov    cs:random,al    ; Save it for next one in sequence
  266.  
  267.     xor    ah,ah
  268.     cmp    ax,cs:persist    ; Should we DEFER?
  269.     jle    go        ; No
  270.     mov    cs:tstate,DEFER    ; We have to wait
  271.     mov    ax,cs:slottime    ; Yes - DEFER 1 slot time
  272.     call    tdelay
  273.     stc            ; We are DEFERring
  274.     ret
  275.  
  276. go:    clc            ; We don't have to wait
  277.     ret
  278.  
  279. check_dcd_1:
  280.     mov    cs:tstate,DEFER    ; We have to wait
  281.     mov    ax,1000        ; In case DCD int. missed (shouldn't happen)
  282.     call    tdelay
  283. ; Defer until dcd transition or 1S timeout or abort
  284.     mov    bx,R15+CTSIE+DCDIE+BRKIE
  285.     call    wrtscc
  286.     stc            ; We are DEFERring
  287.     ret
  288.  
  289.     public    send_pkt
  290. send_pkt:
  291. ;enter with es:di->upcall routine, (0:0) if no upcall is desired.
  292. ;  (only if the high-performance bit is set in driver_function)
  293. ;enter with ds:si -> packet, cx = packet length.
  294. ;if we're a high-performance driver, es:di -> upcall.
  295. ;exit with nc if ok, or else cy if error, dh set to error number.
  296.     assume    ds:nothing
  297. ; Copy packet into local DMA approved buffer
  298. ; Enqueue it for transmission. If the queue is full, return error.
  299. ; If the transmitter is not active and the channel is free, start
  300. ; transmission, else defer. Return as soon as buffer can be released.
  301.     
  302.     pushf
  303.     cli
  304.  
  305.     mov    ax,cs        ;  Point es at the code segment
  306.     mov    es,ax
  307.  
  308.     mov    bx,offset freelist    ; Get a buffer from the freelist
  309.     call    dequeue
  310.     jc    send_error    ; None left
  311.  
  312.     mov    di,ax        ; Use newly aquired DMA buffer
  313.     push    bp
  314.     push    si
  315.     mov    bp,ax
  316.     mov    si,cs:bufsiz
  317.     mov    cs:[bp+si+2],cx    ; Tack on length
  318.     pop    si
  319.     pop    bp    
  320.     
  321.     cld
  322.     rep    movsb        ; Copy packet
  323.  
  324.     mov    bx,offset txqueue    ; Append it to the tx queue
  325.     call    enqueue
  326.  
  327.     mov    al,cs:tstate    ; Is transmitter idle?
  328.     cmp    al,IDLE
  329.     je    send_pkt_1    ; Yes - start transmitting
  330.     popf            ; Else return without error
  331.     clc
  332.     ret    
  333.  
  334. send_error:
  335.     popf
  336.     stc            ; Return error
  337.     ret
  338.     
  339. send_pkt_1:
  340.     cli
  341.  
  342.     mov    bx,offset txqueue; Get a buffer from the txqueue
  343.     call    dequeue
  344.     jc    none_to_send    ; None left
  345.     mov    cs:txbufptr,ax    ; Make it the active tx buffer
  346.  
  347.     push    bp
  348.     push    si
  349.     mov    bp,ax
  350.     mov    si,cs:bufsiz
  351.     mov    cx,cs:[bp+si+2]    ; Get length
  352.     pop    si
  353.     pop    bp    
  354.  
  355.     mov    cs:txlength,cx
  356.  
  357. ; Check DCD - see if we should DEFER transmission
  358.     call    check_dcd
  359.     jc    send_pkt_exit    ; DEFER
  360.     mov    ax,cs        ; Set up for TX DMA
  361.     mov    cx,ax
  362.     mov    bx,cs:txbufptr
  363.     mov    ax,cs:txlength
  364.     call    setup_tx_dma
  365.  
  366.     mov    cs:tstate,TXDELAY
  367.     call    tx_on    ; Start sending flags
  368.     mov    ax,cs:txdelayparm    ; generate an exint after TXDELAY
  369.     call    tdelay
  370.  
  371. send_pkt_exit:
  372.     popf
  373.     clc    ;  No error
  374.     ret
  375.  
  376. none_to_send:
  377.     call    tx_off
  378.     mov    cs:tstate,IDLE
  379.     popf
  380.     clc    ;  No error
  381.     ret
  382.  
  383.     public    set_address
  384. set_address:
  385. ;enter with ds:si -> Ethernet address, CX = length of address.
  386. ;exit with nc if okay, or cy, dh=error if any errors.
  387.     assume    ds:nothing
  388.     ret
  389.  
  390.  
  391. rcv_mode_3:
  392. ;receive mode 3 is the only one we support, so we don't have to do anything.
  393.     ret
  394.  
  395.  
  396.     public    set_multicast_list
  397. set_multicast_list:
  398. ;enter with ds:si ->list of multicast addresses, cx = number of addresses.
  399. ;return nc if we set all of them, or cy,dh=error if we didn't.
  400.     mov    dh,NO_MULTICAST
  401.     stc
  402.     ret
  403.  
  404.  
  405.     public    terminate
  406. terminate:
  407.     ret
  408.  
  409.     public    reset_interface
  410. reset_interface:
  411. ;reset the interface.
  412.     assume    ds:code
  413.     ret
  414.  
  415.  
  416. ;called when we want to determine what to do with a received packet.
  417. ;enter with cx = packet length, es:di -> packet type, dl = packet class.
  418.     extrn    recv_find: near
  419.  
  420. ;called after we have copied the packet into the buffer.
  421. ;enter with ds:si ->the packet, cx = length of the packet.
  422.     extrn    recv_copy: near
  423.  
  424. ;call this routine to schedule a subroutine that gets run after the
  425. ;recv_isr.  This is done by stuffing routine's address in place
  426. ;of the recv_isr iret's address.  This routine should push the flags when it
  427. ;is entered, and should jump to recv_exiting_exit to leave.
  428. ;enter with ax = address of routine to run.
  429.     extrn    schedule_exiting: near
  430.  
  431. ;recv_exiting jumps here to exit, after pushing the flags.
  432.     extrn    recv_exiting_exit: near
  433.  
  434. ;enter with dx = amount of memory desired.
  435. ;exit with nc, dx -> that memory, or cy if there isn't enough memory.
  436.     extrn    malloc: near
  437.  
  438.     extrn    count_in_err: near
  439.     extrn    count_out_err: near
  440.  
  441. wcrsave    dw    0
  442. rsesave    db    0
  443.  
  444.     public rxint
  445. rxint:
  446.     assume    ds:code
  447.  
  448.     mov    bx,R1 ; Get special condition bits from R1
  449.     call    rdscc
  450.     mov    rsesave,al
  451.  
  452. ; save length of frame from 8237 */
  453.     xor    al,al
  454.     out    DMA_RESETFF,al    ; Reset byte pointer flipflop
  455.     mov    dx,dma_wcr    ; Get address of word count register
  456.     in    al,dx        ; Input low byte of word
  457.     mov    bl,al        ; Save it
  458.     in    al,dx        ; Input high byte
  459.     mov    bh,al        ; Save it - bx = bytes left
  460.     mov    wcrsave,bx
  461.     call    switchbuffers    ; Switch buffers so we can get DMA happening
  462. ; Error reset lets the receive fifo empty out using dma. There can be a few
  463. ; garbage bytes left in there so it is important to 'drain' them by
  464. ; issuing the error reset *before* we set up DMA for the next receive.
  465.     mov    bx,R0+ERR_RES    ; Error reset
  466.     call    wrtscc
  467.  
  468.     mov    ax,cs        ; Setup for next receive
  469.     mov    cx,ax
  470.     mov    bx,rxbufptr
  471.     mov    ax,cs:bufsiz
  472.     call    setup_rx_dma
  473.  
  474.     mov    al,rsesave    ; Recover status
  475.     test    al,END_FR    ; Is this an end of packet int?
  476.     jz    rxint_exit    ; no
  477.     test    al,CRC_ERR    ; CRC ok?
  478.     jnz    rxint_exit    ; No - toss frame
  479.  
  480.     mov    bx,wcrsave    ; Recover frame length
  481.     mov    ax,cs:bufsiz    ; ax = buf size - 1
  482.     sub    ax,1
  483.     sub    ax,bx        ; minus bytes left = byte count
  484.     cmp    ax,10        ; Runt?
  485.     jl    rxint_exit    ; Yes, ignore it
  486. ; Valid frame
  487.     sub    ax,2        ; Subtract 2 CRC bytes from byte count
  488.  
  489.     mov    cx,ax        ; Load packet length
  490.     mov    dl,MYCLASS    ; Load packet class
  491.  
  492.     mov    ax,cs        ; Get our segment
  493.     mov    es,ax        ; into es
  494.     mov    di,rxbufptr    ; Point to type field (not needed for AX25)
  495.     add    di,12
  496.  
  497.     call    recv_find    ; Try to get a buffer to send it up in.
  498.     mov ax,    es        ; Did recv_find give us a null pointer?
  499.     or ax,    di        ; ..
  500.     je    rxint_exit    ; If null, we must throw this one away
  501.     
  502.     cld            ; Copies which follow are forward
  503.  
  504.     push    ds        ; Save our data seg
  505.     push    cx        ; We will want the count and pointer
  506.     push    es        ;  to hand to client after copying,
  507.     push    di        ;  so save them at this point
  508.  
  509.     mov    si,altbufptr
  510.     rep    movsb        ; Do the copy
  511.  
  512.     pop    si        ; Recover pointer to destination
  513.     pop    ds        ; Tell client it's his source
  514.     pop    cx        ; And it's this long
  515.     call    recv_copy    ; Give it to him
  516.     pop    ds        ; Recover our data seg
  517.  
  518. rxint_exit:
  519.  
  520.     ret
  521.  
  522. txint:
  523.     assume    ds:code
  524.  
  525.     ret
  526.  
  527. exint:
  528.     assume    ds:code
  529.     pushf
  530.     cli
  531.  
  532.     mov    bx,R0    ; Get status
  533.     call    rdscc
  534.  
  535. ; reset external status latch
  536.     mov    bx,R0+RES_EXT_INT
  537.     call    wrtscc
  538.  
  539.     mov    al,cs:tstate    ; Is transmit IDLE?
  540.     cmp    al,IDLE    
  541.     jnz    exint_1        ; No
  542.  
  543.     mov    bx,R0+ERR_RES    ; TX IDLE - unlock fifo to flush any garbage
  544.     call    wrtscc
  545.     mov    ax,cs        ; Assume abort - Reset receive DMA
  546.     mov    cx,ax
  547.     mov    bx,rxbufptr
  548.     mov    ax,cs:bufsiz
  549.     call    setup_rx_dma
  550.     jmp    exint_exit    ; exit
  551.     
  552. exint_1:
  553.     mov    al,cs:tstate    
  554.     cmp    al,ACTIVE
  555.     jne    exint_2
  556.                 ; Transmitter is ACTIVE
  557.     mov    cs:tstate,FLAGOUT
  558.     mov    ax,tailtime
  559.     call    tdelay
  560.     jmp    exint_exit
  561. exint_2:
  562.     cmp    al,FLAGOUT
  563.     jne    exint_3
  564.                 ; Transmitter in FLAGOUT state
  565.     mov    ax,cs:txbufptr    ; Free the tx buffer
  566.     mov    bx, offset freelist
  567.     call enqueue
  568.     jmp    send_pkt_1    ; Go see if there are more to send
  569. exint_3:
  570.     cmp    al,TXDELAY
  571.     jne    exint_4
  572.                 ; Transmitter is in TXDELAY
  573.     mov    bx,R0+RES_Tx_CRC+RES_Tx_P ; reset CRC, txint pending
  574.     call    wrtscc
  575.     mov    bx,R15+TxUIE    ; Allow underrun int only
  576.     call    wrtscc
  577.                 ; Enable TX DMA
  578.     mov    bx,R1+WT_RDY_ENAB+WT_FN_RDYFN+EXT_INT_ENAB
  579.     call    wrtscc
  580.                 ; Unmask channel n (enable DMA controller chip)
  581.     mov    al,Byte Ptr dma_channel ; Enable DMA for this channel
  582.     add    al,DMA_ENABLE
  583.     out    DMA_MASK,al
  584.     
  585.     mov    bx,R0+RES_EOM_L ; Send CRC on underrun
  586.     call    wrtscc
  587.     mov    cs:tstate,ACTIVE    ; Packet going out now
  588.     jmp    exint_exit
  589.  
  590. exint_4:
  591.                 ; Transmitter must be in DEFER
  592.     call    check_dcd    ; See if we should DEFER again
  593.     jc    exint_exit    ; DEFER
  594.  
  595.     mov    ax,cs        ; Set up for TX DMA
  596.     mov    cx,ax
  597.     mov    bx,txbufptr
  598.     mov    ax,txlength
  599.     call    setup_tx_dma
  600.  
  601.     mov    cs:tstate,TXDELAY
  602.     call    tx_on        ; Start sending flags
  603.     mov    ax,txdelayparm    ; generate an exint after TXDELAY
  604.     call    tdelay
  605.     popf
  606.     ret
  607.  
  608. exint_exit:
  609.     popf
  610.     ret
  611.  
  612.     public    recv
  613. recv:
  614. ;called from the recv isr.  All registers have been saved, and ds=cs.
  615. ;Upon exit, the interrupt will be acknowledged.
  616.     assume    ds:code
  617. ; Read interrupt status register from channel A
  618. ; Process all pending interrupts in a loop
  619.  
  620. recv_1:
  621.  
  622.     mov    bx,R3
  623.     call    rdscc
  624.     cmp    al,0
  625.     jz    recv_exit
  626.     test    al,CHARxIP    ; Is channel A receive int pending?
  627.     jz    recv_2        ; no
  628.     call    rxint        ; yes
  629.     jmp    recv_eoi
  630. recv_2:    test    al,CHATxIP    ; Is channel A tx int pending?
  631.     jz    recv_3        ; no
  632.     call    txint        ; yes
  633.     jmp    recv_eoi
  634. recv_3:    test    al,CHAEXT    ; Is channel external/status int pending?
  635.     jz    recv_eoi    ; no
  636.     call    exint        ; yes
  637. ; Reset highest interrupt under service
  638. recv_eoi:
  639.     mov    bx,R0+RES_H_IUS
  640.     call    wrtscc
  641.     jmp    recv_1 ; Loop for more int processing
  642. recv_exit:    
  643.     ret
  644.  
  645. ; This routine is used for all writes to the SCC. It satisfies the
  646. ; The SCCs access time restriction by using delay loops. These loops
  647. ; are processor speed dependent and are determined by acc_delay.
  648.  
  649. ; Enter with bh = register, bl = value
  650.  
  651.     public    wrtscc
  652. wrtscc:
  653.     pushf        ; Save current interrupt state
  654.     cli        ; Wouldn't do to be interrupted now
  655.     push ax
  656.     push cx
  657.     push dx
  658.     push di
  659.     push si
  660.     push bp
  661.  
  662.     mov di,acc_delay; Load this into a register for speed
  663.  
  664.     mov dx,io_addr    ; Get card address
  665.     add dx,CTL_A    ; Point to channel A control reg
  666.     mov bp,dx    ; Save it
  667.  
  668.     mov dx,io_addr    ; get address of dma enable port
  669.     add dx,DMAEN
  670.     mov si,dx    ; save it
  671.  
  672.     mov cx,di    ; For loop below
  673.  
  674.     mov ax,100h    ; Write a 0 to disable DMA while we touch the scc
  675.     out dx,al
  676. ; ******** DMA off
  677.  
  678. Loop1: loop Loop1    ;[5]
  679.  
  680.     mov dx,bp    ;[2] Get pointer to ch A control reg
  681.     mov al,bh    ;[2] Select register
  682.     out dx,al    ;[8]
  683.  
  684.     mov cx,di    ;[2]
  685. Loop2:    loop Loop2    ;[5]
  686.  
  687.     mov dx,si    ;[2] get address of dma enable port
  688.     mov al,ah    ;[2] Enable DMA in between accesses
  689.     out dx,al    ;[8]
  690. ; ******** DMA on - was off for 36 cycles
  691.     nop        ; Leave extra time for XT ram refresh cycle to finish
  692.     nop
  693.     nop
  694.     mov cx,di    ; For loop below
  695.     mov al,0    ; now disable DMA in between accesses
  696.     out dx,al    ;
  697. ; ******** DMA off
  698.  
  699. Loop2a:    loop Loop2a    ;[5]
  700.  
  701.     mov dx,bp    ;[2] Get pointer to ch A control reg
  702.     mov al,bl    ;[2] Output value
  703.     out dx,al    ;[8]
  704.  
  705.     mov cx,di    ;[2]
  706. Loop3:    loop Loop3    ;[5]
  707.  
  708.     mov dx,si    ;[2] get address of dma enable port
  709.     mov al,ah    ;[2] Enable DMA
  710.     out dx,al    ;[8]
  711. ; ******** DMA on - was off for 36 cycles
  712.  
  713.     pop bp
  714.     pop si
  715.     pop di 
  716.     pop dx
  717.     pop cx
  718.     pop ax
  719.     popf
  720.     ret
  721.  
  722. ; Enter with bh = reg
  723.  
  724.     public    rdscc
  725. rdscc:
  726.     pushf
  727.     cli
  728.     push cx
  729.     push dx
  730.     push di
  731.     push si
  732.     push bp
  733.  
  734.     mov di,acc_delay; Save it
  735.  
  736.     mov dx,io_addr    ; Get card address
  737.     add dx,CTL_A    ; Point to channel A control reg
  738.     mov bp,dx    ; Save it
  739.  
  740.     mov dx,io_addr    ; get address of dma enable port
  741.     add dx,DMAEN
  742.     mov si,dx    ; save it
  743.  
  744.     mov cx,di    ; For loop below
  745.  
  746.     mov ax,100h    ; Disable DMA while we touch the scc
  747.     out dx,al
  748. ; ******** DMA off
  749. Loop4:    loop Loop4    ;[5]
  750.  
  751.     mov dx,bp    ;[2] Get address of SCC control reg
  752.     mov al,bh    ;[2] Select register
  753.     out dx,al;    ;[8]
  754.  
  755.     mov cx,di    ;[2]
  756. Loop5:    loop Loop5    ;[5]
  757.  
  758.     mov dx,si    ;[2] get address of dma enable port
  759.     mov al,ah    ;[2] Enable DMA
  760.     out dx,al    ;[8]
  761. ;********* DMA on - was off for 36 cycles
  762.     nop        ; Leave extra time for XT ram refresh cycle to finish
  763.     nop
  764.     nop
  765.     mov cx,di    ; For loop below
  766.     mov al,0
  767.     out dx,al
  768. ;********* DMA off
  769. Loop5a:    loop Loop5a    ;[5]
  770.  
  771.     mov dx,bp    ;[2] Get address of SCC control reg
  772.     in al,dx    ;[8] read register
  773.     mov bl,al    ;[2] save return value
  774.  
  775.     mov cx,di    ;[2]
  776. Loop6:    loop Loop6    ;[5]
  777.  
  778.     mov dx,si    ;[2] get address of dma enable port
  779.     mov al,ah    ;[2] Enable DMA
  780.     out dx,al    ;[8]
  781. ; ******** DMA on - was off for 36 cycles
  782.  
  783.     mov    al,bl    ; recover return value
  784.  
  785.     pop    bp
  786.     pop    si
  787.     pop    di
  788.     pop    dx
  789.     pop    cx
  790.     popf
  791.     ret
  792.  
  793.     public delay8253
  794. delay8253:
  795.     nop
  796.     nop
  797.     nop
  798.     nop
  799.     nop
  800.     ret
  801.  
  802. ; Setup for DMA
  803. ; Initializes certain DMA chip registers - called by setup_rx_dma
  804. ; and setup_tx_dma
  805. ; Enter with cx:bx = buffer, ax = length
  806. ; Writes the dma chip word count reg, dest reg, and the dma page reg
  807. ;
  808.     public setup_dma
  809. setup_dma:
  810.     
  811.     pushf    ; Save interrupt state
  812.     cli    ; Disable interrupts
  813.  
  814.     sub    ax,1    ; adjust length for DMA chip
  815.     push    ax    ; Save it for later
  816.     
  817.     mov    al,Byte Ptr dma_channel ; Disable DMA for this channel
  818.     add    al,DMA_DISABLE
  819.     out    DMA_MASK,al
  820.  
  821.     xor    al,al
  822.     out    DMA_RESETFF,al    ; Reset byte pointer flipflop
  823.  
  824. ; Calculate high order 4 bits of the buffer area and store
  825. ; them in the DMA page register
  826.     mov    ax,cx    ; Make a working copy of the seg reg
  827.     shl    ax,1
  828.     shl    ax,1
  829.     shl    ax,1
  830.     shl    ax,1
  831.     add    ax,bx    ; add offset - we have bottom word of abs. address
  832.     pushf        ; Save carry bit
  833.     mov    dx,dma_dest    ; Output buf start (source) address
  834.     out    dx,al
  835.     mov    al,ah
  836.     out    dx,al
  837.     mov    ax,cx    ; Get another copy of the seg reg
  838.     mov    cl,12    ; shift it down
  839.     shr    ax,cl    ; to get page register
  840.     popf        ; Recover carry bit
  841.     adc    ax,0    ; add any carry from previous add
  842.  
  843.     mov    dx,page_addr    ; Set up DMA page register
  844.     out    dx,al
  845.  
  846.     mov    dx,dma_wcr    ; Get address of word count register
  847.     pop    ax        ; Recover length and output it
  848.     out    dx,al
  849.     mov    al,ah
  850.     out    dx,al
  851.  
  852.     popf    ; restore interrupt state
  853.     ret
  854.  
  855. ; Setup receive dma
  856. ; Enter with cx:bx = buffer, ax = length
  857. ;
  858.     public    setup_rx_dma
  859. setup_rx_dma:
  860.     pushf    ; Save interrupt state
  861.     cli    ; Disable interrupts
  862.  
  863.     call    setup_dma
  864.  
  865. ; Get ready for RX DMA
  866.     mov    bx,R1+WT_FN_RDYFN+WT_RDY_RT+INT_ERR_Rx+EXT_INT_ENAB
  867.     call    wrtscc
  868.  
  869. ; Set DMA mode register to single transfers, incrementing address,
  870. ; auto init, writes
  871.     mov    al,dma_channel    ; Put dma chip in transmit for this channel
  872.     add    al,DMA_RX_MODE
  873.     out    DMA_MODE,al
  874.  
  875. ; Unmask channel n (enable DMA controller chip)
  876.     mov    al,Byte Ptr dma_channel ; Enable DMA for this channel
  877.     add    al,DMA_ENABLE
  878.     out    DMA_MASK,al
  879.  
  880. ; If a packet is already coming in, this line is supposed
  881. ; to mess up the crc to avoid receiving a partial packet
  882.     mov    bx,R0+RES_Rx_CRC
  883.     call    wrtscc
  884.  
  885. ; Enable RX dma in SCC chip
  886.     mov    bx,R1+WT_RDY_ENAB+WT_FN_RDYFN+WT_RDY_RT+INT_ERR_Rx+EXT_INT_ENAB
  887.     call    wrtscc
  888.     popf
  889.     ret
  890.  
  891. ;
  892. ; Set up for transmit DMA
  893. ; Enter with cx:bx = buffer, ax = length
  894. ;
  895.     public    setup_tx_dma
  896. setup_tx_dma:
  897.     pushf    ; Save interrupt state
  898.     cli    ; Disable interrupts
  899.     call    setup_dma
  900. ; Set DMA mode register to single transfers, incrementing address,
  901. ; no auto init, reads
  902.     mov    al,dma_channel    ; Put dma chip in transmit for this channel
  903.     add    al,DMA_TX_MODE
  904.     out    DMA_MODE,al
  905.     popf
  906.     ret
  907.  
  908.  
  909. ; Set up 8253 chip for time delay
  910. ; enter with time to delay (mS) in ax
  911. ;
  912.     public    tdelay
  913. tdelay:
  914.     push    bx
  915.     push    cx
  916.     push    dx
  917.  
  918.     push    ax            ; Save delay time
  919.     mov    dx,io_addr
  920.     add    dx,TMRCMD
  921.     mov    al,SC1+LSB_MSB+MODE0    ; Setup timer sc
  922.     out    dx,al
  923.     call delay8253            ; Satisy access time restriction
  924.  
  925.     mov    dx,io_addr
  926.     add    dx,TMR1
  927.     pop    ax            ; Recover delay time
  928.     sal    ax,1            ; Times 2 to make milliseconds
  929.     out    dx,al            ; Write low byte
  930.     call delay8253
  931.     mov    al,ah
  932.     out    dx,al            ; then high byte
  933.  
  934.     mov    bx,R15+CTSIE         ; Enable interrupt for timeout
  935.     call    wrtscc
  936.     mov    bx,R1+EXT_INT_ENAB
  937.     call    wrtscc
  938.     mov    bx,R0+RES_EXT_INT
  939.     call    wrtscc
  940.     
  941.     pop    dx
  942.     pop    cx
  943.     pop    bx
  944.     ret
  945.  
  946.     public    tx_off
  947. tx_off:
  948.     pushf
  949.     cli
  950.     push    bx
  951.  
  952.     mov    bx,R5+Tx8+DTR            ; TX off
  953.     call    wrtscc
  954.  
  955.     mov    ax,speed    ; Internally clocked?
  956.     cmp    ax,0
  957.     jz    tx_off_1    ; Externally clocked, don't change BRG
  958.     mov    ax,clkmode    ; Clocking mode 1?
  959.     cmp    ax,1
  960.     jz    tx_search    ; Mode 1, don't change BRG
  961.                 ; But enter search mode
  962. ; Reprogram BRG for 32x clock for receive DPLL
  963.     mov    bx,R14+BRSRC    ; BRG off, keep Pclk source
  964.     call    wrtscc
  965.     mov    ax,rx_tc    ; Get receive time constant for BRG
  966.     mov    bx,R12        ; Write low byte of time constant to R12
  967.     mov    bl,al
  968.     call    wrtscc
  969.     mov    ax,rx_tc    ; Get receive time constant for BRG
  970.     mov    bx,R13        ; Write high byte of time constant to R13
  971.     mov    bl,ah
  972.     call    wrtscc
  973. tx_search:
  974.     mov    bx,R14+BRSRC+SEARCH ; SEARCH mode, BRG source
  975.     call    wrtscc
  976.     mov    bx,R14+BRSRC+BRENABL ; Enable the baud rate generator
  977.     call    wrtscc
  978. tx_off_1:
  979.     mov    bx,R3+RxENABLE+RxCRC_ENAB+Rx8    ; RX on
  980.     call    wrtscc
  981.     
  982.     push    cs        ; Set up RX DMA
  983.     pop    cx
  984.     mov    bx,rxbufptr
  985.     mov    ax,cs:bufsiz
  986.     call    setup_rx_dma
  987.  
  988.     mov    bx,R15+BRKIE
  989.     call    wrtscc        ; allow abort interrupt
  990.  
  991.     pop    bx
  992.     popf
  993.     ret
  994.  
  995.     public    tx_on
  996. tx_on:
  997.     pushf
  998.     cli
  999.     push    bx
  1000.  
  1001.     mov    bx,R15+0    ; Exints off first to avoid abort interrupt
  1002.     call    wrtscc
  1003.     mov    bx,R3+Rx8    ; Rx off
  1004.     call    wrtscc
  1005.     mov    bx,R1+WT_FN_RDYFN+EXT_INT_ENAB    ; Set up for TX DMA
  1006.     call    wrtscc
  1007.     mov    ax,speed    ; Internally clocked?
  1008.     cmp    ax,0
  1009.     jz    tx_on_1        ; Externally clocked, don't change BRG
  1010.     mov    ax,clkmode    ; Clocking mode 1?
  1011.     cmp    ax,1
  1012.     jz    tx_on_1        ; Clocking mode 1, don't change BRG
  1013.     mov    ax,tx_tc    ; Get transmit time constant for BRG
  1014.     mov    bx,R12        ; Write low byte of time constant to R12
  1015.     mov    bl,al
  1016.     call    wrtscc
  1017.     mov    ax,tx_tc    ; Get transmit time constant for BRG
  1018.     mov    bx,R13        ; Write high byte of time constant to R13
  1019.     mov    bl,ah
  1020.     call    wrtscc
  1021. tx_on_1:
  1022.     mov    bx,R5+TxCRC_ENAB+RTS+TxENAB+Tx8+DTR
  1023.     call    wrtscc
  1024.  
  1025.     pop    bx
  1026.     popf
  1027.     ret
  1028.  
  1029.     include    popf.asm
  1030.  
  1031.     public    timer_isr
  1032. timer_isr:
  1033. ;if the first instruction is an iret, then the timer is not hooked
  1034.     iret
  1035.  
  1036. ;any code after this will not be kept.  Buffers used by the program, if any,
  1037. ;are allocated from the memory between end_resident and end_free_mem.
  1038.     public end_resident,end_free_mem
  1039. end_resident    label    byte
  1040.     db    30000 dup(?)
  1041. end_free_mem    label    byte
  1042.  
  1043.  
  1044. ; Initialize the SCC registers
  1045.     public scc_init
  1046. scc_init:
  1047.     pushf
  1048.     cli
  1049.  
  1050.     mov    cs:tstate,IDLE
  1051.     mov    bx,R9+CHRA    ; reset channel A
  1052.     call    wrtscc
  1053.     mov    bx,R2+0ffh    ; Set interrupt vector
  1054.     call    wrtscc
  1055.     mov    bx,R1+0        ; Deselect all Rx and Tx interrupts
  1056.     call    wrtscc
  1057.     mov    bx,R15+0    ; Turn off external interrupts
  1058.     call    wrtscc
  1059.     mov    bx,R4+SDLC+X1CLK ; SDLC mode and times 1 clock
  1060.     call    wrtscc
  1061.  
  1062.     mov    ax,speed    ; Get baud rate
  1063.     cmp    ax,0
  1064.     jz    scc_init_1    ; Jump if externally clocked
  1065.     mov    ax,clkmode    ; Clocking mode 1?
  1066.     cmp    ax,1
  1067.     jnz    scc_init_5    ; No - must be internal clocking
  1068.  
  1069.     mov    bx,R10+CRCPS ; Clock mode 1, CRC preset, not NRZI mode
  1070.     call    wrtscc
  1071.             ; Receive clock = RTxC pin
  1072.             ; Transmit clock = baud rate generator
  1073.             ; Transmit clock is output on TRxC pin 
  1074.     mov    bx,R11+TCBR+RCRTxCP+TRxCOI+TRxCTC
  1075.     call    wrtscc     
  1076.     jmp    scc_init_2
  1077.  
  1078. scc_init_5:
  1079.     mov    bx,R10+CRCPS+NRZI ; Internal clock, CRC preset, NRZI mode
  1080.     call    wrtscc
  1081.             ; Receive clock = DPLL
  1082.             ; Transmit clock = baud rate generator
  1083.             ; Transmit clock is output on TRxC pin 
  1084.     mov    bx,R11+TCBR+RCDPLL+TRxCOI+TRxCTC
  1085.     call    wrtscc     
  1086.     jmp    scc_init_2
  1087. scc_init_1:            ; Externally clocked
  1088.     mov    bx,R10+CRCPS    ; CRC preset
  1089.     call    wrtscc
  1090.             ; Receive clock = RTxC pin
  1091.             ; TRxC pin is input for transmit clock
  1092.     mov    bx,R11+TCTRxCP    ; Rcv clk is from Rtxcl, TRxC pin is input
  1093.     call    wrtscc
  1094.  
  1095. scc_init_2:
  1096.     mov    bx,R6+0        ; Null out SDLC start address
  1097.     call    wrtscc
  1098.     mov    bx,R7+FLAG    ; SDLC flag
  1099.     call    wrtscc
  1100.     mov    bx,R5+Tx8+DTR    ; Set up tx but don't enable it yet
  1101.     call    wrtscc
  1102.     mov    bx,R3+Rx8    ; Initial rx setup
  1103.     call    wrtscc
  1104.     mov    bx,R14+BRSRC
  1105.     call    wrtscc
  1106.  
  1107.     mov    ax,rx_tc    ; Get receive time constant for BRG
  1108.     mov    bx,R12        ; Write low byte of time constant to R12
  1109.     mov    bl,al
  1110.     call    wrtscc
  1111.     mov    ax,rx_tc    ; Get receive time constant for BRG
  1112.     mov    bx,R13        ; Write high byte of time constant to R13
  1113.     mov    bl,ah
  1114.     call    wrtscc
  1115.  
  1116.     mov    ax,speed    ; Internal clocking?
  1117.     cmp    ax,0
  1118.     jz    scc_init_3    ; Jump if External
  1119.     mov    ax,clkmode
  1120.     cmp    ax,1
  1121.     jnz    t1
  1122.  
  1123.     mov    bx,R14+BRSRC+SSRTxC+BRENABL
  1124.     call    wrtscc
  1125.     jmp scc_init_4
  1126.     
  1127. t1:
  1128.     mov    bx,R14+BRSRC+SSBR+BRENABL
  1129.     call    wrtscc
  1130.     jmp scc_init_4
  1131. scc_init_3:
  1132.     mov    bx,R14+BRSRC+SSRTxC ; Set DPLL source = RTxC
  1133.     call    wrtscc
  1134. scc_init_4:
  1135.     call    tx_off        ; Set up and enable RX
  1136.  
  1137.     popf
  1138.     ret
  1139.  
  1140. ;  This routine calculates the constant to be used in the delay loops
  1141. ;  which satisfy the SCC's access recovery time.  This needs to be timed and
  1142. ;  calculated because a fixed value would not work in a 4.77mhz XT
  1143. ;  to a 40mhz 486 (and beyond).
  1144.     public set_acc_delay
  1145. set_acc_delay:
  1146.     pushf
  1147.     cli
  1148.     push    ax
  1149.     push    bx
  1150.     push    cx
  1151.     push    dx
  1152.  
  1153.     mov    cx,1000
  1154.  
  1155.     mov    al,0            ;latch counter zero.
  1156.     out    43h,al
  1157.     in    al,40h            ;read counter zero.
  1158.     mov    ah,al
  1159.     in    al,40h
  1160.     xchg    ah,al
  1161.     mov    tick1,ax
  1162.  
  1163. h1:    loop    h1
  1164.  
  1165.     mov    al,0            ;latch counter zero.
  1166.     out    43h,al
  1167.     in    al,40h            ;read counter zero.
  1168.     mov    ah,al
  1169.     in    al,40h
  1170.     xchg    ah,al
  1171.     mov    tick2,ax
  1172.     mov    ax,tick1
  1173.     sub    ax,tick2
  1174.     mov    diff,ax    ; Elapsed counts
  1175.     mov    bx,ax
  1176.     mov    dx,0
  1177.     mov    ax,5000    ; Divide by
  1178.     div    bx    ; the number of counts elapsed
  1179.     cmp    al,0
  1180.     jne    set_acc_2
  1181.     mov    al,1    ; Delay constant must be at least 1
  1182. set_acc_2:
  1183.     xor    ah,ah
  1184.     mov    acc_delay,ax
  1185.  
  1186.     mov di, offset acc_delay    ; Processor speed constant
  1187.     mov dx,    offset acc_delay_name    ; Message for it
  1188.     call    print_number
  1189.  
  1190.     pop    dx
  1191.     pop    cx
  1192.     pop    bx
  1193.     pop    ax
  1194.     popf
  1195.     ret
  1196.  
  1197.     public    usage_msg
  1198. usage_msg    db    "usage: pi <packet_int_no> [hardware_irq] [io_addr] [dma] [baud] [TXD] [P] [slot] [tail] [clock mode] [buf size] [number of buffers]",CR,LF,'$'
  1199.  
  1200.     public    copyright_msg
  1201. copyright_msg    db    "Packet driver for the Ottawa PI card, version ",'0'+majver,".",'0'+version,CR,LF
  1202.         db    "Portions Copyright 1991, 1992 Dave Perry",CR,LF,'$'
  1203.  
  1204. int_no_name    db    "Interrupt number ",'$'
  1205. io_addr_name    db    "I/O port ",'$'
  1206. dma_name    db    "DMA channel ",'$'
  1207. acc_delay_name    db    "Processor constant ",'$'
  1208. diff_name    db    "diff ",'$'
  1209. tick1_name    db    "tick1 ",'$'
  1210. tick2_name    db    "tick2 ",'$'
  1211. speed_name    db    "Baud rate ",'$'
  1212. txdelay_name    db    "TX delay ",'$'
  1213. persist_name    db    "P value ",'$'
  1214. slottime_name    db    "Slot time ",'$'
  1215. tailtime_name    db    "Tail time ",'$'
  1216. clkmode_name    db    "Clocking mode ",'$'
  1217. bufsiz_name    db    "Buffer size ",'$'
  1218. numbufs_name    db    "Number of buffers ",'$'
  1219. baud_err_msg    db    "Error: Selected baud rate is out of range",CR,LF,'$'
  1220. no_memory_msg    db    "Unable to allocate enough memory, look at end_resident in PI.ASM",CR,LF,'$'
  1221.  
  1222.     extrn    set_recv_isr: near
  1223.  
  1224. ;enter with si -> argument string, di -> wword to store.
  1225. ;if there is no number, don't change the number.
  1226.     extrn    get_number: near
  1227.  
  1228. ;enter with dx -> argument string, di -> wword to print.
  1229.     extrn    print_number: near
  1230.  
  1231. ;-> the assigned Ethernet address of the card.
  1232.     extrn    rom_address: byte
  1233.  
  1234.     public    parse_args
  1235. parse_args:
  1236. ;exit with nc if all went well, cy otherwise.
  1237.     mov    di,offset int_no    ; May override interrupt channel
  1238.     call    get_number
  1239.     mov    di,offset io_addr    ; May override I/O address
  1240.     call    get_number
  1241.     mov    di,offset dma_channel    ; May override channel
  1242.     call    get_number
  1243.     mov    di,offset speed        ; May override speed
  1244.     call    get_number
  1245.     mov    di,offset txdelayparm    ; May override TX delay time
  1246.     call    get_number
  1247.     mov    di,offset persist    ; May override P value
  1248.     call    get_number
  1249.     mov    di,offset slottime    ; May override Slot time
  1250.     call    get_number
  1251.  
  1252. ; Calculate address of dma page register
  1253.     mov    al,Byte Ptr dma_channel
  1254.     cmp    al,2
  1255.     jne    parse_1
  1256.     mov    ax,81h
  1257.     jmp    parse_3
  1258. parse_1:
  1259.     cmp    al,3
  1260.     jne    parse_2
  1261.     mov    ax,82h
  1262.     jmp    parse_3
  1263. parse_2:
  1264.     mov    ax,83h
  1265. parse_3:
  1266.     mov    page_addr,ax
  1267.  
  1268. ; Calculate address of dma destination and dma word count regs
  1269.     mov    ax,Word Ptr dma_channel
  1270.     shl    ax,1
  1271.     mov    dma_dest,ax
  1272.     add    ax,1
  1273.     mov    dma_wcr,ax
  1274.     
  1275. ; Calculate time constants for baud rate generator
  1276.     mov    ax,word ptr speed
  1277.     cmp    ax,0
  1278.     jz    parse_4
  1279.  
  1280.     mov    dx,1ch        ; Load SCC clock freq into dx:ax
  1281.     mov    ax,2000h    
  1282.     div    speed        ; Divide by baud rate
  1283.     sub    ax,2        ; sub 2 - this is the BRG time constant
  1284.     mov    tx_tc,ax    ; for Transmit - save it
  1285.  
  1286.     mov    dx,0h        ; Load SCC clock freq/32 into dx:ax
  1287.     mov    ax,0e100h    
  1288.     div    speed        ; Divide by baud rate
  1289.     sub    ax,2        ; sub 2 - this is the BRG time constant
  1290.     mov    rx_tc,ax    ; for receive - save it
  1291.  
  1292. ; Calculate tail time. This is the time required for the CRC and closing
  1293. ; flag to be sent, during which the transmitter must be held on.
  1294.     mov    dx,0        ; Magic number
  1295.     mov    ax,8ca0h
  1296.     div    speed
  1297.     add    ax,1        ; Tail time is at least 1 ms
  1298.     mov    tailtime,ax
  1299. parse_4:
  1300.     mov    di,offset tailtime    ; May override Tail time
  1301.     call    get_number
  1302.  
  1303.     mov    di,offset clkmode    ; May override clocking mode
  1304.     call    get_number
  1305.  
  1306.     mov    di,offset bufsiz    ; May override buffer size
  1307.     call    get_number
  1308.     mov    ax,bufsiz
  1309.     mov    parm_mtu,ax
  1310.  
  1311.     mov    di,offset numbufs    ; May override number of buffers
  1312.     call    get_number
  1313.     cmp    numbufs,3        ; But we need at least 3
  1314.     jge    parse_4a
  1315.     mov    numbufs,3
  1316. parse_4a:
  1317.  
  1318.     clc    ; Return without error
  1319.     ret
  1320.  
  1321. baud_error:
  1322.     mov    dx,offset baud_err_msg
  1323.     mov    ah,9
  1324.     int    21h
  1325.     stc
  1326.     ret
  1327.  
  1328. ; Return offset of a buffer which does not cross a DMA page boundary.
  1329. ; Returns nc, ax=offset of buffer, or cy if no mem. Buffers are in code segment.
  1330.     public getbuffer
  1331. getbuffer:
  1332.     push    dx
  1333.     push    cx
  1334.     push    bx
  1335.  
  1336.     mov    ax,cs        ; get buffer segment
  1337.     mov    cx,ax
  1338.  
  1339. get1:    mov    ax,cs:bufsiz
  1340.     add    ax,4        ; Leave room for next pointer and length
  1341.     mov    dx,ax
  1342.     call    malloc
  1343.     jc    get_exit
  1344.     mov    bx,dx
  1345.     call    test_buffer
  1346.     jnc    get_exit    ; found one
  1347.     add    numbufs,1    ; Account for it
  1348.     
  1349.     pop    bx
  1350.     pop    cx
  1351.     pop    dx
  1352.     jmp    getbuffer
  1353. get_exit:
  1354.     mov    ax,dx        ; recover pointer
  1355.  
  1356.     pop    bx
  1357.     pop    cx
  1358.     pop    dx
  1359.     ret            ; return buffer found
  1360.  
  1361.     public    etopen
  1362. etopen:
  1363.  
  1364. ; Not meaningful for AX25 class - this code assumes DIX ethernet
  1365. ;get the address of the interface.
  1366.     mov    si,offset etheraddr
  1367.     movseg    es,ds
  1368.     mov    di,offset rom_address
  1369.     mov    cx,EADDR_LEN
  1370.     rep    movsb
  1371.  
  1372. ; Set up DMA buffer pool
  1373.     mov    cx,numbufs    ; We want this many
  1374. et1:
  1375.     call    getbuffer    ; Get a DMA buffer
  1376.     jc    etopen_error
  1377.     mov    bx,offset freelist    ; Append it to the free list
  1378.     call    enqueue
  1379.     loop    et1
  1380.  
  1381.     mov    bx,offset freelist    ; Get a buffer from the freelist
  1382.     call    dequeue
  1383.     jc    etopen_error    ; None left
  1384.     mov    bufptr1,ax    ; Remember as primary
  1385.     mov    rxbufptr,ax    ; Make it current
  1386.  
  1387.     mov    bx,offset freelist    ; Get a buffer from the freelist
  1388.     call    dequeue
  1389.     jc    etopen_error    ; None left
  1390.     mov    bufptr2,ax    ; Use it for secondary rx buffer
  1391.  
  1392. ; Adjust scc delay for speed of host cpu
  1393.     call    set_acc_delay
  1394.  
  1395.     mov    bx,R9+FHWRES    ; Hardware reset SCC
  1396.     call    wrtscc
  1397.  
  1398. ; Disable interrupts with Master interrupt ctrl reg */
  1399.     mov    bx,R9+0
  1400.     call    wrtscc
  1401.     call    scc_init
  1402.     mov    bx,R9+MIE+NV ; master interrupt enable
  1403.     call    wrtscc
  1404.  
  1405. ; Set up counter chip
  1406.     mov    dx,io_addr
  1407.     add    dx,TMRCMD
  1408.     mov    al,SC0+LSB_MSB+MODE3 ; 500 uS square wave
  1409.     out    dx,al
  1410.     call delay8253        ; Satisfy access time restriction
  1411.     mov    ax,922        ; time constant
  1412.     mov    dx,io_addr
  1413.     add    dx,TMR0
  1414.     out    dx,al        ; LSB
  1415.     call delay8253        ; Satisy access time restriction
  1416.     mov    al,ah
  1417.     out    dx,al        ; MSB
  1418.     call delay8253        ; Satisy access time restriction
  1419.  
  1420.     call    set_recv_isr    ; Hook the board int
  1421. ;if all is okay,
  1422.     clc
  1423.     ret
  1424. etopen_error:
  1425.     mov    dx,offset no_memory_msg
  1426.     stc
  1427.     ret
  1428.  
  1429. dma_page_save    dw    0
  1430. dma_dest_save    dw    0
  1431. dma_wcr_save    dw    0
  1432. ; Test a buffer to see if it crosses a DMA page boundary.
  1433. ; Enter with cx:bx = buffer, ax = length
  1434.     public test_buffer
  1435. test_buffer:
  1436.     sub    ax,1    ; adjust length for DMA chip
  1437.     mov    dma_wcr_save,ax ; Save it for the dma_wcr register
  1438.     
  1439. ; Calculate high order 4 bits of the buffer area and store
  1440. ; them in the DMA page register
  1441.     mov    ax,cx    ; Make a working copy of the seg reg
  1442.     shl    ax,1
  1443.     shl    ax,1
  1444.     shl    ax,1
  1445.     shl    ax,1
  1446.     add    ax,bx    ; add offset - we have bottom word of abs. address
  1447.     pushf        ; Save carry bit
  1448.     mov    dma_dest_save,ax ; save this for the dma_dest register
  1449.  
  1450.     mov    ax,cx    ; Get another copy of the seg reg
  1451.     mov    cl,12    ; shift it down
  1452.     shr    ax,cl    ; to get page register
  1453.     popf        ; Recover carry bit
  1454.     adc    ax,0    ; add any carry from previous add
  1455.     mov    dma_page_save,ax ; Save this for the dma_page register
  1456.  
  1457. ; Now do the test: add the buffer size to the destination address
  1458. ; and see if we're still in the same page
  1459.     mov    ax,dma_dest_save ; recover bottom 16 bits of absolute addr
  1460.     add    ax,cs:bufsiz    ; add the buffer size
  1461.                 ; if carry is set, we spilled over the page
  1462.     ret            ; return carry clear on success
  1463.  
  1464.     public    print_parameters
  1465. print_parameters:
  1466. ;echo our command-line parameters
  1467.     mov di,    offset int_no        ; Interrupt channel
  1468.     mov dx,    offset int_no_name    ; Message for it
  1469.     call    print_number
  1470.     mov di,    offset io_addr        ; I/O address
  1471.     mov dx,    offset io_addr_name    ; Message for it
  1472.     call    print_number
  1473.     mov di,    offset dma_channel    ; DMA channel
  1474.     mov dx,    offset dma_name        ; Message for it
  1475.     call    print_number
  1476.     mov di, offset speed        ; Baud rate
  1477.     mov dx,    offset speed_name 
  1478.     call    print_number
  1479.     mov di, offset txdelayparm    ; TX delay
  1480.     mov dx,    offset txdelay_name
  1481.     call    print_number
  1482.     mov di, offset persist        ; P persistance 
  1483.     mov dx,    offset persist_name
  1484.     call    print_number
  1485.     mov di, offset slottime        ; Slot time
  1486.     mov dx,    offset slottime_name
  1487.     call    print_number
  1488.     mov di, offset tailtime        ; Tail time
  1489.     mov dx,    offset tailtime_name
  1490.     call    print_number
  1491.     mov di, offset clkmode        ; Clocking mode
  1492.     mov dx,    offset clkmode_name
  1493.     call    print_number
  1494.     mov di, offset bufsiz        ; Buffer size
  1495.     mov dx,    offset bufsiz_name
  1496.     call    print_number
  1497.     mov di, offset numbufs        ; Number of buffers
  1498.     mov dx,    offset numbufs_name
  1499.     call    print_number
  1500.  
  1501.     ret
  1502.  
  1503. code    ends
  1504.  
  1505.     end
  1506.