;COM2/DVR - LDOS 6.2 - 01/03/84 - Mod II ; TITLE '' ;*=*=* ; Change Log ; ; 02/23/83 - Changed wakeup vectoring to return: ; C = character, if available ; A = STATUS port image ; Z = character received ; 05/20/83 - relocate to HIGH$ if no room in driver area ; 05/25/83 - fixed SFLAG calculation to pt to SFLAG ; ;*=*=* INTVC$ EQU 03EH ;interrupt table RSSERVA EQU INTVC$+4 ;receive serviceA address RSSERVB EQU INTVC$+6 ;receive serviceB address $CTC0 EQU 0F0H ;counter-timer-controller $CTC1 EQU 0F1H $CTC2 EQU 0F2H $CTCX EQU 000H ;dummy for channel B $SIOA EQU 0F6H ;SIOA base port $SIOB EQU 0F7H ;SIOB base port ; ETX EQU 03 LF EQU 10 CR EQU 13 *GET COPYCOM:3 *GET SVCMAC:3 ; SUBTTL '' ; ORG 2400H BEGIN PUSH DE ;Save DCT address POP IX ; in index reg LD (CLDCB),DE ;Stuff prologue ; ; check if user specified port address ; CKSTR LD A,(HL) ;get input INC HL ;bump pointer CP ' ' ;nil? JR Z,CKSTR ;yes, ignore them CP 0DH ;carriage return? JR Z,USENAME ;port from name CP '(' ;param start? JP NZ,PRMERR ;param error if not! DEC HL ;correct pointer LD DE,PRMTBL ;parameter table @@PARAM ;evaluate params JP NZ,PRMERR ;go if error! LD A,(PRESP) ;get response byte OR A ;anything? JR Z,USENAME ;nope, use name for port LD DE,(PDATA) ;get input INC D ;check msb DEC D ;D<>0? JP NZ,PRMERR ;go if >256! LD A,E ;get lsb OR A ;0? JP Z,PRMERR ;port=0? CP 3 ;1/2? JP NC,PRMERR ;go if wrong JR BEG0 ;continue ; ; use device name to specify port ; USENAME LD A,(IX+7) ;get last char name CP ' ' ;last char blank? JR NZ,BEG0 ;go if not LD A,(IX+6) ;else fetch first char BEG0 AND 1 ;use char as address ; ; fetch hardware address' for SIO ports ; LD BC,RSSERVA ;interrupt vector address LD DE,$CTC0<8+$CTC1 ;CTC ports LD HL,'L'<8+$SIOA ;ID + base port JR NZ,BEG1 ;go if one ; LD BC,RSSERVB ;interrupt vector LD DE,$CTC2<8+$CTCX ;CTC ports LD HL,'M'<8+$SIOB ;ID + base port ; BEG1 LD (INTVC),BC ;save vector LD A,H ;get ascii ID LD (MODNAME),A ;save module name postfix LD (MODNAM2),A ;save into prefix LD A,L ;get base port LD (BASPORT),A ;save into data table LD (CTCPORT),DE ;save CTC ports ; @@DSPLY HELLO$ ;Welcome the user ;*=*=* ; Check if entry from SET command ;*=*=* @@FLAGS BIT 3,(IY+'C'-'A') ;System request? JP Z,VIASET ;nope, abort ;*=*=* ; Grab system dependent vectors ;*=*=* PUSH IY ;pass @FLAGS to DE POP DE ;DE => @FLAGS LD HL,'K'-'A' ;Kflag$ offset ADD HL,DE ;HL => KFLAG$ LD (KFLAG),HL ;save for quick test LD HL,'S'-'A' ;SFLAG$ offset ADD HL,DE ;HL => SFLAG$ LD (SFLAG),HL ;save for quick test ;*=*=* ; Move @ICNFG vector into driver ;*=*=* LD A,(IY+28) ;Get opcode prefix LD (LINK),A ;save link prefix LD L,(IY+29) ;Get address LD H,(IY+30) LD (LINK+1),HL ;save link address ;*=*=* ; Check if driver alread resident ;*=*=* LD DE,CL$ ;Check if filter is @@GTMOD ; already resident EX DE,HL ;Put DCB ptr to HL JR NZ,NOTRES ;GM if not ;*=*=* ; Make sure that the new DCB is same as the old ;*=*=* LD C,(HL) ;P/u DCB pointer LSB INC HL LD B,(HL) ;P/u DCB pointer MSB LD HL,6 ;Get old DCB name & ADD HL,BC ; stuff into error LD A,(HL) ; message in case INC HL ; a different DCB LD H,(HL) ; is referenced LD L,A LD (DCBNAM$),HL ;Stuff message with spec LD HL,(CLDCB) ;P/u DCB existing DCB OR A ; pointer SBC HL,BC ;Same DCB pointer? JP NZ,DCBERR ;Can't install if diff JP ISRES ;else driver resident ; ; install new driver, attempt to place low ; NOTRES LD DE,'IK' ;*KI device @@GTDCB ;Locate low memory ptr JP NZ,IOERR ;go if not found ; ; locate current pointer to low modules ; DEC HL ;right before keyboard LD D,(HL) ;load MSB DEC HL ;dec pointer LD E,(HL) ;load LSB LD (LCPTR+1),HL ;Save ptr for later LD HL,CLEND-CLDVR-1 ;driver length ADD HL,DE ;Start + driver length LD (SVEND+1),HL ;save new low pointer LD BC,1300H ;Max addr + 1 XOR A ;clear carry SBC HL,BC ;test if room to add low JR C,PUTLOW ;yes, go! ;*=*=* ; check if high memory available ;*=*=* BIT 0,(IY+'C'-'A') ;Memory frozen? JP NZ,NOROOM ;Can't fit in low core! LD HL,0 ;init for fetch LD B,L ;Get HIGH$ @@HIGH$ LD (SVEND+1),HL ;Top of driver OR A ;clear carry LD BC,CLEND-CLDVR ;Minus length SBC HL,BC ;new high memory LD B,0 ;init high$ PUSH HL ;save @@HIGH$ ;Is new HIGH$ POP HL ;restore new location INC HL ;Plus one is start LD (HCPTR),HL ;Save it LD HL,HCPTR ;And point to it LD (LCPTR+1),HL LD A,0FFH ;flag himem used LD (HGHFLG),A ;save flag ;*=*=* ; Relocate internal references in driver ;*=*=* PUTLOW PUSH IX ;save driver pointer LD IX,RELTAB ;Point to relocation tbl SVEND LD HL,$-$ ;Find distance to move LD (CLDVR+2),HL ;Set last byte used LD DE,CLEND-1 ;end -1 OR A ;Clear carry flag SBC HL,DE ;adjust address LD B,H ;Move to BC LD C,L ; RLOOP LD L,(IX) ;Get address to change LD H,(IX+1) LD A,H ;check for term OR L ;=0000? JR Z,RELEND ;yes, go! LD A,(HL) ;get LSB address ADD A,C ;add lsb offset LD (HL),A ;update INC HL ;bump table LD A,(HL) ;get MSB address ADC A,B ;add msb offset LD (HL),A ;update INC IX ;bump relo table INC IX ;2 bytes each JR RLOOP ;go next value ; RELEND POP IX ;Restore DCB ;*=*=* ; Set up @ICNFG ;*=*=* LD HL,INIT ;Get (relocated) RX01 EQU $-2 LD (IY+29),L ; init address LD (IY+30),H LD A,0C3H ;Get JP instruction LD (IY+28),A ;*=*=* ; Move driver ;*=*=* LCPTR LD HL,$-$ ;Low core pointer LD E,(HL) INC HL LD D,(HL) PUSH DE ;Save start LD HL,CLDVR LD BC,CLEND-CLDVR ;Calc driver length LDIR ;move to new address LD HL,(LCPTR+1) LD (HL),E INC HL LD (HL),D ;*=*=* ; Initialize the driver ;*=*=* PUSH IX ;save CALL INIT ;init device RX02 EQU $-2 POP IX ;restore ; POP DE ;Pop filter start ; ISRES LD HL,CLACT$ ;Advise COM/DVR installed LD (IX),7 ;Init DCB type to "C/P/G" LD (IX+1),E ; & stuff the driver LD (IX+2),D ; address @@LOGOT ;display message LD A,$-$ ;did it use high memory? HGHFLG EQU $-1 OR A ;nz if high JR Z,NTHGH ;go if went low LD HL,HMEM$ ;message @@LOGOT ;display NTHGH LD HL,0 ;clear error code RET ;exit ;*=*=* ; Error exits ;*=*=* PRMERR LD HL,PRMERR$ ;'parameter error' DB 0DDH VIASET LD HL,VIASET$ ;'must install via SET' DB 0DDH DCBERR LD HL,DCBERR$ ;'driver already attached DB 0DDH NOROOM LD HL,NOROOM$ ;'no memory available' @@LOGOT LD HL,-1 ;set error exit RET ;terminate IOERR LD L,A ;pass error code LD H,0 ;init to system error OR 0C0H ;set return + short LD C,A ;pass error code @@ERROR ;display and return RET ;now exit ;*=*=* ; Messages & Data tables ;*=*=* HCPTR DW 0 ;Save start if to HIGH$ CL$ DB '$C' ;device name MODNAME DB 'L',ETX ;device modifier ; HELLO$ DB 'COM' *GET CLIENT:3 ; NOROOM$ DB 'No memory space available',CR DCBERR$ DB 'Driver already attached to *xx',CR DCBNAM$ EQU $-3 CLACT$ DB 'COM driver is now resident',CR PRMERR$ DB 'Parameter error',CR VIASET$ DB 'Must install via SET',CR HMEM$ DB LF,'Note: ' DB 'driver installed in high memory',CR ; ; parameter table ; PRMTBL DB 80H ;extended params DB 4+90H ;length + numeric DM 'PORT' PRESP DB 0 ;response byte DW PDATA ;data address PDATA DW 0 ;response data here ; ; relocation table ; RELTAB DW RX01,RX02,RX03,RX04,RX05,RX06,RX07 DW RX08,RX09,RX10,RX11,RX12,RX13,RX14 DW RX15,RX16,RX17,RX18,RX19,RX20,RX21 DW RX22,RX23,RX24,RX25,0 ;*=*=* ; Actual driver ;*=*=* CLDVR EQU $ JR CLBGN ;Branch around linkage DW CLEND ;Last byte used DB 3,'$CL' MODNAM2 EQU $-1 CLDCB DW $-$ DW 0 CLDATA$ EQU $ MSMASK EQU $-CLDATA$ DB 0 ;*=*=* ; UART control port image ;*=*=* ; bit 7: 1 = even parity, 0 = odd parity ; bits 6,5: word length <00=5, 10=6, 01=7, 11=8> ; bit 4: 1 = 2 stop bits, 0 = 1 stop bit ; bit 3: 1 = disable parity, 0 = enable parity ; bit 2: 1 = enable transmit data, 0 = break ; bit 1: 0 = Data Terminal Ready ; bit 0: 0 = Request to Send ;*=*=* UCIMAGE EQU $-CLDATA$ DB 10100100B BAUD EQU $-CLDATA$ DB 55H ;Init 300 baud LOGBRK EQU $-CLDATA$ DB 3 ;Default is Control-C CLFLG EQU $-CLDATA$ DB 0 ;Init nG char in buf BPORT EQU $-CLDATA$ DB 0 ;base I/O port BASPORT EQU $-1 CTC2 EQU $-CLDATA$ ;CTC 1 DB 0 CTC1 EQU $-CLDATA$ ;CTC 2 DB 0 CTCPORT EQU $-2 CLBUF EQU $-CLDATA$ DB 0 ;One-char buffer R5MASK EQU $-CLDATA$ ;register 5 mask DB 0 WORD EQU $-CLDATA$ ;word length mask DB -1 ;8 bits ;*=*=* ; CL initialization routine. Set up DR interrupt ; vector & initialize the hardware ;*=*=* INIT LD HL,RECVINT ;receive address RX03 EQU $-2 LD ($-$),HL ;pass to interrupt vector INTVC EQU $-2 LD A,(INTVC$) ;LSB SIOA interrupt LD (ITABLE+11),A ;save address RX04 EQU $-2 ADD A,16 ;offset to SIOB interrupt LD (ITABLE+18),A ;save address RX05 EQU $-2 CALL CTL2 RX06 EQU $-2 LINK RET ;Link back DB 0,0 ; CLBGN LD IX,CLDATA$ ;Point tM data area RX07 EQU $-2 JP C,RECV ;Go if @GET request RX08 EQU $-2 JP Z,SEND ;Go if @PUT request RX09 EQU $-2 LD A,C ;P/U @CTL byte OR A ;@CTL 00 ? JP Z,CANISND ;Go if so RX10 EQU $-2 DEC A ;@CTL 01 ? JP Z,CTL1 ;Go if so RX11 EQU $-2 DEC A ;Was it CTL-2 "INIT UART" JR Z,CTL2 ;Go if so CP 4-2 ;Wakeup feature? JP Z,CTL4 ;Go if wakeup feature RX12 EQU $-2 XOR A RET ;*=*=* ; Initialize the UART & BRG ;*=*=* CTL2 PUSH IY ;save LD IY,ITABLE ;init table RX13 EQU $-2 LD IX,CLDATA$ ;start data table RX14 EQU $-2 ; ; init SIO/CTC port addresses ; LD A,(IX+BPORT) ;get base port LD (IY+2),A ;save into table LD A,(IX+CTC1) ;get CTC 1 port LD (IY+15),A ;save into table LD A,(IX+CTC2) ;get CTC 2 port LD (IY+20),A ;save into table ; ; init baud rate configuration ; LD A,(IX+BAUD) ;get baud rate AND 0FH ;low 4 bits ADD A,A ;2 byte table LD HL,BAUDTBL ;baud rate table RX15 EQU $-2 ADD A,L ;add to lsb LD L,A ;update lsb JR NC,$+3 ;go if no overflow INC H ;bump msb LD A,(HL) ;get counter select LD (IY+16),A ;RX baud LD (IY+21),A ;TX baud INC HL ;bump pointer LD A,(HL) ;get count LD (IY+17),A ;RX count LD (IY+22),A ;TX count ; ; init word length ; LD A,(IX+UCIMAGE) ;get image RLCA ;align bits 6,5 => 1,0 RLCA RLCA AND 3 ;low 2 bits JP PE,$+5 ;go if 5 or 8 RX16 EQU $-2 XOR 3 ;change 6/7 => 7/6 ADD A,5 ;add offset LD B,A ;init loop XOR A ;init word byte SIO1 SCF ;set bit RLA ;move into accum DJNZ SIO1 ;go for word length LD (IX+WORD),A ;save word length mask LD A,(IX+UCIMAGE) ;get config byte AND 60H ;bits 6/5 only OR 8 ;TX enable BIT 1,(IX+UCIMAGE) ;DTR? JR NZ,$+4 ;go if not OR 80H ;enable DTR BIT 0,(IX+UCIMAGE) ;RTS? JR NZ,$+4 ;go if not OR 02H ;enable RTS LD (IY+9),A ;DTR,TX enable,RTS,length LD (IX+R5MASK),A ;save for CTL calls RLCA ;align for RX OR 01H ;RX enable LD (IY+7),A ;save into RX table ; ; init parity ; LD A,40H ;parity mask BIT 3,(IX+UCIMAGE) ;enabled? JR NZ,SIO2 ;go if not SET 0,A ;set ODD BIT 7,(IX+UCIMAGE) ;odd? JR Z,SIO2 ;go if yes SET 1,A ;set EVEN SIO2 SET 2,A ;set 1 stop bit BIT 4,(IX+UCIMAGE) ;1/2? JR Z,$+4 ;go if one SET 3,A ;set 2 stop bits LD (IY+5),A ;update table ; ; send compiled init data to SIO ; LD HL,ITABLE ;get init table RX17 EQU $-2 CALL SNDDAT ;send data to chip RX18 EQU $-2 POP IY ;restore XOR A ;set no error RET ; ; init wake up feature ; CTL4 PUSH IY ;Transfer pointer to HL POP HL LD A,H ;Test if set or reset OR L LD A,0C9H ;Init disable wakeup EX DE,HL ;Switch new value to DE LD HL,(WAKEADR+1) ; & p/u old in HL RX19 EQU $-2 JR Z,SETWAK LD A,0C3H SETWAK LD (WAKEADR),A RX20 EQU $-2 LD (WAKEADR+1),DE RX21 EQU $-2 PUSH HL ;Transfer pointer to IY POP IY RET ;*=*=* ; Check if ready to send ;*=*=* CANISND LD C,(IX+BPORT) ;get SIO base port LD A,10H ;reset OUT (C),A ;reset ext IN A,(C) ;RR0 status CPL ;reverse status ADD A,A ;move bits 3/5 to 5/7 ADD A,A AND 10110000B ;keep DCD/CTS only BIT 4,A ;TX buffer empty? RET NZ ;go if not LD C,A ;save status XOR (IX+MSMASK) ;mask for flip RRA ;align to low RRA RRA RRA AND (IX+MSMASK) ;mask for which to check AND 0FH ;keep low 4 only LD A,C ;get back original status RET ;done ;*=*=* ; Send character ;*=*=* SEND PUSH BC ;save char LD A,C ;get char AND (IX+WORD) ;strip bits LD B,A ;save it SNDWT CALL CANISND ;Poll RX22 EQU $-2 JR NZ,SNDWT ; until ready CALL RESBRK ;reset break RX25 EQU $-2 LD C,(IX+BPORT) ;get base port DEC C ;point to data port DEC C OUT (C),B ;send data byte POP BC ;restore LD A,C ;restore char CP A ;set Z for OK RET ; unchanged for return ;*=*=* ; Receive character - Get from buffer if available ;*=*=* RECV BIT 7,(IX+CLFLG) ;char avail? JR NZ,HRECV ;have a char, go! OR -1 ;set NZ CPL ;but return 0 RET ;return NO char HRECV LD A,(IX+CLBUF) ;Get the char RES 7,(IX+CLFLG) ;set char fetched CP A ;Set Z-flag & exit RET ;*=*=* ; Break request ;*=*=* CTL1 LD C,(IX+BPORT) ;get base port LD A,5 ;R5 DI ;disable for send OUT (C),A ;select register LD A,(IX+R5MASK) ;get mask OR 10H ;set break bit OUT (C),A ;send break EI SET 6,(IX+CLFLG) ;show break sent RET ;With Z-flag ; ; reset break ; RESBRK BIT 6,(IX+CLFLG) ;break send prior? RET Z ;nope, go! ; LD C,(IX+BPORT) ;get base port LD A,5 ;R5 DI ;disable for select OUT (C),A ;select R5 LD A,(IX+R5MASK) ;get mask OUT (C),A ;terminate break EI ;done RES 6,(IX+CLFLG) ;reset break cleared RET ;return ;*=*=* ; Data received interrupt handler ;*=*=* RECVINT LD IX,CLDATA$ RX23 EQU $-2 LD C,(IX+BPORT) ;get base port IN B,(C) ;read R0 LD A,10H ;channel reset OUT (C),A ;reset BIT 7,B ;break here? JR Z,RECVI1 ;go if not BIT 5,(IX+CLFLG) ;was break sent? JR NZ,RECVI2 ;go if yes SET 5,(IX+CLFLG) ;else show as sent LD A,(IX+LOGBRK) ;convert for break detect JR RECVI3 ;else show break RECVI1 RES 5,(IX+CLFLG) ;terminate break bit RECVI2 BIT 0,B ;RX char available? RET Z ;nope, go! DEC C ;point to data port DEC C IN A,(C) ;fetch char AND (IX+WORD) ;strip bits RECVI3 LD B,A ;pass to B CALL CKINP ;check input RX24 EQU $-2 WAKEADR RET ;Wakeup if enabled DW 0 ;Space for address ;*=*=* ; Routine to check on a received character ;*=*=* CKINP LD C,A ;Save tempy in reg-C ;*=*=* ; BREAK & PAUSE & ENTER handler routine ;*=*=* LD HL,$-$ ;KFLAG$ KFLAG EQU $-2 CP CR ;ENTER char received? JR NZ,PAWSCK ;Go if not SET 2,(HL) ;Set ENTER bit JR RECVEX ; PAWSCK CP 60H ;Pause char received? JR NZ,BRKCHK ;Go if not SET 1,(HL) ;Set pause bit JR RECVEX ; BRKCHK LD A,(IX+LOGBRK) ;P/u BREAK character OR A ; check if NO break JR Z,RECVEX ; go if so ; CP C ;Break char received? JR NZ,RECVEX ;go if not ;*=*=* ; A BREAK was received, ck system's BREAK disable ;*=*=* BRKRECD LD A,($-$) ;Check if break key SFLAG EQU $-2 AND 10H ; is disabled LD A,0 ;Return NZ & A=0 if RET NZ ; the BREAK is disabled SET 0,(HL) ;Else set break bit LD C,80H ; & reset BREAK code RECVEX LD (IX+CLBUF),C ;Put char into 1-char buf SET 7,(IX+CLFLG) ;show char avail XOR A ;Set Z flag RET ; ; issue init data to SIO/CTC chips ; SNDDAT LD E,(HL) ;get table count INC HL ;point to data ; SNDDAT1 LD B,(HL) ;get data count INC HL ;bump LD C,(HL) ;get port# INC C ;check if nil DEC C RET Z ;yes, ignore CTC2! INC HL ;else point to config dat OTIR ;send to port DEC E ;less table count JR NZ,SNDDAT1 ;go for count RET ;else done! ; ; init data for SIO ports ; ITABLE DB 3 ;# tables ; DB 11 ;# entries this table DB $SIOA ;SIO base port address DB 018H ;channel reset DB 004H ;R4 DB 044H ;X16, stop=1 DB 003H ;R3 DB 0E1H ;word=8, RX DB 005H ;R5 DB 0EAH ;DTR,W=8,TX,RTS DB 002H ;R2 DB 0 ;offset interrupt DB 1+10H ;reset int, R1 DB 01DH ;int on all RX chars ; ; CTC #1 setup ; DB 3 ;# entries this table DB $CTC0 ;CTC0 base port address DB 007H ;count, reset DB 034H ;default 300 baud DB 0 ;offset interrupt vector ; ; CTC #2 setup ; DB 2 ;# entries DB $CTC1 ;CTC1 base port DB 007H ;count, reset DB 034H ;default 300 baud ; ; baud rate lookup table ; BAUDTBL DW 0FE07H ;50 DW 0D007H ;75 DW 08E07H ;110 DW 07407H ;135 DW 06807H ;150 DW 03407H ;300 DW 01A07H ;600 DW 00D07H ;1200 DW 04547H ;1800 DW 03E47H ;2000 DW 03447H ;2400 DW 02347H ;3600 DW 01A47H ;4800 DW 01147H ;7200 DW 00D47H ;9600 DW 00647H ;19200 CLEND EQU $ ; END BEGIN