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 Modell �bersetzen 38 39 40 41 42; ------------------------------------------------------------------- 43; 44; Zeichen f�r Flow-Control bei XON/XOFF 45; 46XON = 11H ; XON 47XOFF = 13H ; XOFF 48 49; ------------------------------------------------------------------- 50; 51; Struktur f�r die Daten eines jeden seriellen Ports. Von diesen Strukturen 52; ist f�r jeden unterst�tzten 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 f�r 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 ; Fehlerz�hler 81 82 ERXOverflow dw 0 ; Puffer�berlauf beim Empfang 83 ETXOverflow dw 0 ; Puffer�berlauf beim Senden 84 EOvrRun dw 0 ; �berlauf beim Empf�nger 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 f�r 8259A #1 95 NotIC1Mask db ? ; Komplement 96 IC2Mask db ? ; Maske f�r 8259A #2 97 NotIC2Mask db ? ; Komplement 98 FIFOLen db ? ; Chunk-Size f�r 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 f�r das FCR des NS16550A. 127; 128FIFO_ENABLE = 001H ; FIFO einschalten 129FIFO_CLR_RX = 002H ; RX-FIFO l�schen 130FIFO_CLR_TX = 004H ; TX-FIFO l�schen 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 f�r warning level 137 138; 139; FIFO Kommandos. In FIFO_INIT mu� eingetragen 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; mu� evtl. bereits nach 8 Zeichen ein Interrupt ausgel�st 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 Verf�gung 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 der �bergebenen Portnummer. Bei Erfolg wird das 235; Handle (immer ein Wert <> 0) zur�ckgeliefert, 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 pr�fen, ob im entsprechenden BIOS-Bereich eine andere Adresse steht. 257; Wenn Ja, dann diese andere Adresse �bernehmen, wenn Nein, oder wenn diese 258; andere Adresse eine 0 ist, den Default behalten. 259; Dann pr�fen, 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 ungew�hnliche 262; Installationen zu unterst�tzen, bei denen z.B. COM 3 fehlt aber COM 4 263; vorhanden ist. Das BIOS packt diese Adressen, so da� der Bereich von COM 4 264; leer ist und COM 3 die Adresse von COM 4 enth�lt. 265; bx enth�lt 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 ; N�chste Adresse 289 loop @@L5 290 291; Die Fehlerz�hler nullen 292 293 xor ax, ax ; 0 nach ax 294 lea di, [(PortDesc si).ErrorBlock] ; Erster Z�hler 295 mov cx, 6 ; 6 Fehlerz�hler 296 rep stosw ; l�schen 297 298; Pr�fen ob der Port einen 16550A besitzt. Die Anzahl der Bytes die bei einem 299; "Transmit-Register leer"-Interrupt geschrieben werden k�nnen 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, da� kein 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 r�ckliefern 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 dem �bergebenen Handle. 351; 352 353PROC PASCAL _ComDeInstall FAR PortHandle: WORD 354USES SI, DI 355 356 mov si, [PortHandle] ; Deskriptor holen 357 358; Pr�fen 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; schlie�en 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 schlie�en 375 mov si, [PortHandle] ; PortHandle neu laden 376 377; Install-Merker r�cksetzen 378 379@@L2: and [(PortDesc si).Installed], NOT 01h 380 381; Interrupt-Vektor r�cksetzen. 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 r�cksetzen 389 pop ds 390 391; Ende 392 393@@L99: ret 394 395ENDP _ComDeInstall 396 397; ------------------------------------------------------------------------- 398; 399; _ComOpen 400; 401; Setzt Baudrate etc., l�scht 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; Pr�fen 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; Pr�fen ob der Port bereits offen ist, wenn ja zuerst schlie�en 420 421@@L0: test [(PortDesc si).Installed], 02h ; Offen ? 422 jz @@L1 ; Nein: Springe 423 push si ; Parameter f�r ComClose 424 call _ComClose ; Schlie�en 425 mov si, [PortHandle] ; Handle neu laden 426 427; Eine der Parit�t entsprechende AND-Maske setzen 428 429@@L1: mov al, 0FFh ; Maske f�r 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 r�cksetzen 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 r�cksetzen 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 pr�fen 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 ; ...r�cksetzen 470 mov dx, [(PortDesc si).DataReg] ; Datenregister 471 in al, dx ; ...r�cksetzen 472 mov dx, [(PortDesc si).MSR] ; modem status register... 473 in al, dx ; ...r�cksetzen 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 f�r 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