home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Serving the Web
/
ServingTheWeb1995.disc1of1.iso
/
connect
/
tcpip
/
crynwr
/
pktd11a
/
express.asm
< prev
next >
Wrap
Assembly Source File
|
1993-07-24
|
53KB
|
1,830 lines
version equ 4
include defs.asm
include 8250defs.asm
;
; Dave Price. October 30th 1990. 12:35.
; Things much better now. I have had my standard
; 'FTP' test running at 2.5 Kbytes per second.
; There is still a transmit bug though.. It appears
; as the transmission of giant packets. I think I know
; the source of the bug. I believe it occurs when we are
; transmitting the last few bytes of a packet. Before
; we change the interrupt mask to expect only TXDONE and
; TXURUN, the TX fifo drains so that the TX419 condition
; becomes true. The result is that the 8952 is already
; waiting to interrupt us with the TX419. My code does not
; expect anymore of these and acts incorrectly when
; one arrives!
;
; Dave Price. October 30th 1990 10:08.
; After several minor changes the driver was almost
; working. Some problems still existed however and
; transferring data with FTP for instance
; seemed to take a very long time. It appeared that
; data was being lost, or that the routers or distant
; host were so busy that packets were being dropped.
; A further possible cause was that the timers used
; by the TCP protocol engines were inappropriate or
; in some sense incompatible. A carefull reading of
; the data sheets implies that one can use the 'FIFO empty'
; bits providing you make sure that at least 2 cycles
; of a 2mHz clock occur after you read data and before you
; read the interrupt flag register. This only amounts to
; 16 bus cycles on a 16Mhz PC. This is really very few
; instructions. I have talked to Jeremy Bicknall at MITEL
; and he seems to agree (I reported a potential design
; bug with the 8952 generating false RX1519s - he will persue).
; I have thus decided to use the RXBYTE bits to decide how
; to process each item of data but use the RXFIFO empty state
; to cease reading data.
;
;
; Dave Price. October 24th 1990 11:10.
; More changes again. The main idea now is
; to only have two states in the RX protocol engine.
; It is either 'building' a frame or 'skipping'
; to the next one. The actual interrupts will just
; be used to indicate the point at which you should
; stop processing the RXFIFO. There will be several
; items to help. A minimum numbers of bytes to read,
; a maximum number of bytes to read and a stop condition.
; Processing the FIFO will cease when either the maximum
; number of bytes have been processed, or BOTH the stop
; condition and the minimum number have been processed.
; On considering a new item of data a mask will be built
; containing 5 bits that reflect a condition implied
; by the data. Four bits are used to simply indicate
; a packet byte, first byte, good last byte or bad last
; byte. The fifth bit is used to indicate a frame abort
; condition; this can only be determined by deciding
; that the byte about to be read is a 'first' byte and
; we already BUILDING a packet.
; This change is a radical departure from previous
; approaches to the RX code and might perhaps work
; (HA, Ha!)
;
; Dave Price. October 23rd 1990 16:06.
; Some change of thought again.. I hate 8952s!
; I am moving to four states in RX protocol engine.
; 'idle' will mean - finished one packet, awaiting next
; 'skipping' will mean we failed to get a buffer so
; we are awaiting this packet to go by before trying
; again for a buffer. I.E. we are discarding all input
; waiting for an FA or EOPD etc etc
; 'found' means that the NEXT byte in the fifo
; is a 'first' byte. I.E. here comes the packet...
; 'building' means we have a buffer and we are off
; making up the next packet.
;
; Dave Price. October 23rd 1990 09:40.
; Having got completely fed up with lots of minor bugs
; in the RX code, I am now carrying on with the changes
; started earlier on 17th to attempt to have
; some more clean code for the RX side. Most of the
; code has been developed over the weekend but is
; handwriiten on the last listing. Problems
; mainly arise with odd combinations of events
; rather than simple circumstances. A major change is
; that the RX code will now longer go and get itself
; a buffer until the 'first byte' has been located. In
; particular the completion of the collection of one
; packet was immediately followed by the allocation
; of a new buffer. This will now not happen.
; I also intend at a later date to add fields to the
; hdlc datastructure to hold port addresses etc. This
; will start to pave the way for making the driver handle
; multiple channels. It will require other changes as
; well though (mainly stopping the code use constructions
; like hdlc0.fred and instead move to set bx; [bx].fred.
; This is not straightforward though as bs is already
; used as a pointer. It will imply lots of pushing and
; popping probably. All this is the next fix NOT
; this change anyway.
;
; October 17th 1990 20:30. Work starts to alter RX data
; structures with a view to adding a 'state' variable
; and dealing with input quite differently.
;
; October 17th 1990.
; Several new patches of code added to try to
; the remaining bugs. Most bugs are caused by too long
; packets being received (possibly because rx fails to
; deal with FAs and RXOFLOWs correctly).
;
; October 16th 1990. The code has now been used
; fairly successfully. Some files have been transfered
; using FTP from a sun via one NOS router over a 64Kbps
; link from a second NOS PC. The central router had to
; be rebooted once during the transfer as the driver
; ran out of receive buffers! Amazingly the file
; transfered o.k! The file was a 43Kbyte binary
; of a virus checking program.
; Code has been added to cope with RXofloe and Frame
; abort, but bugs exist.
;
; October 11th 1990. The code has been running now
; used by NOS. Some problems had occurred with
; events like txdone also having tx419 set.
; Even though only txdone was enabled as an interrupt,
; reading the 'interrupt flag register' showed both
; bits set. As the code allows for several conditions
; to be true it obeyed the one set of code and then
; attempted to handle the other condition too! This
; resulted in errors.
; The code now carefully processes txdone and then avoids
; the tx419 condition!
; Similar problems exist with eopd and fa!
;
; October 1st 1990. Code is now in place to handle
; rx and tx interrupts. user can also specify -n
; so board acts as an NT.
; Only RX1519, and EOPD handled on receive and TXDONE and
; TX419 handles on transmit.
;
; Buffer strategy Changed again. 25 September 1990. Dave Price
; The idea now is that there will be a ring of
; structures, each structure containing a little control
; information plus a Data Unit in which will be placed
; an IP frame (or potentially any other type of frame).
; There will be two such rings, one for transmission
; and one for reception.
; The rings will be statically allocated.
; The Data Units will be set at 1500 bytes, the same
; as the maximum MTU for ethernet packet drivers.
;
; Simple byte-ring-buffer has proved awkward to
; code. One often seems to be fighting the INTEL CPU.
; On reflection a 'frame' based approach might be better.
;
; Added Code for RJG suggested Buffer Management. The
; idea is described in an ARUW?? document. There will
; be a circular ring buffer of bytes (like the slip
; drivers) with an associated structure to hold the
; state of the buffers.
;
; More bits from Dave Price to initialize
; MITEL express card. Just plugs voice so far.
; 30/8/90
;
; This is a hacked version of slip8250 packet driver.
; The hack is beginning on 28/8/90.
; First attempts are just to change messages etc!
;
; Changes started by Dave Price
;
;Ported from Phil Karn's asy.c and slip.c, a C-language driver for the IBM-PC
;8250 by Russell Nelson. Any bugs are due to Russell Nelson.
;16550 support ruthlessly stolen from Phil Karn's 8250.c. Bugs by Denis DeLaRoca
; Copyright, 1988-1992, Russell Nelson, Crynwr Software
; This program is free software; you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation, version 1.
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with this program; if not, write to the Free Software
; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
code segment byte public
assume cs:code, ds:code
;
; Constants etc from MITEL Express card
;
; First the DX (8980)
;
board_w_dx dw 0300h
dx_b_con equ 0000h
dx_b_cm_base equ 0400h
dx_con_cmh equ 00011000b
dx_con_cml equ 00010000b
dx_cmh_mchan equ 00000100b
dx_cmh_oe equ 00000001b
;
; Now the stream and channel assignments
;
snic_stream equ 6
snic_d_channel equ 0
snic_c_channel equ 1
snic_b1_channel equ 2
snic_b2_channel equ 3
hdlc_stream equ 6
hdlc_d_channel equ 4
hdlc_c_channel equ 5
hdlc_b1_channel equ 6
hdlc_b2_channel equ 7
hdlc_b3_channel equ 8
dphone_stream equ 7
dphone_unused_channel equ 4
dphone_c_channel equ 5
dphone_b1_channel equ 6
dphone_b2_channel equ 7
dphone_b3_channel equ 8
;
; Now some snic values etc
;
board_w_snic dw 0b00h
snic_b_master equ 0000h
snic_b_stbus equ 0001h
snic_master_irqenable equ 00000000b
snic_master_msdisable equ 00000010b
snic_master_cstenable equ 00000000b
snic_stbus_all equ 0ffh
snic_c_ar equ 10000000b
snic_c_dr equ 01000000b
snic_c_dinb equ 00100000b
snic_c_priority equ 00010000b
snic_c_dreq equ 00001000b
snic_c_txmch equ 00000100b
snic_c_clrdia equ 00000010b
snic_c_regsel equ 00000001b
;
; now some dphone values
;
board_w_dphone dw 1700h
dphone_b_c equ 0000h
dphone_b_time equ 0005h
dphone_b_wdog equ 0006h
dphone_b_tone1 equ 0007h
dphone_b_tone2 equ 0008h
dphone_b_dsp equ 0009h
dphone_b_trans equ 000ah
dphone_b_rgain equ 000bh
dphone_b_sddata equ 000ch
dphone_b_sddir equ 000dh
dphone_b_test equ 000eh
dphone_sddir_allout equ 0ffh
dphone_sddata_te equ 0b0h
dphone_sddata_nt equ 0b8h
dphone_time_pcmb1 equ 00000001b
dphone_time_pcmb2 equ 00000100b
dphone_time_pcmb3 equ 00010000b
dphone_time_c equ 10000000b
dphone_tone_697 equ 59h
dphone_tone_1209 equ 9bh
dphone_test_disable equ 00h
dphone_dsp_cpcmen equ 01000000b
dphone_dsp_dpcmen equ 00100000b
dphone_dsp_dual equ 00001000b
dphone_dsp_tone equ 00010000b
dphone_dsp_speaker equ 00011000b
dphone_dsp_cadence equ 00000100b
dphone_dsp_warble16 equ 00000010b
dphone_dsp_dspen equ 00000001b
dphone_trans_dial equ 00100000b
dphone_trans_side equ 00010000b
dphone_trans_hsmic equ 00001000b
dphone_trans_spmic equ 00000100b
dphone_trans_spskr equ 00000010b
dphone_trans_hsskr equ 00000001b
dphone_rgain_hpf equ 10000000b
dphone_rgain_rfg_m7 equ 01110000b
;
; now the hdlcs relative to the board base
;
board_w_hdlc0 dw 0f00h
board_w_hdlc1 dw 1300h
;
; Now register offsets in the hdlc chips
;
hdlc_br_fifostatus equ 00h
hdlc_br_receive equ 01h
hdlc_bw_transmit equ 01h
hdlc_b_control equ 02h
hdlc_b_raddress equ 03h
hdlc_b_cchancontrol equ 04h
hdlc_b_time equ 05h
hdlc_br_intflag equ 06h
hdlc_bw_wdog equ 06h
hdlc_bw_intenable equ 07h
hdlc_br_genstatus equ 08h
hdlc_br_cchanstatus equ 09h
;
; Now some values for the registers of the hdlc's
;
hdlc_fifostatus_RXBYTE equ 11000000b
hdlc_fifostatus_packet equ 00000000b
hdlc_fifostatus_first equ 01000000b
hdlc_fifostatus_good equ 10000000b
hdlc_fifostatus_bad equ 01000000b
hdlc_fifostatus_last equ 10000000b
hdlc_fifostatus_RXFIFO equ 00110000b
hdlc_fifostatus_rxempty equ 00000000b
hdlc_fifostatus_rxle14 equ 00010000b
hdlc_fifostatus_rxfull equ 00100000b
hdlc_fifostatus_rxge15 equ 00010000b
hdlc_fifostatus_TXFIFO equ 00001100b
hdlc_fifostatus_txfull equ 00000000b
hdlc_fifostatus_txge5 equ 00000100b
hdlc_fifostatus_txempty equ 00001000b
hdlc_fifostatus_txle4 equ 00000100b
hdlc_control_txen equ 10000000b
hdlc_control_rxen equ 01000000b
hdlc_control_rxad equ 00100000b
hdlc_control_ra6 equ 00010000b
hdlc_control_iftf1 equ 00001000b
hdlc_control_iftf0 equ 00000100b
hdlc_control_fa equ 00000010b
hdlc_control_eop equ 00000001b
hdlc_control_idle equ 00000000b
hdlc_control_iftf equ 00000100b
hdlc_control_trans equ 00001000b
hdlc_control_goahead equ 00001100b
hdlc_time_rst equ 10000000b
hdlc_time_ic equ 01000000b
hdlc_time_c1en equ 00100000b
hdlc_time_brck equ 00010000b
hdlc_time_tc equ 00001111b
hdlc_time_c2bits8 equ 00000011b
hdlc_time_c3bits8 equ 00000100b
hdlc_time_c4bits8 equ 00000101b
hdlc_time_c23bits16 equ 00000110b
hdlc_time_c234bits24 equ 00000111b
hdlc_intflag_ga equ 10000000b
hdlc_intflag_eopd equ 01000000b
hdlc_intflag_txdone equ 00100000b
hdlc_intflag_fa equ 00010000b
hdlc_intflag_tx419 equ 00001000b
hdlc_intflag_txurun equ 00000100b
hdlc_intflag_rx1519 equ 00000010b
hdlc_intflag_rxoflw equ 00000001b
hdlc_intenable_ga equ 10000000b
hdlc_intenable_eopd equ 01000000b
hdlc_intenable_txdone equ 00100000b
hdlc_intenable_fa equ 00010000b
hdlc_intenable_tx419 equ 00001000b
hdlc_intenable_txurun equ 00000100b
hdlc_intenable_rx1519 equ 00000010b
hdlc_intenable_rxoflw equ 00000001b
hdlc_genstatus_rxoflw equ 10000000b
hdlc_genstatus_txurun equ 01000000b
hdlc_genstatus_ga equ 00100000b
hdlc_genstatus_abrt equ 00010000b
hdlc_genstatus_irq equ 00001000b
hdlc_genstatus_idle equ 00000100b
;
; Now the overall interrupt register
;
board_w_intreg dw 1b00h
intreg_hdlc0 equ 00000010b ;bit for hdlc0 interrupt
intreg_hdlc1 equ 00000001b ;bit for hdlc1 interrupt
intreg_snic equ 00000100b ;bit for snic interrupt
intreg_hphone equ 00001000b ;bit for d/hphone interrupt
;
; now a few usefull macros
;
out_chip_reg_value macro chip,reg,value
mov dx,chip
add dx,reg
mov al,value
out dx,al
endm
in_chip_reg macro chip,reg
mov dx,chip
add dx,reg
in al,dx
endm
dx_message macro stream,channel,value
out_chip_reg_value board_w_dx,dx_b_con,<dx_con_cmh or stream>
out_chip_reg_value board_w_dx,<dx_b_cm_base or channel>,<dx_cmh_mchan or dx_cmh_oe>
out_chip_reg_value board_w_dx,dx_b_con,<dx_con_cml or stream>
out_chip_reg_value board_w_dx,<dx_b_cm_base or channel>,value
endm
dx_source macro d_stream,d_channel,s_stream,s_channel
out_chip_reg_value board_w_dx,dx_b_con,<dx_con_cmh or d_stream>
out_chip_reg_value board_w_dx,<dx_b_cm_base or d_channel>,dx_cmh_oe
out_chip_reg_value board_w_dx,dx_b_con,<dx_con_cml or d_stream>
out_chip_reg_value board_w_dx,<dx_b_cm_base or d_channel>,<s_stream shl 5 or s_channel>
endm
public int_no
int_no db 7,0,0,0 ; interrupt number.
NT_switch db 0 ;if 0 be a TE else be an NT
public driver_class, driver_type, driver_name, driver_function, parameter_list
driver_class db 6,0,0,0 ;from the packet spec
driver_type db 0,0,0,0 ;from the packet spec
driver_name db 'EXPRESS',0 ;name of the driver.
driver_function db 2
parameter_list label byte
db 1 ;major rev of packet driver
db 9 ;minor rev of packet driver
db 14 ;length of parameter list
db EADDR_LEN ;length of MAC-layer address
dw GIANT ;MTU, including MAC headers
dw MAX_MULTICAST * EADDR_LEN ;buffer size of multicast addrs
dw 0 ;(# of back-to-back MTU rcvs) - 1
dw 0 ;(# of successive xmits) - 1
dw 0 ;Interrupt # to hook for post-EOI
;processing, 0 == none,
;
; Packet Buffer Structure
owner_k_empty equ 0
owner_k_queue equ 1
owner_k_isr equ 2
info_k_size equ 1500 ;size of info area in buffer
;
buff struc
buff_w_next dw 0 ;pointer to next buffer
buff_w_prev dw 0 ;pointer to previous buffer
buff_w_size dw 0 ;size of frame in info area in bytes
buff_w_owner dw owner_k_empty ;current owner of buffer
buff_info db info_k_size dup (0) ;area for the Transfer Unit
buff ends
;
; Structure for shared Queue Information
; Now contains the info for the associated isr routines
; as well. 17th October 1990.
;
; First some constants.
;
state_k_skipping equ 00000001b
state_k_building equ 00000010b
upcall_k_idle equ 0
upcall_k_active equ 1
;
hdlc_data struc
txq_w_front dw 0 ;pointer to front of tx queue
txq_w_back dw 0 ;pointer to back of tx queue
rxq_w_front dw 0 ;pointer to front of rx queue
rxq_w_back dw 0 ;pointer to back of rx queue
rxupcall_w_state db 0 ;state of any upcall
rxisr_w_state db 0 ;the current state of the isr
rxisr_w_pkt dw 0 ;pointer to the packet being used by rx ISR
rxisr_w_byte dw 0 ;pointer to the byte the rx ISR will use next
rxisr_w_count dw 0 ;count of bytes inserted so far
txisr_w_pkt dw 0 ;pointer to the packet being used by tx ISR
txisr_w_byte dw 0 ;pointer to the byte tx ISR will use next
txisr_w_count dw 0 ;count of bytes remaining
copy_intflag db 0 ;copy of latest value from int flag
copy_intenable db 0 ;copy of latest value sent int enable
hdlc_data ends
hdlc0_data hdlc_data <offset t1_buff, offset t1_buff, offset r1_buff, offset r1_buff,upcall_k_idle,state_k_skipping>
;
; Names for the bits in the byte_status_mask
; rint_status_mask
; and the stop_status_mask
;
mask_k_packet equ 00000001b
mask_k_first equ 00000010b
mask_k_good equ 00000100b
mask_k_bad equ 00001000b
mask_k_fabort equ 00010000b
byte_status_mask db 0 ;used to save status implied
;by the current bytes
;rint_status_mask db 0 ;used to save status implied
;by the bytes so far in this
;segment in the fifo
;stop_status_mask db 0 ;used to specify when we wish
; to stop
;
; Locations to hold counters of bytes read in
; one particular call of the interrupt code.
;
;number_read db 0 ;number read so far
;minimum_read db 0 ;minimum number that MUST be read
; the interrupt style sets this
;maximum_read db 0 ;maximum available
public rcv_modes
rcv_modes dw 4 ;number of receive modes in our table.
dw 0,0,0,rcv_mode_3
public bad_command_intercept
bad_command_intercept:
;called with ah=command, unknown to the skeleton.
;exit with nc if okay, cy, dh=error if not.
mov dh,BAD_COMMAND
stc
ret
public as_send_pkt
; The Asynchronous Transmit Packet routine.
; Enter with es:di -> i/o control block, ds:si -> packet, cx = packet length,
; interrupts possibly enabled.
; Exit with nc if ok, or else cy if error, dh set to error number.
; es:di and interrupt enable flag preserved on exit.
as_send_pkt:
ret
public drop_pkt
; Drop a packet from the queue.
; Enter with es:di -> iocb.
drop_pkt:
assume ds:nothing
ret
public xmit
; Process a transmit interrupt with the least possible latency to achieve
; back-to-back packet transmissions.
; May only use ax and dx.
xmit:
assume ds:nothing
ret
public send_pkt
;
send_pkt:
;enter with es:di->upcall routine, (0:0) if no upcall is desired.
; (only if the high-performance bit is set in driver_function)
;enter with ds:si -> packet, cx = packet length.
;exit with nc if ok, or else cy if error, dh set to error number.
;called from telnet layer via software interrupt
assume ds:nothing
movseg es,cs
assume es:code
sti ; enable interrupts
;
; NOTE Using ES as segment for data accesses
;
mov bx,es:hdlc0_data.txq_w_back ;get pointer to back of queue
cmp es:[bx].buff_w_owner,owner_k_empty ;is it empty?
jne no_buffers_left ;no so error return...
cmp cx,info_k_size ; check packet size o.k.
jle send_pkt_size_ok ; its fine
pr_ch_al 'a' ; error trace message
mov dh,CANT_SEND ;return an error code
cli
stc
ret
send_pkt_size_ok:
mov es:[bx].buff_w_size,cx ;save size
lea di,es:[bx].buff_info ;
rep movsb ;and copy the packet
mov es:[bx].buff_w_owner,owner_k_queue ;give it to queue
mov bx,es:[bx].buff_w_next ;point to buffer
mov es:hdlc0_data.txq_w_back,bx ;adjust back of the queue
;
; NOW WE NEED TO PROVOKE LOADING OF TXFIFO
; IF WE THINK ISR GONE QUIET
;
; structure is at zero no ints active
cli ;block interrupts starting before we exit
cmp es:hdlc0_data.txisr_w_pkt,0
je send_pkt_int_quiet ; jump if interrupts quiet
clc ;clear carry because all o.k.
ret
;
; Else we now need to kick the interrupt code
;
send_pkt_int_quiet:
push ds ;save old ds and make it point to code
push cs
pop ds
pr_ch_al 'b'
call tint_new ;manually call the tint routine !
pop ds ;restore old ds and
ret ;return
no_buffers_left:
pr_ch_al 'c'
mov dh,NO_SPACE
cli ;block interrupts before we exit
stc ;signal its an error - no more buffers
ret
public set_address
set_address:
;set the address of the interface.
;enter with es:di -> place to get the address, cx = size of address buffer.
;exit with nc, cx = actual size of address, or cy if buffer not big enough.
assume ds:nothing
clc
ret
rcv_mode_3:
;receive mode 3 is the only one we support, so we don't have to do anything.
ret
public set_multicast_list
set_multicast_list:
;enter with ds:si ->list of multicast addresses, ax = number of addresses,
; cx = number of bytes.
;return nc if we set all of them, or cy,dh=error if we didn't.
mov dh,NO_MULTICAST
stc
ret
public terminate
terminate:
ret
public reset_interface
reset_interface:
;reset the interface.
assume ds:code
ret
;called when we want to determine what to do with a received packet.
;enter with cx = packet length, es:di -> packet type, dl = packet class.
extrn recv_find: near
;called after we have copied the packet into the buffer.
;enter with ds:si ->the packet, cx = length of the packet.
extrn recv_copy: near
;call this routine to schedule a subroutine that gets run after the
;recv_isr. This is done by stuffing routine's address in place
;of the recv_isr iret's address. This routine should push the flags when it
;is entered, and should jump to recv_exiting_exit to leave.
;enter with ax = address of routine to run.
extrn schedule_exiting: near
;recv_exiting jumps here to exit, after pushing the flags.
extrn recv_exiting_exit: near
extrn count_in_err: near
extrn count_out_err: near
public recv
recv:
;called from the recv isr. All registers have been saved, and ds=cs.
;Upon exit, the interrupt will be acknowledged.
assume ds:code
mov ax,offset recv_exiting ;schedule recv_exiting to be called
call schedule_exiting ; on exit.
recv_2:
in_chip_reg board_w_intreg,0 ; get interrupt source
test al,intreg_hdlc0 ;check if HDLC0
jne not_hdlc0
jmp which_reg ;Jump and check the chip
not_hdlc0:
pr_ch_al '+'
ret ;Not this chip so give up
which_reg:
in_chip_reg board_w_hdlc0,hdlc_br_intflag
mov hdlc0_data.copy_intflag,al ;save the interrupt flags
;
; We now analyse for the different interrupts that
; may be present. We first make some tests for styles
; of interrupts so we dont need to check everything
; each time.
;
test hdlc0_data.copy_intflag,hdlc_intflag_eopd or hdlc_intflag_fa or hdlc_intflag_rx1519 or hdlc_intflag_rxoflw
je test_tint ;No receive style interrupts so jump
; There is a receive event
;
; We recognise 8 receive events.
; 1/. RX1519
; 2/. RX1519 + RXOFLW
; 3/. EOPD
; 4/. EOPD+RX1519
; 5/. EOPD + RX1519 + RXOFLW
; 6/. FA + EOPD
; 7/. FA + EOPD + RX1519
; 8/. FA + EOPD + RX1519 + RXOFLW
; We believe that other (potential) RX events cannot
; occur.
; We recognise only three (major) states for the RX
; protocol engine.
; 1/. SKIPPING for the start of a packet; all data
; is essentially ignored in this state. No
; receive buffer will have been allocated.
; We are in this state between packets or perhaps
; because we have just run out of buffers!
; See also state 3 below.
; 2/. BUILDING a packet. Generally speaking,
; providing we have enough room, 'packet' bytes
; are just added into the buffer, 'good last' bytes
; terminating the building of a packet and provoke
; its delivery to the upper layer. Other data such
; as 'bad last' or 'first' bytes cause the packet
; being built to be discarded and the engine to
; move to SKIPPING state. A first byte implies
; a frame abort has been received of course.
; 3/. It is also possible to be SKIPPING&BUILDING !
; This occurs after we have read data that
; would have moved us to BUILDING state but
; we could not get buffer space. We need this
; to properly detect frame aborts (see below).
;
; EVENT PROCESSING in a little more detail.
;
; 1/. RX1519
; We are required to clear 14 bytes from the fifo.
; It is possible to show that in pathological
; circumstances bytes other than packet bytes can
; be in the FIFO!
;
; 2/. RX1519 + RXOFLW
; Regardless of state, we read 19 bytes from the FIFO.
; We do this as we do not want to accidently
; discard the front of a following packet.
;
; 3/. EOPD
; We process bytes up to a bad/good last byte.
; We then deliver or discard the packet.
; Clearly should not process more than 19 and
; if RX1519 set it would be surprising if we
; processed more than 14!
;
; 4/. EOPD + RX1519
; We are required to clear 14 bytes from the fifo.
; Process as in 3/. above but make sure we clear
; at LEAST 14 bytes. We might read more than 15
; if for instance the EOPD occurred as the 16 byte
; which had arrived while we were responding to
; the event which interrupted us which was a 'packet'
; byte in number 15. It is also possible that the 'last'
; byte might be number 14 but a 'first' byte also arrived
; in 15 creating the RX1519 to occur as well.
;
; 5/. EOPD + RX1519 + RXOFLW
; The RXOFLW implies we have missed stuff and some
; data failed to get into the end of the FIFO. The
; RX FIFO is supposed to enter a FLAG search mode after
; overflowing. Thus is we process as in 3/. but EMPTY
; the whole buffer(i.e. read 19 bytes).,
;
; 6,7,8/. I.E. any FA condition.
; We will read upto 19 bytes of data. It would
; be surprising if we read more than 14 unless RX1519
; was also set. We will end when we discover a Frame
; Abort condition. This is implied by a first byte
; when building but ALSO by a first byte if skipping
; and we have already seen a first byte!
;
;
; Now set up some values. The maximum and minimum
; count values, the current number read
; and we clear the stop_status_mask.
; mov minimum_read,1 ;often increased below
; mov maximum_read,14 ;typically we end before this
; mov stop_status_mask,0 ;clear the stop status mask
;
;test_fa:
; test hdlc0_data.copy_intflag,hdlc_intflag_fa
; je test_eopd
; We have an FA so change stop_status_mask
; and change the maximum read to 19 (?)
; mov stop_status_mask,mask_k_fabort
; mov maximum_read,19 ;typically we end before this
; jmp test_rxoflw ;can avoid the eopd check
;
;test_eopd:
; test hdlc0_data.copy_intflag,hdlc_intflag_eopd
; je test_rxoflw
; ; Its eopd so update stop_status_mask
; ; and change the maximum read to 19 (?)
; mov stop_status_mask,mask_k_good or mask_k_bad
; mov maximum_read,19 ;typically we end before this
;
;test_rxoflw:
; test hdlc0_data.copy_intflag,hdlc_intflag_rxoflw
; je test_rx1519
; ; Its Overflow so adjust minimum read number
; ; and change the maximum read to 19 (?)
; mov minimum_read,19
; mov maximum_read,19 ;typically we end before this
; jmp test_rx_end ;can avoid the rx1519 check
;
;test_rx1519:
; test hdlc0_data.copy_intflag,hdlc_intflag_rx1519
; je test_rx_end
; ; Its Rx1519 so adjust the minimum read number
; mov minimum_read,14
;
test_rx_end:
;
;WE DONT CARE WHAT CAUSED THE INTERRUPT NOW!
;
; Now we call the routine to process the RX fifo having
; hopefully set up all the correct conditions.
call rint_process
test_tint:
mov al,hdlc0_data.copy_intflag
and al,hdlc0_data.copy_intenable ; ignore any not expected
mov hdlc0_data.copy_intflag,al
test hdlc0_data.copy_intflag,hdlc_intflag_txdone or hdlc_intflag_tx419 or hdlc_intflag_txurun
je test_ga ;No transmit style interrupts so jump
; Its some sort of transmit event
test hdlc0_data.copy_intflag,hdlc_intflag_txurun
je test_txdone
call tint_txurun; its an underrun event
; Now need to avoid the txdone and tx419 code etc ....
jmp test_ga
test_txdone:
test hdlc0_data.copy_intflag,hdlc_intflag_txdone
je test_tx419
call tint_txdone; its packet trans. complete event
jmp test_ga ; NOTE tx419 will always be set
;when txdone is set! As we have processed
;the outgoing packet we must now NOT go
;through the tx419 code as well! IMPORTANT!
test_tx419:
test hdlc0_data.copy_intflag,hdlc_intflag_tx419
je test_ga
call tint_tx419; its a tx fifo low event
; and carry on...
test_ga:
test hdlc0_data.copy_intflag,hdlc_intflag_ga
je int_fin
; Its a Go-ahead .. We should not get these..
pr_ch_al '-'
int_fin:
; Now we have finished.. Just output H so we can check
ret
;
;Process 8952 Receive interrupts
;
; Process all RX FIFO data
rint_process:
; pr_ch_al 'A'
; mov number_read,0 ;none so far...
; mov rint_status_mask,0 ;clear the rint status mask
movseg es,ds
rint_loop:
; NEED FIXES IN HERE
; mov al,number_read
; cmp maximum_read,al ;check if data still due
; jg rint_some_due ;yes there is
; pr_ch_al 'B'
; ret ;no we have finished
;rint_some_due:
;get fifo status and build into a mask
;must first check that there is still some data left..
; NOTE it is important that we dont get here less than
; one microsecond after we last removed data.
in_chip_reg board_w_hdlc0,hdlc_br_fifostatus
test al,hdlc_fifostatus_RXFIFO
jne rint_fifo_not_empty
ret ; we have now emptied the RX FIFO
; so we return...
rint_fifo_not_empty: ;still some data so analyze...
mov cl,6 ;number of bits to shift
and al,hdlc_fifostatus_RXBYTE ;get RX byte status
shr al,cl ;shift to lower two bits
mov cl,al ;transfer to cl
mov al,00000001b ;set low bit in al
shl al,cl ;and shift to correct bit for mask
mov byte_status_mask,al ;save byte status mask
; or rint_status_mask,al ;save rint segment status mask
;
; Now check our state
;
test hdlc0_data.rxisr_w_state,state_k_skipping
jz rint_building ;must be building alone
jmp rint_skipping ;skipping or skipping&building
;
; Definitely building a packet
;
rint_building:
test byte_status_mask,mask_k_good;good last byte ?
jnz rint_build_good_last ;deal with good last byte
test byte_status_mask,mask_k_bad;bad last byte ?
jnz rint_build_bad_last ;deal with bad last byte
test byte_status_mask,mask_k_first;first byte ?
jnz rint_build_first ;deal with first byte
;
; must be packet byte
;
in_chip_reg board_w_hdlc0,hdlc_br_receive
mov di,hdlc0_data.rxisr_w_byte ;get ptr to next byte
stosb ;store char into buffer
mov hdlc0_data.rxisr_w_byte,di ;save ptr to next byte
inc hdlc0_data.rxisr_w_count ;count for all isr calls
; inc number_read ;count for this isr
jmp rint_end
rint_build_good_last:
;
; good last byte coming, get it, then close
; the packet and assign it to queue ownership etc.
; then bump the pointers
;
; pr_ch_al 'C'
in_chip_reg board_w_hdlc0,hdlc_br_receive
mov di,hdlc0_data.rxisr_w_byte ;get ptr to next byte
stosb ;store char into buffer
mov hdlc0_data.rxisr_w_byte,di ;save ptr to next byte
inc hdlc0_data.rxisr_w_count ;count for all isr calls
; inc number_read ;count for this isr
mov bx,hdlc0_data.rxisr_w_pkt ;get pointer to buffer
mov ax,hdlc0_data.rxisr_w_count ;save count in buffer
mov [bx].buff_w_size,ax ;via ax
mov [bx].buff_w_owner,owner_k_queue ;mark in q
mov bx,[bx].buff_w_next ;get pointer to next
mov hdlc0_data.rxq_w_back,bx ;and save as back of queue
;
; and change state
;
mov hdlc0_data.rxisr_w_state,state_k_skipping
jmp rint_end
rint_build_bad_last:
;
; Now deal with bad FCS, read the bad byte and then
; then discard the packet we have got so far.
;
pr_ch_al 'D'
in_chip_reg board_w_hdlc0,hdlc_br_receive
;get char but ignore
; inc number_read ;count for this isr
mov bx,hdlc0_data.rxisr_w_pkt ;get ptr to buffer
call rint_reset ;release the buffer etc
;
; and change state
;
mov hdlc0_data.rxisr_w_state,state_k_skipping
jmp rint_end
rint_build_first:
;
; Now deal with first byte, this must be a frame abort!
; DONT read the byte, leave it there for next iteration
; to use as part of the next packet.
; Discard the packet we have got so far.
;
pr_ch_al 'E'
mov bx,hdlc0_data.rxisr_w_pkt ;get ptr to buffer
call rint_reset ;release the buffer etc
;
; Record the Frame Abort in the rint_status_mask
;
; or rint_status_mask,mask_k_fabort
;
; and change state
;
mov hdlc0_data.rxisr_w_state,state_k_skipping
jmp rint_end
rint_skipping:
;
; If we are here then we must be in between packets.
; It is possible that we may have run out of buffers
; so we may be actually discarding data that would
; otherwise have been good. If this second situation
; exists then both the building and skipping bits
; are set in the state mask.
;
test byte_status_mask,mask_k_good;good last byte ?
jnz rint_skip_good_last ;deal with good last byte
test byte_status_mask,mask_k_bad;bad last byte ?
jnz rint_skip_bad_last ;deal with bad last byte
test byte_status_mask,mask_k_first;first byte ?
jnz rint_skip_first ;deal with first byte
;
; must be packet byte
;
in_chip_reg board_w_hdlc0,hdlc_br_receive
;get char but ignore
; inc number_read ;count for this isr
;
; Well we are certainly skipping past bytes now.
;
mov hdlc0_data.rxisr_w_state,state_k_skipping or state_k_building
jmp rint_end
rint_skip_good_last:
;
; good last byte coming, get it, and ignore
;
pr_ch_al 'F'
in_chip_reg board_w_hdlc0,hdlc_br_receive
;get char but ignore
; inc number_read ;count for this isr
;
; change state (might have been skipping and building)
;
mov hdlc0_data.rxisr_w_state,state_k_skipping
jmp rint_end
rint_skip_bad_last:
;
; Now deal with bad FCS, read the bad byte and ignore
;
pr_ch_al 'G'
in_chip_reg board_w_hdlc0,hdlc_br_receive
;get char but ignore
; inc number_read ;count for this isr
;
; change state (might have been skipping and building)
;
mov hdlc0_data.rxisr_w_state,state_k_skipping
jmp rint_end
rint_skip_first:
;
; Now deal with first byte, this must be the start
; of the next packet.
;
test hdlc0_data.rxisr_w_state,state_k_building
jnz rint_skip_build ;skipping&building
;
; As we are here we are just skipping at the moment.
; As we have found a first byte, we now try to
; get a buffer in which to build the new packet.
;
call rint_get_buffer
jnc rint_skip_first_got_buffer
;
; We failed to get buffer. We thus must discard
; the incoming data, count it and move to the
; skipping&building state.
;
pr_ch_al 'H'
in_chip_reg board_w_hdlc0,hdlc_br_receive
;get char but ignore
; inc number_read ;count for this isr
;
; and change state
;
mov hdlc0_data.rxisr_w_state,state_k_skipping or state_k_building
jmp rint_end
rint_skip_first_got_buffer:
; pr_ch_al 'I'
in_chip_reg board_w_hdlc0,hdlc_br_receive
mov di,hdlc0_data.rxisr_w_byte ;get ptr to next byte
stosb ;store char into buffer
mov hdlc0_data.rxisr_w_byte,di ;save ptr to next byte
inc hdlc0_data.rxisr_w_count ;count for all isr calls
; inc number_read ;count for this isr
;
; and change state
;
mov hdlc0_data.rxisr_w_state,state_k_building
jmp rint_end
rint_skip_build:
;
; We are skipping and building. I.e. we are
; discarding data that probably would have been
; good but we had no buffers available.
; Thus if we find a first byte this must be a frame
; abort. Deal with it as such, leaving the byte in
; the FIFO to be picked up on the next cycle.
;
; Record the Frame Abort in the rint_status_mask
;
pr_ch_al 'J'
; or rint_status_mask,mask_k_fabort
;
; and change state
;
mov hdlc0_data.rxisr_w_state,state_k_skipping
jmp rint_end
rint_end:
;
; Now is the time to tidy up at the end of
; the rint loop. Several things to check. For instance,
; if we are still building and not skipping then
; if the packet is already full we have a problem.
; The best policy must be to discard and move
; to skipping&building state.
;
; We must also check if we need to stop iterating.
; If we have not yet read the minimum_read number
; of bytes we must go again. If we have, then
; unless we have got a rint_status_mask that has
; at least one bit in common with our stop_status_mask
; we must also loop again.
test hdlc0_data.rxisr_w_state,state_k_skipping
jnz rint_info_size_ok ;dont care...
cmp hdlc0_data.rxisr_w_count,info_k_size ;check if room for more info
jl rint_info_size_ok ;and branch if ok
;
; TOO much data in this packet, the next byte
; even if it were a last byte would overfill
; the info area. We must therefore discard the packet
; and move to the skipping&building state.
pr_ch_al 'K'
mov bx,hdlc0_data.rxisr_w_pkt ;get ptr to buffer
call rint_reset ;release the buffer etc
;
; and change state
;
mov hdlc0_data.rxisr_w_state,state_k_skipping or state_k_building
rint_info_size_ok:
; mov al,number_read
; cmp minimum_read,al ;have we read enough?
; jle rint_enough ;yes
jmp rint_loop ; no go read some more..
;rint_enough:
; mov al,stop_status_mask
; test rint_status_mask,al ;stop state?
; jnz rint_stop_state ;yes
; jmp rint_loop ; no go read some more..
;rint_stop_state:
;
; Well that seems to be it for this call to the RX
; interrupt service routine so bye bye...
; ret
;
; Routine to get a buffer (or not)
;
rint_get_buffer:
; pr_ch_al 'L'
mov bx,hdlc0_data.rxq_w_back ;get back of queue
cmp [bx].buff_w_owner,owner_k_empty ;is it empty?
jne cant_get_buffer
call rint_grab
clc ;all o.k.
ret
cant_get_buffer:
pr_ch_al 'M'
stc ;signal error (well at least no buffers left)
ret
rint_grab:
or bx,bx
jz rint_grab_problem
mov [bx].buff_w_owner,owner_k_isr ;mark inuse by isr
mov hdlc0_data.rxisr_w_pkt,bx ;save for isr to use next
lea ax,[bx].buff_info ;get address of new info area
mov hdlc0_data.rxisr_w_byte,ax ;save for isr
mov hdlc0_data.rxisr_w_count,0 ;and clear count
; Now set the state to mark as BUILDING
mov hdlc0_data.rxisr_w_state,state_k_building
clc
ret
rint_grab_problem:
pr_ch_al 'N'
stc
ret
rint_reset:
or bx,bx
jz rint_reset_problem
mov [bx].buff_w_owner,owner_k_empty ;mark empty
clc
ret
rint_reset_problem:
pr_ch_al 'O'
stc
ret
; --------------------------------------------------------------
;
; recv_exiting
;
recv_exiting:
assume ds:nothing
pushf
push ax
push bx
mov bx,hdlc0_data.rxq_w_front ;get pointer to next buffer
cmp code:[bx].buff_w_owner,owner_k_queue ;belongs to q?
jne recv_exiting_done ; no - skip to end
push cx
push dx
push ds
push es
push bp
push di
push si
movseg ds,cs
assume ds:code
cmp hdlc0_data.rxupcall_w_state,upcall_k_idle ;is receive frame already active?
jne already_active ;frame will be caught so jump
mov hdlc0_data.rxupcall_w_state,upcall_k_active ;else mark recv_frame starting
sti ; enable interrupts
call recv_frame
cli
already_active:
pop si
pop di
pop bp
pop es
pop ds
pop dx
pop cx
recv_exiting_done:
pop bx
pop ax
jmp recv_exiting_exit
; --------------------------------------------------------------
;
; recv_frame
;
ifdef debug
public recv_frame
endif
recv_frame:
; pr_ch_al 'P'
mov bx,hdlc0_data.rxq_w_front ;get pointer to next buffer
recv_frame_2:
lea si,[bx].buff_info ;point to data
mov cx,[bx].buff_w_size ;get its size
jcxz recv_frame_3 ;count zero? yes,just free frame.
;we don't need to set the type because none are defined for our HDLC encoding.
push si ;save si in case we reject it.
push bx
mov di,0 ;but we avoid any segment end bullshit.
mov dl,cs:driver_class
call recv_find ;look up our type.
pop bx
pop si
mov ax,es ;is this pointer null?
or ax,di
je recv_frame_3 ;yes - just free the frame.
; pr_ch_al 'Q'
push cx
push es ;remember where the buffer pointer is.
push di
rep movsb ;and copy our packet into users buffer
pop si ;now give the frame to the client.
pop ds
pop cx
; pr_ch_al 'R'
assume ds:nothing
call recv_copy
movseg ds,cs
pr_ch_al 'S'
assume ds:code
recv_frame_3:
mov [bx].buff_w_owner,owner_k_empty ;free the buffer
mov bx,[bx].buff_w_next ;get pointer to next
mov hdlc0_data.rxq_w_front,bx ;adjust front of q
cmp [bx].buff_w_owner,owner_k_queue ;belongs to q?
je recv_frame_2 ; yes so process this one.
mov hdlc0_data.rxupcall_w_state,upcall_k_idle ;else mark recv_frame as inactive
; pr_ch_al 'T'
ret
;Handle 8952 transmitter interrupts
; --------------------------------------------------------------
tint_txurun:
pr_ch_al 'd'
mov bx,hdlc0_data.txisr_w_pkt ;point to the packet buffer
call tint_reset ;reset pointers etc...
ret
tint_tx419:
;
; - for MT8952B fifo stuff up to 15 chars at a time
;
; NOW NEED TO POINT DX at TX FIFO
;
mov dx,board_w_hdlc0 ;make dx point at transmit fifo
add dx,hdlc_bw_transmit
mov cx,15 ;fifo fill-loop counter
mov bx,hdlc0_data.txisr_w_count ;get count of bytes left
mov si,hdlc0_data.txisr_w_byte ;get pointer to next byte
tint_next:
lodsb ;fetch next char
dec bx ;reduce count of remaining bytes
jne not_send_last
push dx ;save dx
mov dx,board_w_hdlc0
add dx,hdlc_b_control
push ax
in al,dx ;get current hdlc control reg
or al,hdlc_control_eop ;mark as end of packet
out dx,al ;and tell the 8952
pop ax ; restore al
pop dx ;and dx
not_send_last:
out dx,al ;output char
or bx,bx ;any more chars to output
je tint_no_more ;none...
loop tint_next ;loop while fifo not full
;
; Still some more so select TXURUN and TX419 ints enabled
;
pr_ch_al 'e'
mov dx,board_w_hdlc0
add dx,hdlc_bw_intenable
; in al,dx ;get current hdlc intenable
mov al,hdlc0_data.copy_intenable
;
; switch off txdone interrupt and enable tx419 and txurun
;
and al,not hdlc_intenable_txdone
or al,hdlc_intenable_tx419 or hdlc_intenable_txurun
out dx,al ;and tell the 8952
mov hdlc0_data.copy_intenable,al ;and save it
mov hdlc0_data.txisr_w_count,bx ;save count of bytes left
mov hdlc0_data.txisr_w_byte,si ;save pointer to next byte
clc ;clear carry, all ok
ret ;and exit
tint_no_more:
;
; No more so select TXDONE and TXURUN ints enabled only
;
pr_ch_al 'f'
mov dx,board_w_hdlc0
add dx,hdlc_bw_intenable
; in al,dx ;get current hdlc intenable
mov al,hdlc0_data.copy_intenable
;
; switch off tx419 interrupt and enable txurun and txdone
;
and al,not hdlc_intenable_tx419
or al,hdlc_intenable_txdone or hdlc_intenable_txurun
out dx,al ;and tell the 8952
mov hdlc0_data.copy_intenable,al ;and save it
mov hdlc0_data.txisr_w_count,bx ;save count of bytes left
mov hdlc0_data.txisr_w_byte,si ;save pointer to next byte
clc ;clear carry if all ok
ret ;and exit
;No more characters to transmit -- disable transmit interrupts.
tint_txdone:
; pr_ch_al 'g'
mov bx,hdlc0_data.txisr_w_pkt ;get pointer to isrs pkt
or bx,bx ;check if pkt pointer is 0
je tint_skip
mov [bx].buff_w_owner,owner_k_empty;set owned by empty
tint_skip:
call tint_new ;try to move to next buffer
jc tint_all_empty ;if carry set then none left
clc
ret
tint_all_empty:
;
; No more so set all tx ints off
;
; pr_ch_al 'h'
mov dx,board_w_hdlc0
add dx,hdlc_bw_intenable
; in al,dx ;get current hdlc intenable
mov al,hdlc0_data.copy_intenable
;
; switch off tx419, txurun and txdone
;
and al,not (hdlc_intenable_tx419 or hdlc_intenable_txdone or hdlc_intenable_txurun)
out dx,al ;and tell the 8952
mov hdlc0_data.copy_intenable,al ;and save it
xor ax,ax ;clear ax
mov hdlc0_data.txisr_w_pkt,ax ;save in pointer to buffer
ret
;
; Routine to get info for next packet from queue
;
tint_new:
mov bx,hdlc0_data.txq_w_front ;get pointer to front of queue
cmp [bx].buff_w_owner,owner_k_queue ;belongs to q?
jne tint_no_buffers_in_queue
;
; now bump the front of queue
;
pr_ch_al 'i'
mov ax,[bx].buff_w_next ;point to buffer
mov hdlc0_data.txq_w_front,ax ;adjust front of queue
;
call tint_reset ;and set the pointers etc.
ret
tint_reset:
or bx,bx
jz tint_reset_problem
mov [bx].buff_w_owner,owner_k_isr;set owned by the isr
mov ax,[bx].buff_w_size ;get size of data unit
mov hdlc0_data.txisr_w_count,ax ;and save it for us
mov hdlc0_data.txisr_w_pkt,bx ;save pointer to buffer
lea ax,[bx].buff_info ;get address of data unit
mov hdlc0_data.txisr_w_byte,ax ;and save for us
call tint_tx419 ;and pretend we had a tx419
ret
tint_reset_problem:
stc
ret
tint_no_buffers_in_queue:
pr_ch_al 'j'
stc ;set carry - could not do it
ret
;Set bit(s) in I/O port
setbit:
;enter with dx = port, ah = bit to set.
in al,dx
or al,ah
out dx,al
ret
;Clear bit(s) in I/O port
clrbit:
;enter with dx = port, ah = bit to set.
in al,dx
not al ;perform an and-not using DeMorgan's.
or al,ah
not al
out dx,al
ret
;
; Now define some buffers for the rings.
; Do it statically now because its easier.
;
; First the transmit ring
;
t1_buff buff <offset t8_buff, offset t2_buff>
t2_buff buff <offset t1_buff, offset t3_buff>
t3_buff buff <offset t2_buff, offset t4_buff>
t4_buff buff <offset t3_buff, offset t5_buff>
t5_buff buff <offset t4_buff, offset t6_buff>
t6_buff buff <offset t5_buff, offset t7_buff>
t7_buff buff <offset t6_buff, offset t8_buff>
t8_buff buff <offset t7_buff, offset t1_buff>
;
; Now the Receive ring
;
r1_buff buff <offset r8_buff, offset r2_buff>
r2_buff buff <offset r1_buff, offset r3_buff>
r3_buff buff <offset r2_buff, offset r4_buff>
r4_buff buff <offset r3_buff, offset r5_buff>
r5_buff buff <offset r4_buff, offset r6_buff>
r6_buff buff <offset r5_buff, offset r7_buff>
r7_buff buff <offset r6_buff, offset r8_buff>
r8_buff buff <offset r7_buff, offset r1_buff>
;
; include the serial trace output subroutines
;
include popf.asm
include sersub.asm
public timer_isr
timer_isr:
;if the first instruction is an iret, then the timer is not hooked
iret
;any code after this will not be kept after initialization. Buffers
;used by the program, if any, are allocated from the memory between
;end_resident and end_free_mem.
public end_resident,end_free_mem
end_resident label byte
end_free_mem label byte
public usage_msg
usage_msg db "usage: EXPRESS <packet_int_no> [-n] [driver_class] [hardware_irq] ",CR,LF
db " -n instructs card to be an NT",CR,LF
db " The driver_class should be SLIP or a number.",CR,LF,'$'
public copyright_msg
copyright_msg db "Packet driver for MITEL EXPRESS CARD, version ",'0'+(majver / 10),'0'+(majver mod 10),".",'0'+version,CR,LF
db "Portions Copyright 1988 Phil Karn",CR,LF
db "ISDN bits by Dave Price and Bob Gautier",CR,LF,'$'
class_name_ptr dw ?
class_name db "Interface class ",'$'
slip_name db "SLIP",CR,LF,'$'
int_no_name db "Interrupt number ",'$'
express_start db "starting to initial EXPRESS card",CR,LF,'$'
express_finish db "completed initialization of EXPRESS card",CR,LF,'$'
extrn set_recv_isr: near
;enter with si -> argument string, di -> word to store.
;if there is no number, don't change the number.
extrn get_number: near
;enter with dx -> name of word, di -> dword to print.
extrn print_number: near
;enter with si -> argument string.
;skip spaces and tabs. Exit with si -> first non-blank char.
extrn skip_blanks: near
public parse_args
parse_args:
;exit with nc if all went well, cy otherwise.
call skip_blanks
cmp al,'-' ;did they specify a switch?
jne not_switch
;
; Only SUPPORT -n SWITCH ARGUMENT AT THE MOMENT
;
cmp byte ptr [si+1],'n' ;did they specify '-n'?
je got_NT_switch
stc ;no, must be an error.
ret
got_NT_switch:
mov NT_switch,1
add si,2 ;skip past the switch's characters.
jmp parse_args ;go parse more arguments.
not_switch:
or al,20h ;convert to lower case (assuming letter).
parse_args_2:
cmp al,'s'
jne parse_args_3
mov driver_class,6 ;SLIP, from packet spec.
mov dx,offset slip_name
jmp short parse_args_1
parse_args_3:
mov di,offset driver_class
call get_number
mov class_name_ptr,0
jmp short parse_args_6
parse_args_1:
mov class_name_ptr,dx
parse_args_5:
mov al,[si] ;skip to the next blank or CR.
cmp al,' '
je parse_args_6
cmp al,CR
je parse_args_6
inc si ;skip the character.
jmp parse_args_5
parse_args_6:
mov di,offset int_no
call get_number
;
; Might get number of buffer in TX queue here.
;
clc
ret
; --------------------------------------------------------------
;
; etopen
;
public etopen
etopen:
pushf
cli
call open ; open the serial port for traces
;let user know we are about to initial
; the express card
pr_ch_al '$'
;
;Now set up the Mitel Express Card
;
;
; First the dphone - this controls timing as well
;
out_chip_reg_value board_w_dphone,dphone_b_test,dphone_test_disable
;
; Now the board timing via the dphone sense/drive port
;
out_chip_reg_value board_w_dphone,dphone_b_sddir,dphone_sddir_allout
cmp NT_switch,1 ;has user selected NT operation
jne act_as_te ;no so set as TE
out_chip_reg_value board_w_dphone,dphone_b_sddata,dphone_sddata_nt
jmp te_nt_set
act_as_te:
out_chip_reg_value board_w_dphone,dphone_b_sddata,dphone_sddata_te
te_nt_set:
;
; Now set use of st-bus timeslots
;
out_chip_reg_value board_w_dphone,dphone_b_time,<dphone_time_c or dphone_time_pcmb1>
;
; Now stop the watchdog
;
out_chip_reg_value board_w_dphone,dphone_b_wdog,0
;
; Now set the tone values
;
out_chip_reg_value board_w_dphone,dphone_b_tone1,dphone_tone_697
out_chip_reg_value board_w_dphone,dphone_b_tone2,dphone_tone_1209
;
; Now set up the dsp
;
out_chip_reg_value board_w_dphone,dphone_b_dsp,<dphone_dsp_cpcmen or dphone_dsp_dpcmen or dphone_dsp_dual>
;
; Now set up the transducers
;
out_chip_reg_value board_w_dphone,dphone_b_trans,<dphone_trans_side or dphone_trans_hsmic or dphone_trans_hsskr>
;
; Finally the Receive gain control
;
out_chip_reg_value board_w_dphone,dphone_b_rgain,dphone_rgain_rfg_m7
;
; Second the snic
;
out_chip_reg_value board_w_snic,snic_b_master,<snic_master_cstenable or snic_master_msdisable or snic_master_irqenable>
out_chip_reg_value board_w_snic,snic_b_stbus,snic_stbus_all
;
; Now set up the hdlc controller
;
out_chip_reg_value board_w_hdlc0,hdlc_b_time,hdlc_time_rst
;
; NOTE you are required to clear reset TWICE
;
out_chip_reg_value board_w_hdlc0,hdlc_b_time,<hdlc_time_ic or hdlc_time_brck or hdlc_time_c2bits8>
out_chip_reg_value board_w_hdlc0,hdlc_b_time,<hdlc_time_ic or hdlc_time_brck or hdlc_time_c2bits8>
out_chip_reg_value board_w_hdlc0,hdlc_b_control,<hdlc_control_rxen or hdlc_control_txen>
out_chip_reg_value board_w_hdlc0,hdlc_b_raddress,00
out_chip_reg_value board_w_hdlc0,hdlc_bw_wdog,00
out_chip_reg_value board_w_hdlc0,hdlc_bw_intenable,<hdlc_intenable_eopd or hdlc_intenable_fa or hdlc_intenable_rx1519 or hdlc_intenable_rxoflw>
mov hdlc0_data.copy_intenable,al ;and save it
;
; Now the DX; plug up the channels and send messages etc,
;
dx_source snic_stream,snic_b2_channel,dphone_stream,dphone_b1_channel
dx_source dphone_stream,dphone_b1_channel,snic_stream,snic_b2_channel
dx_source snic_stream,snic_b1_channel,hdlc_stream,hdlc_b1_channel
dx_source hdlc_stream,hdlc_b1_channel,snic_stream,snic_b1_channel
;
; MIGHT NEED TO CHANGE THE NEXT FOR NT OPERATION
;
dx_message snic_stream,snic_c_channel,<<snic_c_ar or snic_c_clrdia>>
;let user know we have finished
; initializing the express card
pr_ch_al '%'
;Set interrupt vector to EXPRESS handler
call set_recv_isr
popf
clc ;indicate no errors.
ret
public print_parameters
print_parameters:
cmp class_name_ptr,0
je echo_args_1
mov dx,offset class_name
mov ah,9
int 21h
mov dx,class_name_ptr
mov ah,9
int 21h
jmp short echo_args_2
echo_args_1:
mov di,offset driver_class
mov dx,offset class_name
call print_number
echo_args_2:
mov di,offset int_no
mov dx,offset int_no_name
call print_number
ret
code ends
end