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