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 Modell �bersetzen 39 40 41 42 43; ------------------------------------------------------------------- 44; 45; Zeichen f�r Flow-Control bei XON/XOFF 46; 47XON = 11H ; XON 48XOFF = 13H ; XOFF 49 50; ------------------------------------------------------------------- 51; 52; Struktur f�r die Daten eines jeden seriellen Ports. Von diesen Strukturen 53; ist f�r jeden unterst�tzten 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 f�r 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 ; Fehlerz�hler 82 83 ERXOverflow dw 0 ; Puffer�berlauf beim Empfang 84 ETXOverflow dw 0 ; Puffer�berlauf beim Senden 85 EOvrRun dw 0 ; �berlauf beim Empf�nger 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 f�r 8259A #1 96 NotIC1Mask db ? ; Komplement 97 IC2Mask db ? ; Maske f�r 8259A #2 98 NotIC2Mask db ? ; Komplement 99 FIFOLen db ? ; Chunk-Size f�r 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 f�r das FCR des NS16550A. 131; 132FIFO_ENABLE = 001H ; FIFO einschalten 133FIFO_CLR_RX = 002H ; RX-FIFO l�schen 134FIFO_CLR_TX = 004H ; TX-FIFO l�schen 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 f�r warning level 141 142; 143; FIFO Kommandos. In FIFO_INIT mu� eingetragen 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; mu� evtl. bereits nach 8 Zeichen ein Interrupt ausgel�st 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 Verf�gung 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 der �bergebenen Portnummer. Bei Erfolg wird das 239; Handle (immer ein Wert <> 0) zur�ckgeliefert, 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 pr�fen, ob im entsprechenden BIOS-Bereich eine andere Adresse steht. 260; Wenn Ja, dann diese andere Adresse �bernehmen, wenn Nein, oder wenn diese 261; andere Adresse eine 0 ist, den Default behalten. 262; Dann pr�fen, 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 ungew�hnliche 265; Installationen zu unterst�tzen, bei denen z.B. COM 3 fehlt aber COM 4 266; vorhanden ist. Das BIOS packt diese Adressen, so da� der Bereich von COM 4 267; leer ist und COM 3 die Adresse von COM 4 enth�lt. 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 ; N�chste Adresse 287 loop @@L5 288 289; Die Fehlerz�hler nullen 290 291 xor ax, ax ; 0 nach ax 292 lea edi, [(PortDesc esi).ErrorBlock]; Erster Z�hler 293 mov ecx, 6 ; 6 Fehlerz�hler 294 rep stosw ; l�schen 295 296; Pr�fen ob der Port einen 16550A besitzt. Die Anzahl der Bytes die bei einem 297; "Transmit-Register leer"-Interrupt geschrieben werden k�nnen 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, da� kein 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 r�ckliefern 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 dem �bergebenen Handle. 351; 352 353PROC PASCAL _ComDeInstall NEAR PortHandle: DWORD 354USES ESI, EDI 355 356 mov esi, [PortHandle] ; Deskriptor holen 357 358; Pr�fen 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; schlie�en 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 schlie�en 375 mov esi, [PortHandle] ; PortHandle neu laden 376 377; Install-Merker r�cksetzen 378 379@@L2: and [(PortDesc esi).Installed], NOT 01h 380 381; Interrupt-Vektor r�cksetzen. 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 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 NEAR PortHandle: DWORD 406USES ESI, EDI 407 408; Zeiger auf den Port-Deskriptor nach esi 409 410 mov esi, [PortHandle] 411 412; Pr�fen 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; Pr�fen ob der Port bereits offen ist, wenn ja zuerst schlie�en 420 421@@L0: test [(PortDesc esi).Installed], 02h ; Offen ? 422 jz @@L1 ; Nein: Springe 423 push esi ; Parameter f�r ComClose 424 call _ComClose ; Schlie�en 425 mov esi, [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 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 r�cksetzen 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 r�cksetzen 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 pr�fen 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 ; ...r�cksetzen 470 mov dx, [(PortDesc esi).DataReg] ; Datenregister 471 in al, dx ; ...r�cksetzen 472 mov dx, [(PortDesc esi).MSR] ; modem status register... 473 in al, dx ; ...r�cksetzen 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