1; *****************************************************************************
2; *                                                                           *
3; *                               _SERCOM.ASM                                 *
4; *                                                                           *
5; * (C) 1991-96  Ullrich von Bassewitz                                        *
6; *              Zwehrenbuehlstrasse 33                                       *
7; *              D-72070 Tuebingen                                            *
8; * EMail:       uz@ibb.schwaben.com                                          *
9; *                                                                           *
10; *****************************************************************************
11
12
13
14; $Id$
15;
16; $Log$
17;
18;
19
20
21
22; This is a simple module for serial communication under DOS based on a module
23; called USER. The module supports up to four ports, 16550s and the "high"
24; interrupts.
25; Comments are in german, sorry.
26
27
28
29; ***************************************************************************
30
31
32
33IDEAL                   ; IDEAL-Modus von TASM einschalten
34JUMPS                   ; Sprungoptimierung
35LOCALS                  ; Lokale Symbole zulassen
36SMART                   ; "Schlauen" Modus einschalten
37MODEL LARGE             ; Im LARGE Modellbersetzen
38
39
40
41
42; -------------------------------------------------------------------
43;
44; Zeichen fr Flow-Control bei XON/XOFF
45;
46XON             =       11H             ; XON
47XOFF            =       13H             ; XOFF
48
49; -------------------------------------------------------------------
50;
51; Struktur fr die Daten eines jeden seriellen Ports. Von diesen Strukturen
52; ist fr jeden untersttzten Port eine vorhanden.
53;
54
55STRUC   PortDesc
56
57        ; Allgemeine Einstellungen
58
59        Baudrate        dd      ?       ; Baudrate
60        Connection      db      ?       ; M)odem, D)irect
61        Parity          db      ?       ; N)one, O)dd, E)ven, S)pace, M)ark
62        StopBits        db      ?       ; 1, 2
63        DataBits        db      ?       ; 5..8
64        XonXoff         db      ?       ; E)nabled, D)isabled
65                        db      ?       ; Fill auf gerade Adressen
66
67        ; Ringpuffer fr Senden und Empfang incl Verwaltung
68
69        RXBuf           dd      ?       ; Zeiger auf Empfangspuffer
70        TXBuf           dd      ?       ; Zeiger auf Sendepuffer
71        RXBufSize       dw      ?       ; Gr��e Empfangspuffer
72        TXBufSize       dw      ?       ; Gr��e Sendepuffer
73        RXStart         dw      0       ; Ringpufferzeiger
74        RXEnd           dw      0       ;
75        TXStart         dw      0
76        TXEnd           dw      0
77        RXCount         dw      0       ; Anzahl Zeichen im Puffer
78        TXCount         dw      0       ; Anzahl Zeichen im Puffer
79
80        ; Fehlerzhler
81
82        ERXOverflow     dw      0       ; Pufferberlauf beim Empfang
83        ETXOverflow     dw      0       ; Pufferberlauf beim Senden
84        EOvrRun         dw      0       ; �berlauf beim Empfnger
85        EBreak          dw      0       ; Break
86        EFrame          dw      0       ; Framing Fehler
87        EParity         dw      0       ; Parity Fehler
88        ErrorBlock      EQU     ERXOverFlow
89
90        ; Interna
91
92        Installed       db      0       ; 1 wenn installiert
93        IntNr           db      ?       ; Interrupt-Nummer
94        IC1Mask         db      ?       ; Maske fr 8259A #1
95        NotIC1Mask      db      ?       ; Komplement
96        IC2Mask         db      ?       ; Maske fr 8259A #2
97        NotIC2Mask      db      ?       ; Komplement
98        FIFOLen         db      ?       ; Chunk-Size fr Sender-FIFO
99        ParityMask      db      ?       ; 7Fh wenn Parity, sonst 0FFh
100
101        ; Adressen der Chip-Register
102
103        DataReg         dw      ?       ; data register
104        DLL             EQU     DataReg ; divisor low latch
105        IER             dw      ?       ; interrupt enable register
106        DLH             EQU     IER     ; divisor high latch
107        IIR             dw      ?       ; interrupt id register (lesen)
108        FCR             EQU     IIR     ; FIFO control register (schreiben)
109        LCR             dw      ?       ; line control register
110        MCR             dw      ?       ; modem control register
111        LSR             dw      ?       ; line status register
112        MSR             dw      ?       ; modem status register
113
114        IntHandler      dw      ?       ; Offset des Interrupt-Handlers
115        OldVector       dd      ?       ; Alter Interrupt-Vektor
116
117        HostOff         db      0       ; Host Xoff'ed (1=ja, 0 = nein)
118        PCOff           db      0       ; PC Xoff'ed (1=ja, 0=nein)
119        MustSend        db      0       ; Es _mu_ ein Byte gesendet werden
120        DSR_CTS_Ok      db      ?       ; DSR und CTS sind beide On
121
122ENDS    PortDesc
123
124
125;
126; Steuerbits fr das FCR des NS16550A.
127;
128FIFO_ENABLE     =       001H            ; FIFO einschalten
129FIFO_CLR_RX     =       002H            ; RX-FIFO lschen
130FIFO_CLR_TX     =       004H            ; TX-FIFO lschen
131
132FIFO_SZ_1       =       000H            ; Warning level:  1 Bytes
133FIFO_SZ_4       =       040H            ; Warning level:  4 Bytes
134FIFO_SZ_8       =       080H            ; Warning level:  8 Bytes
135FIFO_SZ_14      =       0C0H            ; Warning level: 14 Bytes
136FIFO_SZ_MASK    =       0C0H            ; Maske fr warning level
137
138;
139; FIFO Kommandos. In FIFO_INIT mueingetragen werden, nach wievielen Bytes
140; ein Interrupt erzeugt wird. Unter DOS sind normalerweise 14 Bytes ok, bei
141; langsamen Rechnern (oder langsamen EMM) und hohen Zeichengeschwindigkeiten
142; muevtl. bereits nach 8 Zeichen ein Interrupt ausgelst werden.
143; Default ist Interrupt nach 8 Zeichen.
144;
145FIFO_CLEAR      =       FIFO_CLR_RX OR FIFO_CLR_TX
146FIFO_INIT       =       FIFO_ENABLE OR FIFO_SZ_8 OR FIFO_CLR_RX OR FIFO_CLR_TX
147
148;
149; Sonstiges FIFO-Zeugs.
150;
151
152FIFO_ENABLED    =       0C0H            ; Bitmuster wenn FIFO an
153
154
155;
156; Bits im Modem Control Register
157;
158
159MCR_DTR         =       00000001B
160MCR_RTS         =       00000010B
161MCR_OUT2        =       00001000B
162
163
164
165; -------------------------------------------------------------------
166;
167; Externe Prozeduren, die das Programmiersprachenmodul zur Verfgung
168; stellen mu�.
169;
170;
171
172
173EXTRN PASCAL _COMWAIT   : FAR           ; Warte-Prozedur
174EXTRN PASCAL _COMERROR  : FAR           ; _ComError-Routine
175
176
177
178; -------------------------------------------------------------------
179;
180; Vom Assembler-Modul exportierte Routinen.
181;
182
183PUBLIC  _COMINSTALL
184PUBLIC  _COMDEINSTALL
185PUBLIC  _COMOPEN
186PUBLIC  _COMCLOSE
187PUBLIC  _COMISINSTALLED
188PUBLIC  _COMISOPEN
189PUBLIC  _COMDTROFF
190PUBLIC  _COMDTRON
191PUBLIC  _COMRTSOFF
192PUBLIC  _COMRTSON
193PUBLIC  _COMRXCOUNT
194PUBLIC  _COMRXSIZE
195PUBLIC  _COMRXCLEAR
196PUBLIC  _COMTXCOUNT
197PUBLIC  _COMTXSIZE
198PUBLIC  _COMTXFREE
199PUBLIC  _COMTXCLEAR
200PUBLIC  _COMRECEIVE
201PUBLIC  _COMSEND
202PUBLIC  _COMBREAK
203PUBLIC  _COMMODEMSTATUS
204
205; Interrupt-Handler
206PUBLIC  _INTCOM1
207PUBLIC  _INTCOM2
208PUBLIC  _INTCOM3
209PUBLIC  _INTCOM4
210
211; ---------------------------------------------------------------------------
212; Datensegment
213;
214
215DATASEG
216
217EXTRN   C _ComPort1     : PortDesc
218EXTRN   C _ComPort2     : PortDesc
219EXTRN   C _ComPort3     : PortDesc
220EXTRN   C _ComPort4     : PortDesc
221
222
223; -------------------------------------------------------------------
224;
225; Beginn Codesegment
226;
227
228CODESEG
229
230; -------------------------------------------------------------------------
231;
232; _ComInstall
233;
234; Installiert einen Port mit derbergebenen Portnummer. Bei Erfolg wird das
235; Handle (immer ein Wert <> 0) zurckgeliefert, ansonsten der Wert 0 als
236; Handle.
237;
238
239PROC    PASCAL _ComInstall FAR PortHandle: WORD
240USES    SI, DI
241
242        mov     si, [PortHandle]                ; Porthandle holen
243
244; si zeigt ab hier auf einen Record vom Typ PortDesc
245
246        test    [(PortDesc si).Installed], 01h  ; Bereits installiert
247        jz      @@L3                            ; Nein: Ok
248
249; Fehler, Port war bereits installiert
250
251@@L1:   call    _ComError
252        mov     ax, -1                          ; -1 als Handle liefern
253        jmp     @@L99
254
255; Port ist noch nicht installiert. Port-Adresse aus dem Default-Array holen
256; und prfen, ob im entsprechenden BIOS-Bereich eine andere Adresse steht.
257; Wenn Ja, dann diese andere Adressebernehmen, wenn Nein, oder wenn diese
258; andere Adresse eine 0 ist, den Default behalten.
259; Dann prfen, ob diese Adresse _irgendwo_ im BIOS-Bereich als Adresse
260; eingetragen ist. Fehler wenn nein.
261; Der Sinn dieses ganzen Hin und Her ist es, auch etwas ungewhnliche
262; Installationen zu untersttzen, bei denen z.B. COM 3 fehlt aber COM 4
263; vorhanden ist. Das BIOS packt diese Adressen, so dader Bereich von COM 4
264; leer ist und COM 3 die Adresse von COM 4 enthlt.
265; bx enthlt noch immer (PortAdresse-1)*2
266
267@@L3:   mov     ax, [(PortDesc si).DataReg]     ; Grundadresse holen
268        mov     di, 040h                        ; BIOS-Segment
269        mov     es, di
270        xor     di, di                          ; BIOS-Offset COM Bereich
271        cld
272        mov     cx, 4
273        repne   scasw                           ; Adresse vorhanden ?
274        je      @@L4                            ; Springe wenn Ja
275
276; Fehler, die Adresse konnte nicht gefunden werden. -1 als Handle liefern.
277
278        mov     ax, -1                          ; Handle = -1
279        jmp     @@L99                           ; und Ende
280
281; Adresse ist Ok, die gesamten Adressen in den Deskriptor-Record eintragen
282
283@@L4:   push    ds
284        pop     es
285        lea     di, [(PortDesc ds:si).DataReg]  ; Adresse erstes Register
286        mov     cx, 7                           ; 7 Register pro Chip
287@@L5:   stosw                                   ; Eintragen
288        inc     ax                              ; Nchste Adresse
289        loop    @@L5
290
291; Die Fehlerzhler nullen
292
293        xor     ax, ax                          ; 0 nach ax
294        lea     di, [(PortDesc si).ErrorBlock]  ; Erster Zhler
295        mov     cx, 6                           ; 6 Fehlerzhler
296        rep     stosw                           ; lschen
297
298; Prfen ob der Port einen 16550A besitzt. Die Anzahl der Bytes die bei einem
299; "Transmit-Register leer"-Interrupt geschrieben werden knnen vermerken. Diese
300; Anzahl ist 1 ohne FIFO und bis zu 14 mit FIFO.
301
302        mov     dx, [(PortDesc si).FCR]         ; FIFO control register holen
303        mov     al, FIFO_INIT OR FIFO_ENABLED   ; FIFO...
304        out     dx, al                          ; ... einschalten
305        in      al, dx                          ; Wert wieder holen
306        and     al, FIFO_ENABLED                ; FIFO-Bits ausmaskieren
307        mov     ah, 1                           ; annehmen, dakein FIFO da
308        cmp     al, FIFO_ENABLED                ; Ist es ein 16550A ?
309        jne     @@L6                            ; Springe wenn keiner
310        mov     ah, 16                          ; 16 Sendebytes wenn FIFO vorh.
311@@L6:   mov     [(PortDesc si).FIFOLen], ah     ; Wert merken
312
313; FIFO (falls vorhanden) erstmal wieder ausschalten
314
315        mov     al, FIFO_CLEAR
316        out     dx, al
317
318; Interrupt-Vektor retten und eigenen Vektor setzen
319
320        mov     ah, 35h
321        mov     al, [(PortDesc si).IntNr]       ; Nummer des Interrupts
322        int     21h                             ; Vektor holen
323        mov     [WORD LOW (PortDesc si).OldVector], bx
324        mov     [WORD HIGH (PortDesc si).OldVector], es
325
326        push    ds
327        mov     ah, 25h
328        mov     al, [(PortDesc si).IntNr]       ; Nummer des Interrupts
329        mov     dx, [(PortDesc si).IntHandler]  ;
330        push    cs
331        pop     ds
332        int     21h                             ; Vektor setzen
333        pop     ds
334
335; Den Port als installiert markieren und das Handle in ax rckliefern
336
337        mov     [(PortDesc si).Installed], 01h  ; Bit 0 setzen
338        mov     ax, si                          ; Handle nach ax
339
340; Das wars: Funktionsausgang.
341
342@@L99:  ret
343
344ENDP    _ComInstall
345
346; -------------------------------------------------------------------------
347;
348; _ComDeInstall
349;
350; Deinstalliert den Port mit dembergebenen Handle.
351;
352
353PROC    PASCAL _ComDeInstall FAR  PortHandle: WORD
354USES    SI, DI
355
356        mov     si, [PortHandle]                ; Deskriptor holen
357
358; Prfen ob der Port installiert ist. Fehler wenn nicht.
359
360        test    [(PortDesc si).Installed], 01h  ; Installiert ?
361        jnz     @@L1                            ; Springe wenn ja
362
363; Fehler: Port ist nicht installiert
364
365        call    _ComError                       ; Fehler melden
366        jmp     @@L99                           ; Und Ende
367
368; Port ist installiert. Falls der Port auch gleichzeitig offen ist, zuerst
369; schlieen
370
371@@L1:   test    [(PortDesc si).Installed], 02h  ; Offen ?
372        jz      @@L2                            ; Springe wenn Nein
373        push    si                              ; PortHandle als Parameter
374        call    _ComClose                       ; Port schlieen
375        mov     si, [PortHandle]                ; PortHandle neu laden
376
377; Install-Merker rcksetzen
378
379@@L2:   and     [(PortDesc si).Installed], NOT 01h
380
381; Interrupt-Vektor rcksetzen.
382
383        push    ds
384        mov     ah, 25h
385        mov     al, [(PortDesc si).IntNr]       ; Nummer des belegten Interrupts
386        mov     dx, [WORD LOW (PortDesc si).OldVector]
387        mov     ds, [WORD HIGH (PortDesc si).OldVector]
388        int     21h                             ; Vektor rcksetzen
389        pop     ds
390
391; Ende
392
393@@L99:  ret
394
395ENDP    _ComDeInstall
396
397; -------------------------------------------------------------------------
398;
399; _ComOpen
400;
401; Setzt Baudrate etc., lscht die Puffer, gibt die Interrupts frei, kurz:
402; Setzt den RS232-Betrieb in Gang.
403;
404
405PROC    PASCAL _ComOpen FAR PortHandle: WORD
406USES    SI, DI
407
408; Zeiger auf den Port-Deskriptor nach si
409
410        mov     si, [PortHandle]
411
412; Prfen ob der Port installiert ist. Fehler wenn nicht.
413
414        test    [(PortDesc si).Installed], 01h
415        jnz     @@L0                            ; Springe wenn installiert
416        call    _ComError                       ; Fehler-Routine
417        jmp     @@L99
418
419; Prfen ob der Port bereits offen ist, wenn ja zuerst schlieen
420
421@@L0:   test    [(PortDesc si).Installed], 02h  ; Offen ?
422        jz      @@L1                            ; Nein: Springe
423        push    si                              ; Parameter fr ComClose
424        call    _ComClose                       ; Schlieen
425        mov     si, [PortHandle]                ; Handle neu laden
426
427; Eine der Paritt entsprechende AND-Maske setzen
428
429@@L1:   mov     al, 0FFh                        ; Maske fr kein Parity
430        cmp     [(PortDesc si).Parity], 'N'     ; Parity ?
431        jz      @@L2                            ; Springe wenn Nein
432        mov     al, 07Fh                        ; Maske wenn Parity
433@@L2:   mov     [(PortDesc si).ParityMask], al  ; Maske merken
434
435; Flow-Control rcksetzen
436
437        xor     ax, ax
438        mov     [(PortDesc si).HostOff], al     ;
439        mov     [(PortDesc si).PCOff], al
440        mov     [(PortDesc si).MustSend], al
441        mov     [(PortDesc si).DSR_CTS_Ok], al
442
443; Puffer rcksetzen
444
445        mov     [(PortDesc si).TXStart], ax
446        mov     [(PortDesc si).TXEnd], ax
447        mov     [(PortDesc si).TXCount], ax
448        mov     [(PortDesc si).RXStart], ax
449        mov     [(PortDesc si).RXEnd], ax
450        mov     [(PortDesc si).RXCount], ax
451
452; UART initialisieren
453
454        mov     dx, [(PortDesc si).MCR]         ; modem control register
455        mov     al, 0                           ; clr dtr, rts, out1, out2 & loopback
456        out     dx, al
457        cmp     [(PortDesc si).Connection], 'D' ; Direkte Verbindung ?
458        jz      @@L3                            ; Springe wenn ja
459        mov     dx, [(PortDesc si).MSR]         ; modem status register
460        in      al, dx                          ; modem status lesen
461        and     al, 30h                         ; DSR, CTS maskieren
462        cmp     al, 30h                         ; DSR, CTS prfen
463        jnz     @@L4                            ; Springe wenn nicht ok
464@@L3:   mov     [(PortDesc si).DSR_CTS_Ok], 01h ; Beide da, Ausgang Ok
465@@L4:   mov     dx, [(PortDesc si).FCR]         ; FIFO control register
466        mov     al, FIFO_CLEAR                  ; FIFO ausschalten
467        out     dx, al
468        mov     dx, [(PortDesc si).LSR]         ; line status register...
469        in      al, dx                          ; ...rcksetzen
470        mov     dx, [(PortDesc si).DataReg]     ; Datenregister
471        in      al, dx                          ; ...rcksetzen
472        mov     dx, [(PortDesc si).MSR]         ; modem status register...
473        in      al, dx                          ; ...rcksetzen
474
475; Baudrate in Divisor umrechnen und setzen
476
477        cmp     [WORD HIGH (PortDesc si).Baudrate], 0
478        jz      @@L5                            ; Baudrate < 65536
479        mov     bx, 1                           ; Divisor fr 115200
480        jmp     @@L6
481@@L5:   mov     ax, 0C200h                      ; 115200 MOD 10000h
482        mov     dx, 00001h                      ; 115200 DIV 10000h
483        div     [WORD LOW (PortDesc si).Baudrate]
484        mov     bx, ax                          ; Ergebnis nach bx
485
486; Baudrate am UART einstellen
487
488@@L6:   mov     dx, [(PortDesc si).LCR]         ; line control register
489        mov     al, 80h                         ; DLAB = 1
490        out     dx, al
491        xchg    ax, bx                          ; Divisor nach ax
492        mov     dx, [(PortDesc si).DLL]         ; divisor low
493        out     dx, al                          ; lsb ausgeben
494        mov     dx, [(PortDesc si).DLH]         ; divisor high
495        xchg    ah, al
496        out     dx, al                          ; msb ausgeben
497
498; Parity und Anzahl Stop- und Daten-Bits setzen
499
500        mov     al, 00h                         ; Bits in al zusammenbauen
501        mov     ah, [(PortDesc si).Parity]
502        cmp     ah, 'O'                         ; odd ?
503        jne     @@L7
504        or      al, 0Ah                         ; odd !
505        jmp     @@L9
506
507@@L7:   cmp     ah, 'E'                         ; even ?
508        jne     @@L8
509        or      al, 1Ah                         ; even !
510        jmp     @@L9
511
512@@L8:   cmp     ah, 'M'                         ; mark ?
513        jne     @@L9
514        or      al, 2Ah                         ; mark !
515
516@@L9:   cmp     [(PortDesc si).StopBits], 2     ; 2 Stop-Bits ?
517        jnz     @@L10
518        or      al, 04h
519
520@@L10:  mov     ah, [(PortDesc si).DataBits]    ; Anzahl Datenbits holen
521        sub     ah, 5                           ; 5..8 --> 0..3
522        and     ah, 3                           ; maskieren
523        or      al, ah                          ; und reinodern
524
525        mov     dx, [(PortDesc si).LCR]         ; line control register
526        out     dx, al                          ; parity mode & DLAB = 0
527
528; FIFO's initalisieren (wird ignoriert wenn nicht 16550A)
529
530        mov     dx, [(PortDesc si).FCR]         ; FIFO control register
531        mov     al, FIFO_INIT
532        out     dx, al
533
534; Interrupts freigeben
535
536        cli                                     ; Interrupts aus
537        in      al, 0A1h                        ; Int-Controller #2
538        and     al, [(PortDesc si).NotIC2Mask]  ; Bit l�schen
539        out     0A1h, al                        ; und wieder ausgeben
540        in      al, 021h                        ; Int-Controller #1
541        and     al, [(PortDesc si).NotIC1Mask]  ; Bit l�schen
542        out     021h, al                        ; und wieder ausgeben
543        sti                                     ; Interrupts an
544
545        mov     dx, [(PortDesc si).IER]         ; interrupt enable register
546        mov     al, 00001101B                   ; line & modem status, rec...
547        out     dx, al                          ; ...freigeben
548
549        mov     dx, [(PortDesc si).MCR]         ; modem control register
550        mov     al, MCR_OUT2                    ; OUT2, kein RTS, kein DTR
551        cmp     [(PortDesc si).Connection], 'M' ; Modem connection?
552        jne     @@L11                           ; Nein: Skip
553        or      al, MCR_RTS                     ; Ja: RTS aktiv setzen
554@@L11:  out     dx, al                          ; setzen
555
556; Port als Open markieren.
557
558        or      [(PortDesc si).Installed], 02h
559
560; Ende
561
562@@L99:  ret
563
564ENDP    _ComOpen
565
566
567; -------------------------------------------------------------------------
568;
569; _ComClose
570;
571; Schlie�t einen Com-Port
572;
573
574PROC    PASCAL _ComClose FAR PortHandle: WORD
575
576; Pr�fen ob der Port �berhaupt offen ist
577
578        mov     bx, [PortHandle]
579        test    [(PortDesc bx).Installed], 02h
580        jz      @@Error                         ; Springe wenn Port nicht offen
581
582; Interrupts an UART abklemmen, FIFO abschalten
583
584        cli                                     ; Keine Interrupts
585        mov     dx, [(PortDesc bx).MCR]         ; modem control register
586        mov     al, 0                           ; Kein RTS, DTR, OUT2
587        out     dx, al
588        mov     dx, [(PortDesc bx).IER]         ; interrupt enable register
589        out     dx, al                          ; Shut up !
590        mov     dx, [(PortDesc bx).FCR]
591        mov     al, FIFO_CLEAR
592        out     dx, al                          ; FIFO ausschalten
593
594; Interrupt-Controller abschalten
595
596        in      al, 0A1h                        ; Int-Controller #2
597        or      al, [(PortDesc bx).IC2Mask]
598        out     0A1h, al                        ; Interrupt sperren
599
600        in      al, 021h                        ; Int-Controller #1
601        or      al, [(PortDesc bx).IC1Mask]
602        out     021h, al                        ; Interrupt sperren
603
604; DTR und RTS l�schen
605
606        mov     dx, [(PortDesc bx).MCR]         ; modem control register
607        in      al, dx                          ; Register lesen
608        and     al, NOT (MCR_DTR OR MCR_RTS)    ; DTR l�schen...
609        out     dx, al                          ; ...und wieder setzen
610
611; Vermerken, da� der Port nicht mehr offen ist und Ende
612
613        and     [(PortDesc bx).Installed], NOT 02h
614        sti                                     ; Interrupts wieder zulassen
615
616@@L99:  ret
617
618; Fehlereinsprung
619
620@@Error:call    _ComError
621        jmp     @@L99
622
623ENDP    _ComClose
624
625; ----------------------------------------------------------------------
626;
627; _ComDTROff
628;
629; Schaltet DTR auf off
630;
631
632PROC    PASCAL _ComDTROff FAR PortHandle: WORD
633
634        mov     bx, [PortHandle]
635        test    [(PortDesc bx).Installed], 02h
636        jz      @@Error
637
638; Port ist offen, Aktion durchf�hren
639
640        mov     dx, [(PortDesc bx).MCR]         ; modem control register
641        in      al, dx                          ; Register lesen
642        and     al, NOT MCR_DTR                 ; DTR l�schen...
643        out     dx, al                          ; ...und wieder setzen
644
645; Ende
646
647@@L99:  ret
648
649; Fehlereinsprung
650
651@@Error:call    _ComError
652        jmp     @@L99
653
654ENDP    _ComDTROff
655
656
657
658; -------------------------------------------------------------------------
659;
660; _ComDTROn
661;
662; Schaltet DTR auf aktiv
663;
664
665PROC PASCAL _ComDTROn FAR   PortHandle: WORD
666
667        mov     bx, [PortHandle]
668        test    [(PortDesc bx).Installed], 02h  ; Port offen ?
669        jz      @@Error                         ; Springe wenn Port nicht offen
670
671; Port ist offen, DTR setzen
672
673        mov     dx, [(PortDesc bx).MCR]         ; modem control register
674        in      al, dx                          ; Register lesen
675        or      al, MCR_DTR                     ; DTR aktiv...
676        out     dx, al                          ; und wieder setzen
677
678; Ende
679
680@@L99:  ret
681
682; Fehlereinsprung
683
684@@Error:call    _ComError
685        jmp     @@L99
686
687ENDP    _ComDTROn
688
689
690
691; ----------------------------------------------------------------------
692;
693; _ComRTSOff
694;
695; Schaltet RTS auf off
696;
697
698PROC    PASCAL _ComRTSOff FAR PortHandle: WORD
699
700        mov     bx, [PortHandle]
701        test    [(PortDesc bx).Installed], 02h
702        jz      @@Error
703        cmp     [(PortDesc bx).Connection], 'M' ; Modem connection?
704        je      @@Error                         ; Dann Aufruf nicht erlaubt
705
706; Port ist offen, RTS r�cksetzen
707
708        mov     dx, [(PortDesc bx).MCR]         ; modem control register
709        in      al, dx                          ; Register lesen
710        and     al, NOT MCR_RTS                 ; RTS l�schen...
711        out     dx, al                          ; ...und wieder setzen
712
713; Ende
714
715@@L99:  ret
716
717; Fehlereinsprung
718
719@@Error:call    _ComError
720        jmp     @@L99
721
722ENDP    _ComRTSOff
723
724
725
726; -------------------------------------------------------------------------
727;
728; _ComRTSOn
729;
730; Schaltet RTS auf aktiv
731;
732
733PROC PASCAL _ComRTSOn FAR   PortHandle: WORD
734
735        mov     bx, [PortHandle]
736        test    [(PortDesc bx).Installed], 02h  ; Port offen ?
737        jz      @@Error                         ; Springe wenn Port nicht offen
738        cmp     [(PortDesc bx).Connection], 'M' ; Modem connection?
739        je      @@Error                         ; Dann Aufruf nicht erlaubt
740
741; Port ist offen, RTS setzen
742
743        mov     dx, [(PortDesc bx).MCR]         ; modem control register
744        in      al, dx                          ; Register lesen
745        or      al, MCR_RTS                     ; RTS aktiv...
746        out     dx, al                          ; und wieder setzen
747
748; Ende
749
750@@L99:  ret
751
752; Fehlereinsprung
753
754@@Error:call    _ComError
755        jmp     @@L99
756
757ENDP    _ComRTSOn
758
759
760
761; -------------------------------------------------------------------------
762;
763; _ComIsInstalled
764;
765; Ergibt einen Wert != 0 wenn der Port installiert ist.
766;
767
768PROC    PASCAL _ComIsInstalled FAR   PortHandle: WORD
769
770        mov     bx, [PortHandle]
771        mov     bl, [(PortDesc bx).Installed]
772        xor     ax, ax
773        test    bl, 01h                         ; Installiert ?
774        jz      @@L1                            ; Springe wenn Nein
775        inc     ax                              ; Installiert !
776@@L1:   ret
777
778ENDP    _ComIsInstalled
779
780
781
782; -------------------------------------------------------------------------
783;
784; _ComIsOpen
785;
786; Ergibt einen Wert != 0 wenn der Port ge�ffnet ist.
787;
788
789PROC    PASCAL _ComIsOpen FAR   PortHandle: WORD
790
791        mov     bx, [PortHandle]
792        mov     bl, [(PortDesc bx).Installed]
793        xor     ax, ax
794        test    bl, 02h                         ; Offen ?
795        jz      @@L1                            ; Springe wenn Nein
796        inc     ax                              ; Offen !
797@@L1:   ret
798
799ENDP    _ComIsOpen
800
801
802
803; -------------------------------------------------------------------------
804;
805; _ComReceive
806;
807; Holt ein Zeichen aus dem Empfangspuffer. Warte bis ein Zeichen da ist. Bei
808; Fehlern kommt -1 als Wert zur�ck.
809;
810
811
812PROC    PASCAL _ComReceive FAR   PortHandle: WORD
813USES    SI, DI
814
815        mov     si, [PortHandle]
816        test    [(PortDesc si).Installed], 02h  ; Port offen ?
817        jz      @@Error                         ; Springe wenn Nein
818
819; Port ist offen, pr�fen ob Zeichen da
820
821@@L1:   cmp     [(PortDesc si).RXCount], 0      ; Zeichen da ?
822        jnz     @@L2                            ; Abholen wenn ja
823
824; Es ist kein Zeichen da - erstmal warten, dabei die _ComWait Routine
825; aufrufen
826
827        mov     ax, 10                          ; 10ms
828        push    ax
829        call    _ComWait
830        jmp     @@L1
831
832; Zeichen ist da, holen. Da die Interrupt-Routinen nicht auf den
833; RXStart-Zeiger zugreift, m�ssen die Interrupts nicht gesperrt
834; werden.
835
836@@L2:   mov     bx, [(PortDesc si).RXStart]     ; Ringpufferzeiger
837        les     di, [(PortDesc si).RXBuf]       ; Zeiger auf Pufferbereich
838        mov     al, [es:di+bx]                  ; Zeichen holen
839        inc     bx                              ; Zeiger erh�hen
840        mov     ah, 0                           ; Zeichen nach WORD wandeln
841        push    ax                              ; ... und auf den Stack
842        cmp     bx, [(PortDesc si).RXBufSize]   ; Warp-Around ?
843        jb      @@L3                            ; Springe wenn Nein
844        xor     bx, bx                          ; Ja, Ringpufferzeiger wird 0
845@@L3:   mov     [(PortDesc si).RXStart], bx     ; Zeiger r�ckschreiben
846        dec     [(PortDesc si).RXCount]         ; Ein Zeichen weniger...
847
848; Flow-Control pr�fen. Zuerst Hardware (RTS/CTS), dann Software
849
850        mov     bx, [(PortDesc si).RXBufSize]   ; Gr��e Puffer nach bx
851        shr     bx, 1
852        shr     bx, 1                           ; Gr��e/4 in bx
853        cmp     [(PortDesc si).RXCount], bx     ; Puffer fast leer ?
854        jae     @@L99                           ; Ende wenn nicht
855
856        cli                                     ; Interrupts aus
857        cmp     [(PortDesc si).Connection], 'M' ; Modem connection?
858        jne     @@L4                            ; Springe wenn nein
859        mov     dx, [(PortDesc si).MCR]
860        in      al, dx                          ; MCR lesen
861        or      al, MCR_RTS                     ; RTS setzen (Freigabe)
862        out     dx, al
863
864; Jetzt pr�fen ob XON/XOFF Flow-Control an-, und der Sender abgeschaltet wurde
865
866@@L4:   cmp     [(PortDesc si).XonXoff], 'E'    ; Flow-Control an ?
867        jne     @@L7                            ; Ende wenn nicht
868        cmp     [(PortDesc si).HostOff], 00h    ; XOFF-Status ?
869        jz      @@L7                            ; Ende wenn nicht
870        mov     bx, [(PortDesc si).RXBufSize]   ; Gr��e Puffer nach bx
871
872; Der Host ist gestoppt, der Puffer aber wieder leer genug. XON senden.
873
874@@L5:   cmp     [(PortDesc si).MustSend], 00h   ; Zeichen im Puffer ?
875        je      @@L6                            ; Springe wenn Nein
876
877; Es ist noch ein Steuerzeichen im Puffer. Warten bis es weg ist.
878
879        sti                                     ; Interrupts freigeben
880        mov     ax, 10                          ; 10 ms
881        push    ax
882        call    _ComWait                        ; Warteroutine aufrufen
883        mov     si, [PortHandle]                ; Handle neu laden
884        cli                                     ; Interrupts wieder aus
885        jmp     @@L5                            ; und neu pr�fen...
886
887; Das Kontrollzeichen kann ausgegeben werden
888
889@@L6:   mov     al, XON
890        call    SendII                          ; XON senden
891@@L7:   sti                                     ; Interrupts wieder freigeben
892
893; Zeichen vom Stack und Ende
894
895@@L99:  pop     ax
896        ret
897
898; Fehlereinsprung wenn Port nicht offen
899
900@@Error:call    _ComError                       ; Fehler melden
901        mov     ax, -1                          ; Returncode -1
902        ret
903
904
905ENDP    _ComReceive
906
907
908
909; -------------------------------------------------------------------------
910;
911; _ComRXCount
912;
913; Liefert die Anzahl Bytes im Empfangspuffer.
914;
915
916PROC    PASCAL _ComRXCount FAR PortHandle: WORD
917
918        mov     bx, [PortHandle]
919        test    [(PortDesc bx).Installed], 02h
920        jz      @@Error
921
922; Alles klar, Anzahl liefern und Ende
923
924        mov     ax, [(PortDesc bx).RXCount]
925@@L99:  ret
926
927; Fehlereinsprung wenn Port nicht offen
928
929@@Error:call    _ComError
930        ret
931
932ENDP    _ComRXCount
933
934
935; -------------------------------------------------------------------------
936;
937; _ComRXSize
938;
939; Liefert die Gr��e des Empfangspuffers.
940;
941
942PROC PASCAL _ComRXSize FAR   PortHandle: WORD
943
944        mov     bx, [PortHandle]
945        mov     ax, [(PortDesc bx).RXBufSize]
946        ret
947
948ENDP    _ComRXSize
949
950
951; -------------------------------------------------------------------------
952;
953; _ComRXClear
954;
955; L�scht den kompletten Empfangspuffer. Der Port mu� offen sein.
956;
957
958PROC    PASCAL _ComRXClear  FAR     PortHandle: WORD
959
960        mov     bx, [PortHandle]
961        test    [(PortDesc bx).Installed], 02h
962        jz      @@Error
963
964; Alles klar, Port ist offen
965
966        xor     ax, ax
967        cli                             ; Interrupts sperren
968        mov     [(PortDesc bx).RXStart], ax
969        mov     [(PortDesc bx).RXEnd], ax
970        mov     [(PortDesc bx).RXCount], ax
971        sti                             ; Interrupts freigeben
972
973@@L99:  ret
974
975; Fehlereinsprung wenn Port nicht offen
976
977@@Error:call    _ComError
978        ret
979
980ENDP    _ComRXClear
981
982
983
984; -------------------------------------------------------------------------
985;
986; _ComTXCount
987;
988; Liefert die Anzahl belegter Bytes im Sendepuffer
989;
990
991PROC    PASCAL _ComTXCount FAR   PortHandle: WORD
992
993        mov     bx, [PortHandle]
994        test    [(PortDesc bx).Installed], 02h
995        jz      @@Error                         ; Springe wenn nicht offen
996
997; Port ist offen. Anzahl holen und Ende
998
999        mov     ax, [(PortDesc bx).TXCount]
1000@@L99:  ret
1001
1002; Fehlereinsprung wenn Port ist nicht offen.
1003
1004@@Error:call    _ComError
1005        ret
1006
1007ENDP    _ComTXCount
1008
1009
1010; -------------------------------------------------------------------------
1011;
1012; _ComTXFree
1013;
1014; Liefert die Anzahl freier Bytes im Sendepuffer
1015;
1016
1017PROC    PASCAL _ComTXFree FAR   PortHandle: WORD
1018
1019        mov     bx, [PortHandle]
1020        test    [(PortDesc bx).Installed], 02h
1021        jz      @@Error                         ; Springe wenn nicht offen
1022
1023; Port ist offen. Gr��e - Belegte Bytes rechnen.
1024; VORSICHT: Dieser Wert kann negativ werden, da sich evtl. zus�tzliche
1025; Kontrollzeichen im Puffer befinden k�nnen. In einem solchen Fall
1026; einfach 0 liefern.
1027
1028        mov     ax, [(PortDesc bx).TXBufSize]   ; Gesamtgr��e
1029        dec     ax                              ; Maximale Gr��e f�r Benutzer
1030        sub     ax, [(PortDesc bx).TXCount]
1031        jnc     @@L99                           ; Springe wenn >= 0
1032        xor     ax, ax                          ; if (ax < 0) then ax := 0;
1033@@L99:  ret
1034
1035; Fehlereinsprung wenn Port ist nicht offen.
1036
1037@@Error:call    _ComError
1038        jmp     @@L99
1039
1040ENDP    _ComTXFree
1041
1042
1043
1044; -------------------------------------------------------------------------
1045;
1046; _ComTXSize
1047;
1048; Liefert die Gr��e des Sendepuffers.
1049;
1050
1051PROC    PASCAL _ComTXSize FAR   PortHandle: WORD
1052
1053        mov     bx, [PortHandle]
1054        mov     ax, [(PortDesc bx).TXBufSize]
1055        ret
1056
1057ENDP    _ComTXSize
1058
1059
1060; -------------------------------------------------------------------------
1061;
1062; _ComTXClear
1063;
1064; L�scht den kompletten Sendespuffer. Der Port mu� offen sein.
1065; ACHTUNG: Im Gegensatz zu ComRXClear k�nnen sich hier Steuerzeichen im Puffer
1066; befinden, deren L�schung fatal w�re. Falls sich ein Steuerzeichen im Puffer
1067; befindet ist es jedoch immer (!) das erste Zeichen im Puffer.
1068
1069PROC    PASCAL _ComTXClear  FAR     PortHandle: WORD
1070
1071        mov     bx, [PortHandle]
1072        test    [(PortDesc bx).Installed], 02h
1073        jz      @@Error
1074
1075; Alles klar, Port ist offen
1076
1077        xor     cx, cx                          ; Neue Anzahl Zeichen
1078        pushf                                   ; I-Flag retten
1079        cli                                     ; Interrupts sperren
1080        mov     ax, [(PortDesc bx).TXEnd]
1081        cmp     [(PortDesc bx).MustSend], 00h   ; Steuerzeichen im Puffer ?
1082        jz      @@L2                            ; Springe wenn Nein
1083
1084; Ein Zeichen im Puffer lassen
1085
1086        inc     cx                              ; Anzahl = 1 nach Clear
1087        or      ax, ax                          ; Index schon 0?
1088        jnz     @@L1                            ; Springe wenn nein
1089        mov     ax, [(PortDesc bx).TXBufSize]   ; Gr��e laden
1090@@L1:   dec     ax                              ; - 1
1091
1092; Puffer l�schen
1093
1094@@L2:   mov     [(PortDesc bx).TXStart], ax
1095        mov     [(PortDesc bx).TXCount], cx     ; Neue Anzahl
1096        popf                                    ; Altes I-Flag
1097
1098@@L99:  ret
1099
1100; Fehlereinsprung wenn Port nicht offen
1101
1102@@Error:call    _ComError
1103        jmp     @@L99
1104
1105ENDP    _ComTXClear
1106
1107
1108
1109; -------------------------------------------------------------------------
1110;
1111; _ComSend
1112;
1113; Abschicken eines Zeichens.
1114;
1115
1116PROC    PASCAL _ComSend FAR   PortHandle: WORD, C: BYTE
1117USES    SI, DI
1118
1119        mov     si, [PortHandle]
1120        test    [(PortDesc si).Installed], 02h  ; Port offen ?
1121        jz      @@Error                         ; Springe wenn nein
1122
1123; Port ist offen, pr�fen ob Platz im Puffer
1124
1125        mov     dx, [(PortDesc si).TXBufSize]   ; Gr��e des Puffers nach dx
1126        cmp     [(PortDesc si).TXCount], dx     ; noch Platz ?
1127        jae     @@L4                            ; Springe wenn Nein
1128
1129; Es ist genug Platz. Zeichen schreiben.
1130
1131        mov     al, [C]                         ; Zeichen holen
1132        les     di, [(PortDesc si).TXBuf]       ; Zeiger auf Puffer holen
1133        cli                                     ; Keine Interrupts
1134        mov     bx, [(PortDesc si).TXEnd]       ; Pufferzeiger holen
1135        mov     [es:di+bx], al                  ; Zeichen in Puffer schreiben
1136        inc     bx                              ; Pufferzeiger erh�hen
1137        cmp     bx, dx                          ; Wrap-Around ?
1138        jb      @@L1                            ; Springe wenn Nein
1139        xor     bx, bx                          ; Ringpufferzeiger auf 0 wenn ja
1140@@L1:   mov     [(PortDesc si).TXEnd], bx       ; Pufferzeiger r�ckschreiben
1141        inc     [(PortDesc si).TXCount]         ; Ein Zeichen mehr
1142
1143; Wenn notwendig die Sende-Interrupts freischalten
1144
1145        mov     dx, [(PortDesc si).IER]         ; Interrupt enable register
1146        in      al, dx                          ; ... lesen
1147        test    al, 02h                         ; Interrupts frei ?
1148        jnz     @@L2                            ; Ja, alles klar
1149        cmp     [(PortDesc si).PCOff], 00h      ; XOFF-Status ?
1150        jnz     @@L2                            ; Ja, nix unternehmen
1151        cmp     [(PortDesc si).DSR_CTS_Ok], 00h ; Statusleitungen ok ?
1152        jz      @@L2                            ; Nein, nix unternehmen
1153        mov     al, 00001111B                   ;
1154        out     dx, al                          ; TX-Ints freischalten
1155@@L2:   sti                                     ; Interrupts wieder frei
1156        mov     al, [C]
1157        mov     ah, 0                           ; Zeichen nach ax
1158
1159; Ende
1160
1161@@L99:  ret
1162
1163; Einsprung wenn Puffer voll
1164
1165@@L4:   inc     [(PortDesc si).ETXOverFlow]     ; Fehlerz�hler erh�hen
1166        mov     ax, -1                          ; Fehlerkennung
1167        ret                                     ; Und Ende
1168
1169; Einsprung wenn Port nicht offen
1170
1171@@Error:call    _ComError                       ; Fehler melden
1172        mov     ax, -1                          ; Fehlerkennung
1173        ret                                     ; Ende
1174
1175ENDP    _ComSend
1176
1177
1178
1179; -------------------------------------------------------------------------
1180;
1181; Interne Routine. Wird aufgerufen von ComReceive und vom RX-Interrupthandler
1182; wenn Flow-Control Zeichen verschickt werden m�ssen.
1183; si mu� auf den Port-Deskriptor zeigen, Interrupts m�ssen gesperrt sein.
1184; al enth�lt das zu sendende Zeichen.
1185;
1186
1187PROC    SENDII  NEAR
1188
1189        push    bx
1190        push    dx                              ; Register werden ben�tigt
1191        push    di
1192        push    es
1193
1194        mov     bx, [(PortDesc si).TXStart]     ; Ringpufferzeiger holen
1195        les     di, [(PortDesc si).TXBuf]       ; Zeiger auf Pufferbereich
1196        mov     dx, [(PortDesc si).TXBufSize]   ; Puffergr��e nach dx
1197        cmp     [(PortDesc si).TXCount], dx     ; Puffer voll ?
1198        jb      @@L2                            ; Springe wenn Nein
1199
1200; Im Puffer ist kein Platz mehr (obwohl das eigentlich immer gew�hrleistet
1201; werden sollte !). Das kann eigentlich nur passieren, wenn direkt
1202; hintereinander zwei Flow-Control Zeichen geschickt werden...
1203
1204        mov     [es:bx+di], al                  ; Zerst�rt erstes Zeichen
1205        inc     [(PortDesc si).ETXOverFlow]     ; Fehlerz�hler erh�hen
1206        jmp     @@L2                            ; einfach weiter
1207
1208; Im Puffer ist Platz, Zeichen an die erste Stelle schreiben
1209
1210        dec     bx                              ; Ergibt 0FFFF wenn bx = 0
1211        jns     @@L1                            ; Springe wenn kein Wrap
1212        mov     bx, dx                          ; Sonst Gr��e-1 nach bx
1213        dec     bx
1214@@L1:   mov     [es:bx+di], al                  ; Zeichen schreiben
1215        mov     [(PortDesc si).TXStart], bx     ; Zeiger r�ckschreiben
1216        inc     [(PortDesc si).TXCount]         ; Ein Zeichen mehr ...
1217
1218; Flag f�r extra Zeichen setzen
1219
1220@@L2:   mov     [(PortDesc si).MustSend], 01h   ; Flag setzen
1221
1222; Falls notwendig Interrupts enablen
1223
1224        mov     dx, [(PortDesc si).IER]         ; interrupt enable register
1225        in      al, dx                          ; Wert holen
1226        test    al, 02h                         ; TX-Ints frei ?
1227        jnz     @@L99                           ; Ja: Ende
1228        cmp     [(PortDesc si).DSR_CTS_Ok], 00h ; Statusleitungen ok ?
1229        jz      @@L99                           ; Nein, Pech ..
1230        mov     al, 00001111B                   ; modem & line status, rec, xmit
1231        out     dx, al                          ; ... freigeben
1232
1233; Fertig !
1234
1235@@L99:  pop     es
1236        pop     di
1237        pop     dx
1238        pop     bx
1239        ret
1240
1241ENDP    SendII
1242
1243
1244; -------------------------------------------------------------------------
1245;
1246; _ComBreak
1247;
1248; Sendet ein Break-Signal mit variabler L�nge.
1249;
1250
1251PROC    PASCAL _ComBreak FAR  PortHandle: WORD, BreakLen: WORD
1252
1253        mov     bx, [PortHandle]
1254        test    [(PortDesc bx).Installed], 02h
1255        jz      @@Error                         ; Springe wenn Port nicht offen
1256
1257; Port ist offen, Break senden
1258
1259        mov     dx, [(PortDesc bx).LCR]
1260        pushf                                   ; I-Bit retten
1261        cli                                     ; Interrupts off
1262        in      al, dx                          ; get LCR
1263        or      al, 40h                         ; break bit on
1264        out     dx, al                          ; setzen
1265        popf                                    ; Altes I-Bit
1266
1267; Warte-Routine aufrufen
1268
1269        push    [BreakLen]
1270        call    _ComWait
1271
1272; Register sind futsch, neu laden
1273
1274        mov     bx, [PortHandle]
1275        mov     dx, [(PortDesc bx).LCR]
1276
1277; Und Break-Bit r�cksetzen
1278
1279        pushf
1280        cli
1281        in      al, dx
1282        and     al, NOT 40h
1283        out     dx, al
1284        popf
1285
1286; Fertig
1287
1288@@L99:  ret
1289
1290; Fehlereinsprung wenn Port ist nicht offen.
1291
1292@@Error:call    _ComError
1293        jmp     @@L99
1294
1295ENDP    _ComBreak
1296
1297
1298
1299; -------------------------------------------------------------------------
1300;
1301; ComModemStatus
1302;
1303; Gibt den Status der Kontroll-Leitungen zur�ck.
1304;
1305; Portbelegung:
1306;       0x80:   -CD     (Carrier Detect, inverted)
1307;       0x40:   -RI     (Ring Indicator, inverted)
1308;       0x20:   -DSR    (Data Set Ready, inverted)
1309;       0x10:   -CTS    (Clear to Send, inverted)
1310;       0x08:   Delta Carrier Detect    (CD changed)
1311;       0x04:   Trailing edge of RI     (RI went OFF)
1312;       0x02:   Delta DSR               (DSR changed)
1313;       0x01:   Delta CTS               (CTS changed)
1314;
1315
1316PROC    PASCAL _ComModemStatus FAR  PortHandle: WORD
1317
1318        mov     bx, [PortHandle]
1319        test    [(PortDesc bx).Installed], 02h  ; Port Offen ?
1320        jz      @@Error                         ; Springe wenn Nein
1321        mov     dx, [(PortDesc bx).MSR]         ; Modem status register
1322        in      al, dx                          ; Wert holen
1323        mov     ah, 0                           ; Wert in ax
1324@@L99:  ret
1325
1326; Fehlereinsprung wenn Port nicht offen
1327
1328@@Error:call    _ComError
1329        jmp     @@L99
1330
1331
1332ENDP    _ComModemStatus
1333
1334
1335; -------------------------------------------------------------------------
1336;
1337; Interrupt-Handler f�r COM1
1338;
1339
1340PROC    PASCAL _IntCom1 FAR
1341
1342        push    si                              ; Register retten
1343        mov     si, OFFSET _ComPort1            ; Deskriptor laden
1344        jmp     SHORT IntCommon                 ; Gemeinsame Routine
1345
1346ENDP    _IntCom1
1347
1348; -------------------------------------------------------------------------
1349;
1350; Interrupt-Handler f�r COM2
1351;
1352
1353PROC    PASCAL _IntCom2 FAR
1354
1355        push    si                              ; Register retten
1356        mov     si, OFFSET _ComPort2            ; Deskriptor laden
1357        jmp     SHORT IntCommon                 ; Gemeinsame Routine
1358
1359ENDP    _IntCom2
1360
1361; -------------------------------------------------------------------------
1362;
1363; Interrupt-Handler f�r COM3
1364;
1365
1366PROC    PASCAL _IntCom3 FAR
1367
1368        push    si                              ; Register retten
1369        mov     si, OFFSET _ComPort3            ; Deskriptor laden
1370        jmp     SHORT IntCommon                 ; Gemeinsame Routine
1371
1372ENDP    _IntCom3
1373
1374; -------------------------------------------------------------------------
1375;
1376; Interrupt-Handler f�r COM4
1377;
1378
1379PROC    PASCAL _IntCom4 FAR
1380
1381        push    si                              ; Register retten
1382        mov     si, OFFSET _ComPort4            ; Deskriptor laden
1383        jmp     SHORT IntCommon                 ; Gemeinsame Routine
1384
1385ENDP    _IntCom4
1386
1387; -------------------------------------------------------------------------
1388;
1389; Gemeinsame Interrrupt-Routine f�r alle Ports
1390;
1391
1392PROC    IntCommon FAR
1393
1394        push    ax
1395        push    bx
1396        push    cx
1397        push    dx
1398        push    di
1399        push    bp
1400        push    es
1401        push    ds                              ; Register retten
1402
1403        mov     ax, DGROUP
1404        mov     ds, ax                          ; Datensegment setzen
1405
1406; Rausfinden, was es f�r ein Interrupt war und entsprechend verzweigen
1407
1408@@RePoll:
1409        mov     dx, [(PortDesc si).IIR]         ; interrupt id register
1410        in      al, dx
1411        test    al, 01h                         ; "no interrupt present" ?
1412        jnz     @@L98                           ; Ja: Ende
1413        mov     bl, al                          ; Wert nach bx
1414        and     bx, 000Eh                       ; unerw�nschte Bits ausmaskieren
1415        jmp     [@@IntDispatch+bx]              ; Behandlungsroutine
1416
1417LABEL @@IntDispatch WORD
1418        dw      @@MSInt                         ; 0: Modem status int
1419        dw      @@TXInt                         ; 2: Transmitter int
1420        dw      @@RXInt                         ; 4: Receiver int
1421        dw      @@LSInt                         ; 6: Line status int
1422        dw      @@RePoll                        ; 8: Reserviert
1423        dw      @@RePoll                        ; A: Reserviert
1424        dw      @@RXInt                         ; C: FIFO timeout, wie RXInt
1425        dw      @@RePoll                        ; E: Reserviert
1426
1427; Interrupt-Controller verst�ndigen. Problemlos m�glich, weil die Interrupts
1428; sowieso noch gesperrt sind.
1429
1430@@L98:  mov     dx, [(PortDesc si).IER]         ; Interrupt enable register
1431        in      al, dx                          ; Wert lesen
1432        mov     ah, al                          ; ... und nach ah retten
1433        xor     al, al                          ; Interrupts disablen
1434        out     dx, al
1435
1436        mov     al, 20h                         ; EOI
1437        cmp     [(PortDesc si).IC2Mask], 00     ; "Hoher" Interrupt ?
1438        jz      @@L99                           ; Springe wenn Nein
1439        out     0A0h, al                        ; EOI an Controller #2
1440@@L99:  out     20h, al                         ; EOI an Controller #1
1441
1442        mov     al, ah                          ; Alter IER-Wert
1443        out     dx, al                          ; ... restaurieren
1444
1445        pop     ds
1446        pop     es
1447        pop     bp
1448        pop     di
1449        pop     dx
1450        pop     cx
1451        pop     bx
1452        pop     ax
1453        pop     si
1454        iret
1455
1456; -------------------------------------------------------------------------
1457;
1458; Line status interrupt
1459;
1460
1461@@LSInt:mov     dx, [(PortDesc si).LSR]         ; line status register
1462        in      al, dx                          ; lesen
1463        shr     al, 1                           ; Bit wird nicht ben�tigt
1464        xor     bx, bx                          ; bx = 0
1465
1466        shr     al, 1                           ; overrun error pr�fen
1467        adc     [(PortDesc si).EOvrRun], bx     ; Z�hler evtl. erh�hen
1468        shr     al, 1                           ; parity error pr�fen
1469        adc     [(PortDesc si).EParity], bx     ; Z�hler evtl. erh�hen
1470        shr     al, 1                           ; framing error pr�fen
1471        adc     [(PortDesc si).EFrame], bx      ; Z�hler evtl. erh�hen
1472        shr     al, 1                           ; break error pr�fen
1473        adc     [(PortDesc si).EBreak], bx      ; Z�hler evtl. erh�hen
1474
1475        jmp     @@RePoll                        ; Und neu abfragen
1476
1477; -------------------------------------------------------------------------
1478;
1479; Modem status interrupt
1480;
1481
1482@@MSInt:mov     dx, [(PortDesc si).MSR]         ; modem status register
1483        in      al, dx                          ; lesen
1484
1485        cmp     [(PortDesc si).Connection], 'D' ; direkte Verbindung ?
1486        je      @@B1                            ; dann immer frei
1487
1488        and     al, 30h                         ; DSR/CTS maskieren
1489        cmp     al, 30h                         ; beide da ?
1490        mov     al, 00h                         ; Flag f�r Nein
1491        jne     @@B2                            ; Springe wenn Nein
1492@@B1:   mov     al, 01h                         ; Flag f�r Ja
1493@@B2:   mov     [(PortDesc si).DSR_CTS_Ok], al  ; Flag setzen
1494
1495; Jetzt auf jeden Fall immer alle Interrupts freigeben. Falls keine Daten
1496; anliegen werden die Ints in der TXInt-Routine wieder gesperrt.
1497
1498        mov     dx, [(PortDesc si).IER]         ; interrupt enable register
1499        mov     al, 00001111B
1500        out     dx, al
1501        jmp     @@RePoll                        ; und neu pollen
1502
1503; -------------------------------------------------------------------------
1504;
1505; Transmit interrupt
1506;
1507
1508@@TXInt:cmp     [(PortDesc si).DSR_CTS_Ok], 0   ; Hardware Ok ?
1509        je      @@C5                            ; Nein: Ints abklemmen und Ende
1510
1511        mov     cx, 1                           ; Anzahl Flow-Control Zeichen
1512        cmp     [(PortDesc si).MustSend], 00h   ; Flow-Control Zeichen ?
1513        jnz     @@C2                            ; Ja, immer senden
1514        cmp     [(PortDesc si).PCOff], 00h      ; Flow-Control ok ?
1515        jnz     @@C5                            ; Nein: Ints abklemmen und Ende
1516
1517        mov     cl, [(PortDesc si).FIFOLen]     ; Maximale Anzahl FIFO
1518        cmp     cx, [(PortDesc si).TXCount]     ; > Anzahl im Puffer ?
1519        jle     @@C1                            ; Springe wenn kleiner
1520        mov     cx, [(PortDesc si).TXCount]     ; Sonst Anzahl im Puffer nehmen
1521@@C1:   jcxz    @@C5                            ; Nichts zu senden
1522
1523@@C2:   mov     bx, [(PortDesc si).TXStart]     ; Ringpufferzeiger
1524        les     di, [(PortDesc si).TXBuf]       ; Zeiger auf Sendepuffer
1525        mov     dx, [(PortDesc si).DataReg]     ; Datenregister
1526        sub     [(PortDesc si).TXCount], cx     ; Anzahl passend vermindern
1527
1528@@C3:   mov     al, [es:bx+di]                  ; Zeichen holen
1529        out     dx, al                          ; und schreiben
1530        inc     bx                              ; Pufferzeiger erh�hen
1531        cmp     bx, [(PortDesc si).TXBufSize]   ; Wrap ?
1532        jb      @@C4
1533        xor     bx, bx                          ; Wrap !
1534@@C4:   loop    @@C3                            ; und n�chstes Zeichen
1535
1536        mov     [(PortDesc si).TXStart], bx     ; Zeiger r�ckschreiben
1537        mov     [(PortDesc si).MustSend], 0     ; Flow-Control ist weg
1538
1539        jmp     @@RePoll                        ; Fertig !
1540
1541; Es gibt nichts zu senden, oder es darf nicht gesendet werden:
1542; TX-Interrupts abklemmen
1543
1544@@C5:   mov     dx, [(PortDesc si).IER]         ; interrupt enable register
1545        mov     al, 00001101B                   ; line & modem status, rec.
1546        out     dx, al
1547        jmp     @@RePoll
1548
1549; -------------------------------------------------------------------------
1550;
1551; Receive interrupt
1552;
1553
1554@@RXInt:mov     bx, [(PortDesc si).RXEnd]       ; Ringpufferzeiger holen
1555        les     di, [(PortDesc si).RXBuf]       ; Zeiger auf Pufferbereich holen
1556        mov     bp, [(PortDesc si).RXBufSize]   ; Puffergr��e nach bp
1557
1558@@D1:   mov     dx, [(PortDesc si).DataReg]     ; Datenregister
1559        in      al, dx                          ; lesen
1560        and     al, [(PortDesc si).ParityMask]  ; Parity-Bit ausmaskieren
1561        cmp     [(PortDesc si).XonXoff], 'E'    ; Flow Control ?
1562        jnz     @@D4                            ; Springe wenn Nein
1563
1564; Flow-Control ist an, Ctrl-S und Ctrl-Q pr�fen
1565
1566        cmp     al, XOFF                        ; Ctrl-S ?
1567        jnz     @@D2                            ; Nein: Skip
1568        mov     [(PortDesc si).PCOff], 01h      ; Ja: Stop !
1569        mov     al, 00001101B                   ; TX-Ints sperren
1570        jmp     @@D3                            ; Zeichen nicht speichern
1571@@D2:   cmp     al, XON                         ; Ctrl-Q ?
1572        jnz     @@D4                            ; Nein: Skip
1573        mov     [(PortDesc si).PCOff], 00h      ; Ja: Output freigeben
1574        mov     al, 00001111B
1575@@D3:   mov     dx, [(PortDesc si).IER]
1576        out     dx, al
1577        jmp     @@D7                            ; Zeichen nicht speichern
1578
1579; Zeichen speichern
1580
1581@@D4:   cmp     [(PortDesc si).RXCount], bp     ; Noch Platz ?
1582        jb      @@D5                            ; Springe wenn ja
1583        inc     [(PortDesc si).ERXOverflow]     ; Fehlerz�hler erh�hen
1584        jmp     @@D7                            ; Und n�chstes Byte
1585
1586@@D5:   mov     [es:bx+di], al                  ; Zeichen speichern
1587        inc     bx                              ; Zeiger erh�hen
1588        cmp     bx, bp                          ; Wrap-Araound ?
1589        jb      @@D6                            ; Springe wenn Nein
1590        xor     bx, bx
1591@@D6:   inc     [(PortDesc si).RXCount]         ; Anzahl im Puffer erh�hen
1592
1593; Pr�fen, ob noch mehr Zeichen vorliegen (FIFO)
1594
1595@@D7:   mov     dx, [(PortDesc si).LSR]         ; line status register
1596        in      al, dx                          ; ...lesen
1597        test    al, 01h                         ; noch Zeichen da ?
1598        jne     @@D1                            ; Ja: N�chstes Zeichen lesen
1599
1600; Es liegen keine Zeichen mehr vor. Pufferzeiger r�ckspeichern.
1601
1602        mov     [(PortDesc si).RXEnd], bx
1603
1604; Jetzt noch pr�fen, ob der Sender gestoppt werden mu�, wenn der Puffer
1605; zu voll wird.
1606
1607        mov     ax, [(PortDesc si).RXBufSize]   ; Puffergr��e nach ax
1608        shr     ax, 1                           ; / 2
1609        mov     bx, ax
1610        shr     ax, 1                           ; / 4
1611        add     ax, bx                          ; 3/4 Gr��e in ax
1612        cmp     [(PortDesc si).RXCount], ax     ; Puffer 3/4 voll ?
1613        jb      @@D99                           ; Nein: Kein Grund zum Abschalten
1614
1615; Falls RTS/CTS verwendet wird, RTS abschalten
1616
1617        cmp     [(PortDesc si).Connection], 'M' ; HW Control?
1618        jne     @@D8                            ; Springe wenn nein
1619        mov     dx, [(PortDesc si).MCR]
1620        in      al, dx                          ; Sonst MCR lesen...
1621        and     al, NOT MCR_RTS                 ; ...RTS off...
1622        out     dx, al                          ; ...und wieder schreiben
1623
1624; Falls Software Flow Control verwendet wird, XOFF absenden
1625
1626@@D8:   cmp     [(PortDesc si).XonXoff], 'E'    ; Enabled ?
1627        jnz     @@D99                           ; Nein: Fertig
1628        cmp     [(PortDesc si).HostOff], 00h    ; Schon XOFF gesandt ?
1629        jnz     @@D99                           ; Ja: Keins mehr senden
1630        mov     al, XOFF
1631        call    SendII                          ; Zeichen abschicken
1632        mov     [(PortDesc si).HostOff], 01h    ; und merken...
1633
1634; Fertig, neu pollen
1635
1636@@D99:  jmp     @@RePoll
1637
1638
1639ENDP    IntCommon
1640
1641END
1642