home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS 1992 September / Simtel20_Sept92.cdr / msdos / sysutl / async_ce.arc / ASYNC.ASM next >
Assembly Source File  |  1987-08-31  |  48KB  |  1,336 lines

  1. page 58,132
  2. ;    file: ASYNC.ASM
  3. TITLE    ASYNC DRIVER FOR MSDOS
  4. SUBTTL    DESCRIPTION
  5. ;
  6. ;    Loadable asyncrounous device driver for msdos.
  7. ;    Written by: Mike Higgins
  8. ;    Copyright (c) April 1984 by The Computer Entomologist.
  9. ;
  10. ;    Permission is hearby granted to use or distribute this software
  11. ;without any restrictions.  You may make copies for yourself or your
  12. ;friends. You may include it in any hardware or software product that you
  13. ;sell for profit.
  14. ;
  15. ;    This software is distributed as is, and is not guaranteed to work
  16. ;on any particular hardware/software configuration.  Furthermore, no 
  17. ;liability is granted with this software: the user takes responcibility for
  18. ;any damage this software may do to his system.
  19. ;
  20. ;    Nasy notices aside, if you have any questions about this software, you
  21. ;can reach me at the address below.  If you impliment any new features or
  22. ;find (and fix!) any bugs, I would be happy to hear from you.
  23. ;
  24. ;    Mike Higgins
  25. ;    The Computer Entomologist
  26. ;    P.O. Box 197
  27. ;    Duncans Mills, CA 95430
  28. ;
  29. ;    -Impliments FULL RS232 support for IBM PC and compatable async cards.
  30. ;    -Includes 128-byte buffers on input and output.
  31. ;    -Supports Xon/Xoff or hardware handshake. Hardware handshake uses
  32. ;     DSR or CTS (to throttle output data) All handshake modes are
  33. ;     treated separately, an can be used in combinations.
  34. ;    -Bells can be set to echo when the input buffer overflows.
  35. ;    -An inteligent half-duplex mode is available that echoes characters
  36. ;     only after MSDOS has requested them. (Typed-ahead answers to
  37. ;     questions apear AFTER the questions, not as you type them).
  38. ;    -The 8th bit (parity) can optionally be stripped off on input
  39. ;     and/or output.
  40. ;    -Lower case characters can optionally be translated to upper case
  41. ;     on input and/or output.
  42. ;    -Control-c and control-s characters are optionally passed through 
  43. ;     the buffer on non-destructive reads so that the buffer does not
  44. ;     defeat the break command to MSDOS when the buffer is full.
  45. ;    -Several escape sequences are optionally scanned for on input that
  46. ;     perform useful tasks when used as a console terminal:
  47. ;     1) A soft reset sequence that re-boots the system in the same way
  48. ;        ALT-SHIFT-DEL does. (Default: control-C control-R control-B).
  49. ;     2) A flush input buffer sequence that removes all characters in
  50. ;        the 128 byte typeahead buffer that have not been read by
  51. ;        MSDOS yet (Default: control-X).
  52. ;     3) A re-draw the last output line sequence. (Default: control-R).
  53. ;     4) A delete line sequence that will delete all input back to the
  54. ;        begening of the last line. (Default: control-U).
  55. ;     5) A skip output sequence turns this driver into a NUL device,
  56. ;        (output data disapears) until the next skip-output sequence is
  57. ;        types, or until input is requested. (Default: control-O).
  58. ;    -The IOCTRL read and write function is used to query or change
  59. ;     baud rates, bits/byte, parity, as well as enabling/disabling all
  60. ;     the optional features mentioned above.  This eliminates the
  61. ;     necesity of a program that has special knowledge of the system.
  62. ;     A program to change these features need not know the location of
  63. ;     the driver or special words in low memory, or even the port
  64. ;     address of the UART.  Instead, all that is needed is the name of
  65. ;     the device, and the format of an IOCTL write to this driver.
  66. ;
  67. ;        ASSEMBLY INSTRUCTIONS:
  68. ;    MASM ASYNC,ASYNC,ASYNC,NUL
  69. ;    LINK ASYNC,ASYNC,ASYNC,NUL
  70. ;    EXE2BIN ASYNC
  71. ;    COPY ASYNC.BIN A:    (IF NOT THERE ALREADY)
  72. ;        ADD THE FOLLOWING LINE TO A:CONFIG.SYS:
  73. ;    DRIVER=ASYNC.BIN
  74. ;        RE-BOOT YOUR SYSTEM AND IT'S THERE! NOTE: THIS DRIVER
  75. ;    DOES NOT GET ALONG AT ALL WITH BASICA OR MODE, AND POSSIBLY 
  76. ;    MANY OTHER PCDOS PROGRAMS THAT DO NOT CONFORM TO THE MSDOS 
  77. ;    STANDARDS.  BASICA IN PARTICULAR MUCKS UP ALL THE ASYNC CARD
  78. ;    INTERNAL REGESTERS, REDIRECTS THE HARDWARE VECTOR, AND IT
  79. ;    NEVER PUTS THEM BACK THE WAY THEY WERE.  IF YOU TRY TO USE
  80. ;    THIS DRIVER AFTER BASICA HAS BEEN IN MEMORY, THE DRIVER WILL
  81. ;    PROBABLY HANG YOUR SYSTEM.
  82. ;
  83. ;        ***BUGS***
  84. ;
  85. ;    If your RS232 device continually sends data to the driver, the driver
  86. ;    will hang when your system boots. (The EPSON RX80 serial card sends
  87. ;    ^Q's constantly and causes this).  The current solution is to leave
  88. ;    your device turned off until the system boots completely.  Then turn
  89. ;    the RS232 device on after the driver is ready for it, and everything
  90. ;    works as expected.
  91. ;
  92. ;    There are a lot of hooks in the driver for features that do not work
  93. ;    yet. (For example, input data throttleing, output conversion of
  94. ;    tabs to spaces).  So don't expect all of these things to work just
  95. ;    because there are comments about them or bits to set for them.
  96. ;    Write me if you do impliment any of this stuff.
  97. SUBTTL    DEFINITIONS
  98. PAGE
  99. ;
  100. ;        DEVICE TYPE CODES
  101. DEVCHR    EQU    08000h    ;THIS IS A CHARACTER DEVICE
  102. DEVBLK    EQU    0H    ;THIS IS A BLOCK (DISK) DEVICE
  103. DEVIOC    EQU    04000H    ;THIS DEVICE ACCEPTS IOCTRL REQUESTS
  104. DEVNON    EQU    02000H    ;NON IBM DISK DRIVER
  105. DEVSPC    EQU    010H    ;CONSOLE ACCEPTS SPECIAL INTERUPT 29
  106. DEVCLK    EQU    08H    ;THIS IS THE CLOCK DEVICE
  107. DEVNUL    EQU    04H    ;THIS IS THE NUL DEVICE
  108. DEVSTO    EQU    02H    ;THIS IS THE CURRENT STANDARD OUTPUT DEVICE
  109. DEVSTI    EQU    01H    ;THIS IS THE STANDARD INPUT DEVICE
  110. ;
  111. ;        ERROR STATUS BITS
  112. STSERR    EQU    08000H    ;GENERAL ERROR, SEE LOWER ORDER BITS FOR REASON
  113. STSBSY    EQU    0200H    ;DEVICE IS BUISY
  114. STSDNE    EQU    0100H    ;REQUEST IS COMPLETED
  115. ;        ERROR REASON VALUES FOR LOWER ORDER BITS.
  116. ERRWP    EQU    0    ;WRITE PROTECT ERROR
  117. ERRUU    EQU    1    ;UNKNOWN UNIT
  118. ERRDNR    EQU    2    ;DRIVE NOT READY
  119. ERRUC    EQU    3    ;UNKNOWN COMMAND
  120. ERRCRC    EQU    4    ;CYCLIC REDUNDANCY CHECK ERROR
  121. ERRBSL    EQU    5    ;BAD DRIVE REQUEST STRUCTURE LENGTH
  122. ERRSL    EQU    6    ;SEEK ERROR
  123. ERRUM    EQU    7    ;UNKNOWN MEDIA
  124. ERRSNF    EQU    8    ;SECTOR NOT FOUND
  125. ERRPOP    EQU    9    ;PRINTER OUT OF PAPER
  126. ERRWF    EQU    10    ;WRITE FAULT
  127. ERRRF    EQU    11    ;READ FAULT
  128. ERRGF    EQU    12    ;GENERAL FAILURE
  129. ;
  130. ;        DEFINE THE BIT MEANINGS OF THE OUTPUT STATUS BYTE
  131. ;
  132. LINIDL    EQU    0FFH    ;IF ALL BITS OFF, XMITTER IS IDLE.
  133. LINXOF    EQU    1    ;OUTPUT IS SUSPENDED BY XOFF
  134. LINEXP    EQU    2    ;XMITTER IS BUISY, INTERUPT EXPECTED.
  135. LINSKP    EQU    8    ;SKIP OUTPUT UNTIL NEXT SKIPO SEQUENC.
  136. LINDSR    EQU    10H    ;OUTPUT IS SUSPENDED UNTIL DSR COMES ON AGAIN
  137. LINCTS    EQU    20H    ;OUTPUT IS SUSPENDED UNTIL CTS COMES ON AGAIN
  138. ;
  139. ;        BIT DEFINITIONS OF THE INPUT STATUS BYTE
  140. ;
  141. MODERR    EQU    1    ;INPUT LINE ERRORS HAVE BEEN DETECTED.
  142. MODOVR    EQU    4    ;RECEIVER BUFFER OVERFLOWED, DATA LOST.
  143. MODOFF    EQU    2    ;DEVICE IS OFFLINE NOW.
  144. ;
  145. ;        DEFINE THE BIT MEANINGS IN THE SPECIAL CHARACTERISTICS WORDS
  146. ;
  147. ;    THE FIRST SPECIAL WORD CONTROLS HOW THE INPUT FROM THE UART IS TREATED
  148. ;
  149. INDTR    EQU    2    ;DTR IS DATA-THROTTLE SIGNAL.
  150. INRTS    EQU    4    ;RTS IS DATA-THROTTLE SIGNAL.
  151. INXON    EQU    8    ;XON/XOFF IS USED TO THROTTLE INPUT DATA.
  152. INBEL    EQU    010H    ;BELLS ARE ECHOED WHEN BUFFER OVERFLOWS.
  153. INHDP    EQU    020H    ;HALF DUPLEX: INPUT CHARS ARE ECHOED.
  154. INCTX    EQU    040H    ;FLUSH INPUT BUFFER SEQUENCE RECOGNIZED.
  155. INCTR    EQU    080H    ;RE-DRAW CURRENT LINE ENABLED.
  156. INCTU    EQU    0100H    ;DELETE CURRENT LINE ENABLED.
  157. INCTO    EQU    0200H    ;SKIP OUTPUT SEQUENCE INABLED.
  158. INEST    EQU    0400H    ;ERRORS CAUSE STATUS RETURNS.
  159. INEPC    EQU    0800H    ;ERRORS TRANSLATE TO CODES WITH PARITY BIT ON.
  160. INSTP    EQU    01000H    ;STRIP PARITY BIT OFF ON INPUT
  161. INUPR    EQU    02000H    ;FORCE CHARACTERS TO UPPER CASE.
  162. INCTC    EQU    04000H    ;CONTROL-C LEAPS INPUT BUFFER ON N.D. READ.
  163. INRES    EQU    08000H    ;RESET SEQUENCE CAUSES SYSTEM RE-BOOT.
  164. ;
  165. ;    THE SECOND SPECIAL WORD CONTROLS HOW THE OUTPUT TO THE UART IS TREATED
  166. ;
  167. OUTDSR    EQU    2    ;DSR IS USED TO THROTTLE OUTPUT DATA.
  168. OUTCTS    EQU    4    ;CTS IS USED TO THROTTLE OUTPUT DATA.
  169. OUTXON    EQU    8    ;XON/XOFF IS USED TO THROTTLE OUTPUT DATA.
  170. OUTCSF    EQU    010H    ;CTS IS OFFLINE SIGNAL.
  171. OUTCDF    EQU    020H    ;CARRIER DETECT IS OFFLINE SIGNAL
  172. OUTDRF    EQU    040H    ;DSR IS OFFLINE SIGNAL.
  173. OUTSTP    EQU    01000H    ;STRIP PARITY OFF ON OUTPUT.
  174. OUTUPR    EQU    02000H    ;LOWER CASE XLATES TO UPPER ON OUTPUT.
  175. OUTTAB    EQU    04000H    ;TABS ARE TRANSLATED TO SPACES ON OUTPUT.
  176. ;
  177. ;        DEFINE THE PORT OFFSETS AND IMPORTANT ASYNC BOARD CONSTANTS
  178. DLAB    EQU    080H    ;DIVISOR LATCH ACCESS BIT
  179. ALLINT    EQU    01111B    ;ENABLE ALL INTERUPTS IN INTEN REGESTER.
  180. TXBUF    EQU    0    ;OFFSET TO TRANSMITTER BUFFER REGESTER
  181. RXBUF    EQU    0    ;DITO FOR RECEIVER (DIRECTION DIFERENTIATES FUNCS)
  182. BAUD0    EQU    0    ;BAUD DIVISOR REG (DLAB IN LCTRL DIFFERENCIATES)
  183. BAUD1    EQU    1    ;BAUD DIVISOR HIGH BYTE
  184. INTEN    EQU    1    ;INTERUPT ENABLE REGESTER
  185. INTID    EQU    2    ;INTERUPT IDENTIFICATION REGESTER.
  186. LCTRL    EQU    3    ;LINE CONTROL REGESTER
  187. MCTRL    EQU    4    ;MODEM CONTROL REGESTER
  188. LSTAT    EQU    5    ;LINE STATUS REGESTER
  189. MSTAT    EQU    6    ;MODEM STATUS REGESTER
  190.  
  191.  
  192. BOOTS    SEGMENT AT 0FFFFH    ;SEGMENT FOR FAR JUMP TO WARM BOOT
  193. RE_BOOT    LABEL    FAR        ;ADDRESS.  THIS IS USED BY THE
  194. BOOTS    ENDS            ;RE-BOOT ESCAPE SEQUENCE, IF ENABLED.
  195.  
  196. VECS    SEGMENT AT 0    ;ON AN IBM PC, YOU CAN REQUEST A "QUICK" BOOT
  197.     ORG    72H    ;BY STORING 1234H IN LOCATION 0:72.  THIS IS
  198. FLAG    LABEL    WORD    ;THE MOST IBM SPECIFIC THING IN THIS WHOLE
  199. VECS    ENDS        ;DRIVER, YOU MAY HAVE TO CHANGE THE RE-BOOT
  200.             ;LOGIC FOR OTHER SYSTEMS.  ON THE OTHER HAND,
  201.             ;WRITING TO 0:72 BEFORE RESETTING THE 8088
  202.             ;CAN'T DO ANY HARM, SO YOU CAN LEAVE THIS IN.
  203. SUBTTL    DRIVER LIST HEAD
  204. PAGE
  205. ;*************************************************************************
  206. ;
  207. ;    BEGENING OF DRIVER CODE.
  208. ;
  209. DRIVER    SEGMENT
  210.     ASSUME    CS:DRIVER,DS:DRIVER,ES:DRIVER
  211. ;    ORG    0    ;DRIVERS START AT 0
  212. ASYNC2:
  213.     DW    ASYNC1,-1    ;POINTER TO NEXT DEVICE: DOS FILLS THIS IN.
  214.     DW    DEVCHR OR DEVIOC    ;CHARACTER DEVICE
  215.     DW    STRATEGY        ;OFFSET TO STRATEGY ROUTINE.
  216.     DW    REQUEST2        ;OFFSET TO "INTERUPT" ENTRYPOINT.
  217.     DB    "ASYNC2  "        ;DEVICE NAME.
  218. ASYNC1:
  219.     DW    -1,-1        ;POINTER TO NEXT DEVICE: END OF LINKED LIST.
  220.     DW    DEVCHR OR DEVIOC    ;THIS DEVICE IS CHARACTER IOCTL
  221.     DW    STRATEGY        ;STRATEGY ROUTINE
  222.     DW    REQUEST1        ;I/O REQUEST ROUTINT
  223.     DB    "ASYNC1  "
  224. debug    dd    0b8000000h
  225. onotify    macro    char
  226.     push    es
  227.     push    di
  228.     push    ax
  229.     mov    ax,'&char'
  230.     les    di,CS:debug
  231.     stos    byte ptr [di]
  232.     inc    di
  233.     mov    word ptr CS:debug,di
  234.     pop    ax
  235.     pop    di
  236.     pop    es
  237. endm
  238. SUBTTL DRIVER INTERNAL DATA STRUCTURES
  239. PAGE
  240. ;
  241. ASY_UNITS    EQU    2    ;NUMBER OF UNITS THIS DRIVER IS BUILT FOR
  242.  
  243. UNIT    STRUC    ;EACH UNIT HAS A STRUCTURE DEFINING IT'S STATE:
  244. PORT    DW    ?    ;I/O PORT ADDRESS
  245. VECT    DW    ?    ;INTERUPT VECTOR OFFSET (NOT INTERUPT NUMBER!)
  246. ISRADR    DW    ?    ;OFFSET TO INTERUPT SERVICE ROUTINE
  247. LINE    DB    ?    ;DEFAULT LINE CONTROL BIT SETTINGS DURING INIT,
  248.             ;OUTPUT STATUS BITS AFTERWORDS.
  249. MODEM    DB    ?    ;MODEM CONTROL BIT SETTINGS DURING INIT,
  250.             ;INPUT STATUS BITS AFTERWARDS.
  251. INSPEC    DW    ?    ;SPECIAL CHAR INPUT TREATMENT, HANDSHAKING MODE.
  252. OUTSPEC    DW    ?    ;SPECIAL MODE BITS FOR OUTPUT
  253. BAUD    DW    ?    ;CURRENT BAUD RATE DIVISOR VALUE
  254. FLSHP    DW    ?    ;OFFSET INTO FLUSH BUFFER COMMAND STRING.
  255. REDRP    DW    ?    ;OFFSET INTO RE-DRAW LINE COMMAND STRING.
  256. BACKP    DW    ?    ;OFFSET INTO DELETE CURRENT LINE COMMAND STRING.
  257. SKIPP    DW    ?    ;OFFSET INTO SKIP OUTPUT SEQUENCE.
  258. REBTP    DW    ?    ;OFFSET INTO RE-BOOT SYSTEM COMMAND STRING.
  259. IFIRST    DW    ?    ;OFFSET TO FIRST CHARACTER IN INPUT BUFFER.
  260. IAVAIL    DW    ?    ;OFFSET TO NEXT AVAILABLE BYTE.
  261. IBUF    DW    ?    ;POINTER TO 128 BYTE INPUT BUFFER.
  262. OFIRST    DW    ?    ;OFFSET INTO FIRST CHARACTER IN OUTPUT BUFFER
  263. OAVAIL    DW    ?    ;OFFSET INTO NEXT AVAIL BYTE IN OUTPUT BUFFER
  264. OBUF    DW    ?    ;POINTER TO 128 BYTE OUTPUT BUFFER
  265. UNIT    ENDS
  266.  
  267.     ;TABLE OF STRUCTURES FOR EACH ASYNCROUNOUS UNIT
  268.             ;ASYNC1 DEFAULTS TO THE COM1 PORT AND VECTOR,
  269.             ;NO PARITY, 8 DATA BITS, 1 STOP BIT,AND 9600 BAUD.
  270. ASY_TAB1:
  271.     UNIT    <3F8H,30H,ASY1ISR,3,0BH,0D3D0H,8,12,0,0,0,0,0,0,0,IN1BUF,0,0,OUT1BUF>
  272.  
  273.             ;ASYNC2 DEFAULTS TO THE COM2 PORT AND VECTOR,
  274.             ;NO PARITY, 8 DATA BITS, 1 STOP BIT,
  275.             ;AND 9600 BAUD.
  276. ASY_TAB2:
  277.     UNIT    <2F8H,2CH,ASY2ISR,3,0BH,0D3D0H,8,12,0,0,0,0,0,0,0,IN2BUF,0,0,OUT2BUF>
  278.  
  279.         ;IF THE BUFFER SIZE IS A POWER OF TWO, THE PROCESS OF KEEPING
  280.         ;THE OFSETTS WITHIN THE BOUNDS OF THE BUFFER IS GREATLY
  281.         ;SIMPLIFIED.  IF YOU MODIFY THE BUFFER SIZE, KEEP IT A
  282.         ;POWER OF 2, AND MODIFY THE MASK ACCORDINGLY.
  283. BUFSIZ    EQU    128        ;INPUT BUFFER SIZE
  284. BUFMSK    EQU    127        ;MASK FOR CALCULATING OFFSETS MODULO BUFSIZ
  285. IN1BUF    DB    BUFSIZ DUP (?)
  286. IN2BUF    DB    BUFSIZ DUP (?)
  287. OUT1BUF    DB    BUFSIZ DUP (?)
  288. OUT2BUF    DB    BUFSIZ DUP (?)
  289. ;
  290. ;    BAUD RATE CONVERSION TABLE
  291. ASY_BAUDT    DW    50,2304        ;FIRST VALUE IS DESIRED BAUD RATE,
  292.         DW    75,1536        ;SECOND IS DIVISOR REGISTER VALUE.
  293.         DW    110,1047
  294.         DW    134,857
  295.         DW    150,786
  296.         DW    300,384
  297.         DW    600,192
  298.         DW    1200,96
  299.         DW    1800,64
  300.         DW    2000,58
  301.         DW    2400,48
  302.         DW    3600,32
  303.         DW    4800,24
  304.         DW    7200,16
  305.         DW    9600,12
  306. ;
  307. ;    DEFINE THE SEQUENCES OF CHARACTERS THAT ARE SCANNED FOR ON
  308. ;    INPUT, USED TO FLUSH BUFFER, RE-BOOT, RE-DRAW LINES, ETC.
  309. ;        EACH OF THESE SEQUENCES IS A STRING OF THREE OR LESS
  310. ;    BYTES TERMINATED WITH A NUL.  HERE THEY ARE PADDED WITH NULS
  311. ;    TO 4 BYTES EACH SO THAT ALTERNATE SEQUENCES CAN BE PATCHED IN
  312. ;    WITH DEBUG.
  313. ;
  314. FLUSH    DB    'X' AND 1FH,0,0,0    ;FLUSH INPUT BUFFER
  315. REDRAW    DB    'R' AND 1FH,0,0,0    ;RE-DRAW LAST LINE
  316. BACKL    DB    'U' AND 1FH,0,0,0    ;DELETE LAST LINE
  317. SKIPO    DB    'O' AND 1FH,0,0,0    ;SKIP OUTPUT
  318. REBOOT    DB    'C' AND 1FH,'R' AND 1FH,'B' AND 1FH,0 ;RE-BOOT SYSTEM
  319.  
  320. ;
  321. ;    STRUCTURE OF AN I/O REQUEST PACKET STATIC HEADER
  322. ;
  323. PACK    STRUC
  324. LEN    DB    ?    ;LENGTH OF RECORD
  325. PRTNO    DB    ?    ;UNIT CODE
  326. CODE    DB    ?    ;COMMAND CODE
  327. STAT    DW    ?    ;RETURN STATUS
  328. DOSQ    DD    ?    ;UNUSED DOS QUE LINK POINTER
  329. DEVQ    DD    ?    ;UNUSED DRIVER QUE LINK POINTER
  330. MEDIA    DB    ?    ;MEDIA CODE ON READ/WRITE
  331. XFER    DW    ?    ;XFER ADDRESS OFFSET
  332. XSEG    DW    ?    ;XFER ADDRESS SEGMENT
  333. COUNT    DW    ?    ;TRANSFER BYTE COUNT.
  334. PACK    ENDS
  335. ;
  336. ;    THE FOLLOWING TWO WORDS IS THE STORAGE AREA FOR THE REQUEST PACKET
  337. ;    ADDRESS, SENT TO ME BY A STRATEGY ROUTINE CALL.
  338. ;        AS REQUESTED BY THE MSDOS DRIVER MANUAL, I AM "THINKING
  339. ;    ABOUT" THE FUTURE, SO I`M DESIGNATING THIS POINTER AS THE QUEUE
  340. ;    LIST HEAD FOR REQUESTS TO THIS DRIVER.
  341. ;
  342. PACKHEAD    DD    0
  343. ;
  344. ;    THE STRATEGY ROUTINE ITSELF.
  345. STRATEGY    PROC    FAR
  346.             ;SQUIRREL AWAY THE POINTER FOR LATER.
  347.     MOV    WORD PTR CS:PACKHEAD,BX        ;STORE THE OFFSET,
  348.     MOV    WORD PTR CS:PACKHEAD+2,ES    ;AND THE SEGMENT.
  349.     RET
  350. STRATEGY    ENDP
  351. SUBTTL    REQUEST ROUTINES
  352. PAGE
  353. ;    PHYLOSOPHICAL RUMINATIONS:
  354. ;        Why does MicroSoft INSIST on choosing names for things that
  355. ;    already have firmly defined meanings for OTHER things?  Take for
  356. ;    example, the MASM definition of a SEGMENT: It bears little relation
  357. ;    to the deffinition of a segment in the intel 8088 processor handbook.
  358. ;    This leads to a GREAT DEAL of confusion.  Many other assemblers on
  359. ;    other systems have constructs that are equivalent to MASM's SEGMENT,
  360. ;    they are often called PSECTS for Program SECTionS.  Perhaps the
  361. ;    people at Microsoft wanted a word that made more sence in English,
  362. ;    but I wish they had chosen SECTION instead of SEGMENT.
  363. ;        The example that it bringing all this to mind now is the
  364. ;    MicroSoft device driver documentation, which insists on calling
  365. ;    the following routine an "interupt routine".  Go read the intel
  366. ;    manual, you will find that an interupt routine is defined THERE as
  367. ;    a bunch of code that is jumped to by a special kind of event in
  368. ;    the hardware.  That is NOT what the people at MicroSquishy mean
  369. ;    this time either.  Depending on weather you describe these routines
  370. ;    in terms of what they do now, or in the "future", the following
  371. ;    routine should be called the "I/O request routine" or the "I/O
  372. ;    completion routine".   But NO, they had to deside to call this
  373. ;    the "interupt routine", and create another layer of confusion for
  374. ;    those of us who already know the traditional deffinition of this
  375. ;    relatively well known phrase.
  376. ;
  377. ;        I am herby refering to the "interupt routine" as the
  378. ;    "request routine", and nameing all my labels accordingly.
  379. ;
  380. ;        I/O REQUEST ROUTINES
  381. REQUEST1:        ;ASYNC1 HAS BEEN REQUESTED
  382.     PUSH    SI    ;SAVE SI SO YOU CAN
  383.     MOV    SI,OFFSET ASY_TAB1    ;GET THE DEVICE UNIT TABLE ADDRESS.
  384.     JMP    GEN_REQUEST    ;THE GENERIC DRIVER DOES THE REST.
  385. REQUEST2:        ;ASYNC2 HAS BEEN REQUESTED TO DO SOMETHING
  386.     PUSH    SI    ;SAVE SI
  387.     MOV    SI,OFFSET ASY_TAB2    ;GET UNIT TABLE TWO`S ADDRESS
  388.  
  389. GEN_REQUEST:
  390.     PUSHF        ;I REQUIRE DIRECTION FLAG CLEARED, SO I SAVE
  391.     CLD        ;THE FLAGS AND CLEAR THEM HERE.
  392.     PUSH    AX        ;SAVE ALL THE REGESTERS, YOU MAY NOT
  393.     PUSH    BX        ;NEED THEM ALL, BUT YOU WILL REGRET IT
  394.     PUSH    CX        ;IF YOU FORGET TO SAVE JUST ONE OF THEM.
  395.     PUSH    DX
  396.     PUSH    DI
  397.     PUSH    BP
  398.     PUSH    DS
  399.     PUSH    ES
  400.     PUSH    CS        ;COPY THE CS REGESTER
  401.     POP    DS        ;INTO THE DS TO ACCESS MY DATA
  402.     LES    BX,PACKHEAD    ;RECOVER THE POINTER TO THE PACKET.
  403.     MOV    DI,OFFSET ASY_FUNCS    ;GET THE POINTER TO THE DISPATCH TABLE
  404.     MOV    AL,ES:CODE[BX]    ;GET THE FUNCTION REQUEST CODE,
  405.     MOV    AH,0        ;MAKE IT INTO A WORD,
  406.     SAL    AX,1        ;CONVERT TO A WORD OFFSET,
  407.     ADD    DI,AX        ;AND ADD TO THE TABLE START ADDRESS
  408.     JMP    [DI]        ;JUMP TO THE APPROPRIATE ROUTINE
  409. ;
  410. ;        TABLE OF OFFSETS TO ALL THE DRIVER FUNCTIONS
  411. ASY_FUNCS:
  412.     DW    ASYNC_INIT    ;INITIALIZE DRIVER
  413.     DW    EXIT        ;MEDIA CHECK (BLOCK DEVICES ONLY)
  414.     DW    EXIT        ;BUILD BPB (BLOCK DEVICES ONLY)
  415.     DW    IOCTLIN        ;IOCTL INPUT
  416.     DW    READ        ;READ
  417.     DW    NDREAD        ;NON-DESTRUCTIVE READ
  418.     DW    RXSTAT        ;INPUT STATUS
  419.     DW    INFLUSH        ;FLUSH INPUT BUFFER
  420.     DW    WRITE        ;WRITE
  421.     DW    WRITE        ;WRITE WITH VERIFY
  422.     DW    TXSTAT        ;OUTPUT STATUS
  423.     DW    TXFLUSH        ;FLUSH OUTPUT BUFFER
  424.     DW    IOCTLOUT    ;IOCTL OUTPUT
  425. ;
  426. ;    EXIT FROM DRIVER REQUEST
  427. ;        CALL WITH AX= RETURN STATUS VALUE
  428. EXITP    PROC    FAR
  429. EXIT:
  430.     LES    BX,PACKHEAD    ;RETREIVE POINTER TO PACKET
  431.     OR    AX,STSDNE    ;SET THE DONE BIT IN IT.
  432.     MOV    ES:STAT[BX],AX    ;STORE THE STATUS BACK IN THE PACKET.
  433.  
  434.     POP    ES        ;RESTORE ALL THE REGESTERS
  435.     POP    DS
  436.     POP    BP
  437.     POP    DI
  438.     POP    DX
  439.     POP    CX
  440.     POP    BX
  441.     POP    AX
  442.     POPF
  443.     POP    SI
  444.     RET
  445. EXITP    ENDP
  446. SUBTTL    READ DATA REQUEST ROUTINE
  447. PAGE
  448. ;
  449. ;        ALL THE FOLLOWING ROUTINES ARE CALLED WITH THE SAME CONTEXT
  450. ;    FROM THE REQUEST ROUTINE:
  451. ;    - ES:BX POINTS TO THE I/O PACKET.
  452. ;       ROUTINES CAN MUCK UP THESE TWO REGESTERS IF THEY WANT, AS EXIT
  453. ;       WILL RESTORE THEM BEFORE IT TRIES TO SEND THE STATUS WORD BACK.
  454. ;    - CS: AND DS: POINT TO THE BEGENING OF THE DRIVER SEGMENT.
  455. ;    - DS:SI POINTS TO THE DEVICE UNIT TABLE DESCRIBING THE PARTICULAR
  456. ;       PORT BEING ACCESSED.
  457. ;    - ALL OTHER REGESTERS ARE AVAILABLE FOR USE, THE EXIT ROUTINE
  458. ;       RESTORES THEM ALL BEFORE RETURNING TO MSDOS.
  459. ;        ALL THE FOLLOWING ROUTINES SHOULD EXIT BY DOING A JMP
  460. ;    TO THE EXIT ROUTINE.  EXIT ASSUMES THAT AX
  461. ;    CONTAINS EITHER ZERO, OR THE ERROR BIT SET AND A VALID ERROR
  462. ;    RETURN VALUE IN THE LOW ORDER BITS.  EXIT SETS THE DONE BIT IN
  463. ;    THIS VALUE FOR YOU BEFORE IT RETURNS TO MSDOS.
  464. ;
  465. SUBTTL    READ REQUEST ROUTINE
  466. ;        READ DATA FROM DEVICE
  467. ;
  468. READ:
  469.     MOV    CX,ES:COUNT[BX]        ;GET THE REQUESTED NUMBER OF BYTES
  470.     MOV    DI,ES:XFER[BX]        ;DI IS OFFSET TO USER BUFFER
  471.     MOV    DX,ES:XSEG[BX]        ;SEGMENT IS LAST I NEED FROM PACKET,
  472.     MOV    ES,DX            ;NOW ES:DI POINTS TO USER BUFFER.
  473.  
  474.     TEST    LINE[SI],LINSKP        ;IF THERE IS A SKIP OUTPUT IN
  475.     JE    NO_SKIP            ;PROGRESS, I MUST CANCEL IT NOW.
  476.     AND    LINE[SI],NOT LINSKP    ;CLEAR THE SKIP OUTPUT BIT.
  477.     CALL    START_OUTPUT        ;START THE XMITTER GOING AGAIN.
  478. NO_SKIP:
  479.     TEST    MODEM[SI],MODERR OR MODOVR ;HAVE ANY LINE ERRORS OCCURED?
  480.     JE    NO_LERR            ;NOT LATELY.
  481.     AND    MODEM[SI],NOT ( MODERR OR MODOVR ) ;YES, CLEAR THE BITS,
  482.     MOV    AX,ERRRF        ;AND RETURN ERROR INDICATION TO DOS
  483.     JMP    EXIT
  484. NO_LERR:
  485.  
  486. RLUP:
  487.     CALL    GET_IN            ;GET NEXT CHAR FROM INPUT BUFFER
  488.     CMP    AH,0            ;WAS THERE ONE?
  489.     JE    TEST_READ        ;YES, TEST FOR SPECIAL BITS
  490.     JMP    RLUP            ;NO, WAIT FOR A CHAR TO ARRIVE.
  491. TEST_READ:
  492.         ;BEFORE RETURNING A CHARACTER TO MSDOS, I CHECK FOR ANY
  493.         ;SPECIAL PROCESSING I AM REQUIRED TO DO.  I DO AS MANY
  494.         ;OF THESE FUNCTIONS HERE AS POSSIBLE, TO SAVE THE
  495.         ;RECEIVER INTERUPT ROUTINE FROM HAVING TO DO THEM, AND
  496.         ;TO ALLOW INTELIGENT USE OF THE RING BUFFER.  FOR EXAMPLE,
  497.         ;CHARACTERS TO NOT ECHO-HALF-DUPLEX UNTIL THEY ARE READ
  498.         ;FROM THE BUFFER HERE, SO A PROGRAM THAT DISABLES ECHO
  499.         ;WHILE READING A PASSWORD WILL WORK EVEN IF THE USER TYPED
  500.         ;THE PASWORD IN BEFORE BEING PROMPTED FOR IT.
  501.             ;************************************
  502.             ;TEST FOR STRIPPING PARITY BIT
  503.     TEST    INSPEC[SI],INSTP    ;SHOULD I STRIP PARITY?
  504.     JE    NO_STRIP        ;NOPE.
  505.     AND    AL,NOT 080H        ;YES.
  506. NO_STRIP:
  507.             ;*********************************
  508.             ;TEST FOR UPPER-CASE CONVERSION
  509.     TEST    INSPEC[SI],INUPR    ;IS LOWER TO UPPER CONV. ENABLED?
  510.     JE    NO_UPPER        ;NOPE, SKIP THIS.
  511.     MOV    AH,AL            ;MAKE A COPY IN AH,
  512.     AND    AH,07FH            ;STRIP PARITY TO MAKE TEST VALID,
  513.     CMP    AH,'a'            ;IS IT < A LOWER CASE a?
  514.     JL    NO_UPPER        ;YES, THEN IT'S NOT LOWER.
  515.     CMP    AH,'z'            ;IS IT > A LOWER CASE z?
  516.     JG    NO_UPPER        ;YES, THEN IT'S STILL NOT LOWER.
  517.     SUB    AL,020H            ;NO, THEN CONVERT THE ONE IN AL.
  518. NO_UPPER:
  519.             ;**********************************8
  520.             ;TEST FOR HALF-DUPLEX MODE
  521.     STOS    BYTE PTR [DI]        ;BUT FIRST STORE CHAR IN USER BUFFER.
  522.     TEST    INSPEC[SI],INHDP    ;AM I IN HALF DUPLEX MODE?
  523.     JE    NO_HALF            ;NO.
  524. HALF_WAIT:
  525.     CALL    PUT_OUT            ;YES, PUT THE CHARACTER IN OUTBUF.
  526.     CMP    AH,0            ;WAS THERE ROOM?
  527.     JNE    HALF_WAIT        ;NO, WAIT FOR IT.
  528.     CALL    START_OUTPUT        ;AND MAKE SURE THE XMITTER STARTS
  529. NO_HALF:
  530.         ;ALTHOUGH MSDOS NEVER, TO MY KNOWLEDGE, ASKS FOR MORE THAN
  531.         ;ONE STUPID CHARACTER AT A TIME, I LOOP ON THE REQUEST SIZE
  532.         ;SO THAT THIS DRIVER WILL STILL WORK ON THAT GLORIOUS DAY
  533.         ;WHEN SOMEBODY ASKS FOR MORE THAN ONE.
  534.     LOOP    RLUP            ;KEEP GOING IF YOU WERE REQUESTED.
  535.     MOV    AL,0            ;RETURN NO ERRORS IN AX IF DONE.
  536.     JMP    EXIT
  537. SUBTTL    NON-DESTRUCTIVE READ REQUEST ROUTINE
  538. PAGE
  539. ;        NON-DESTRUCTIVE READ FROM DEVICE
  540. ;
  541. NDREAD:
  542.     MOV    DI,IFIRST[SI]        ;GET POINTER TO FIRST CHAR
  543.     CMP    DI,IAVAIL[SI]        ;IS THE BUFFER EMPTY?
  544.     JNE    NDGET            ;NO, GET ONE NON DESTRUCTIVELY.
  545.     MOV    AX,STSBSY        ;YES, RETURN DEVICE BUISY
  546.     JMP    EXIT
  547. NDGET:
  548.     PUSH    BX            ;SAVE AN EXTRA COPY OF BX.
  549.     MOV    BX,IBUF[SI]        ;GET BUFFER ADDRESS
  550.     TEST    INSPEC[SI],INCTC    ;SHOULD I CHECK FOR IMBEDDED ^C'S?
  551.     JE    NONDCTC            ;NO.
  552.                 ;YES, SCAN BUFFER FOR CONTROL-C.
  553. CTCLUP:
  554.     CMP    BYTE PTR [BX+DI],'C' AND 1FH    ;IS THIS A CONTROL-C?
  555.     JNE    NXTCTC            ;NO, GO TRY AGAIN
  556. YESCTC:
  557.     MOV    IFIRST[SI],DI        ;YES, DESTRUCTIVELY READ TO HERE,
  558.     JMP    NONDCTC            ;AND RETURN THE CONTROL-C.
  559. NXTCTC:
  560.     CMP    BYTE PTR [BX+DI],'S' AND 1FH    ;DO THE SAME TEST FOR ^S
  561.     JE    YESCTC            ;IN CASE XON/XOFF IS DISABLED.
  562.     INC    DI            ;INCRIMENT THE POINTER,
  563.     AND    DI,BUFMSK        ;MODULO BUFSIZ,
  564.     CMP    DI,IAVAIL[SI]        ;STOP IF YOU BUMP INTO YOURSELF,
  565.     JNE    CTCLUP            ;ELSE KEEP LOOKING.
  566.     MOV    DI,IFIRST[SI]        ;IF NO, CONTROL-C, RETURN FIRST CHAR
  567. NONDCTC:
  568.     MOV    AL,[BX+DI]            ;GET THE CHARACTER,
  569.     POP    BX            ;RECOVER BX AGAIN.
  570.     MOV    ES:MEDIA[BX],AL        ;RETURN IT IN THE REQUEST PACKET.
  571.     MOV    AX,0            ;RETURN NO ERRORS IN AX.
  572.     JMP    EXIT
  573. SUBTTL    INPUT STATUS REQUEST ROUTINE
  574. PAGE
  575. ;        INPUT STATUS REQUEST
  576. ;
  577. RXSTAT:
  578.     MOV    DI,IFIRST[SI]        ;GET POINTER TO FIRST CHAR
  579.     CMP    DI,IAVAIL[SI]        ;IS THE BUFFER EMPTY?
  580.     JNE    RXFUL
  581.     MOV    AX,STSBSY        ;NO, RETURN STATUS BUISY.
  582.     JMP    EXIT
  583. RXFUL:
  584.     MOV    AX,0            ;YES, RETURN STATUS ZERO.
  585.     JMP    EXIT
  586. SUBTTL    INPUT FLUSH REQUEST ROUTINE
  587. ;        INPUT FLUSH REQUEST
  588. ;
  589. INFLUSH:
  590.     MOV    AX,IAVAIL[SI]        ;GET THE POINTER TO THE NEXT EMPTY
  591.     MOV    IFIRST[SI],AX        ;CHAR AND POINT THE FIRST AT IT.
  592.     MOV    AX,0            ;AND RETURN DONE.
  593.     JMP    EXIT
  594. SUBTTL    WRITE REQUEST ROUTINE
  595. PAGE
  596. ;        OUTPUT DATA TO DEVICE
  597. ;
  598. WRITE:
  599.     MOV    CX,ES:COUNT[BX]        ;GET BYTE COUNT,
  600.     MOV    DI,ES:XFER[BX]        ;GET XFER ADDRESS OFFSET,
  601.     MOV    AX,ES:XSEG[BX]        ;GET XFER SEGMENT.
  602.     MOV    ES,AX            ;STORE IN ES NOW.
  603.     TEST    LINE[SI],LINSKP        ;SHOULD I BE SKIPPING OUTPUT?
  604.     JNE    WRSUCC
  605. WLUP:
  606.     MOV    AL,ES:[DI]        ;GET THE NEXT CHAR,
  607.     INC    DI            ;AND INC DI PAST IT.
  608. ;
  609. ;        CHECK FOR STRIP PARITY ON OUTPUT.
  610. ;
  611.     TEST    OUTSPEC[SI],OUTSTP    ;IS THIS ENABLED?
  612.     JE    NOOSTP            ;NOPE
  613.     AND    AL,NOT 080H        ;YES, WACK OFF BIT SEVEN!
  614. NOOSTP:
  615. ;
  616. ;        CHECK FOR LOWER-TO-UPPER CONVERSION ON OUTPUT
  617. ;
  618.     TEST    OUTSPEC[SI],OUTUPR    ;IS THIS ENABLED?
  619.     JE    NOOUPR            ;NOPE
  620.     MOV    AH,AL            ;DO COMPARISON IN AH
  621.     AND    AH,NOT 080H        ;SO YOU CAN STRIP PARITY
  622.     CMP    AH,'a'            ;IS IT GREATER THAN LOWER A?
  623.     JL    NOOUPR            ;NOPE, IT'S NOT LOWER
  624.     CMP    AH,'z'            ;IS IT GREATER THAN LOWER Z?
  625.     JG    NOOUPR            ;NOPE, STILL NOT LOWER
  626.     AND    AL,NOT 020H        ;YES, WHACK OUT THE LOWER BIT.
  627. NOOUPR:
  628. ;
  629. ;        AFTER ALL THE SPECIAL OUTPUT PROCESSING, I DO A HARD WAIT
  630. ;        FOR A SLOT IN THE OUTPUT BUFFER.
  631. WWAIT:
  632.     CALL    PUT_OUT            ;ATTEMPT TO PUT IN IN OUTPUT BUFFER
  633.     CMP    AH,0            ;DID IT WORK?
  634.     JNE    WWAIT            ;NO, KEEP TRYING.
  635.     LOOP    WLUP            ;YES, GO GET NEXT CHAR.
  636.     CALL    START_OUTPUT        ;START THE XMITTER IF NECC.
  637. WRSUCC:
  638.     MOV    AX,0            ;RETURN SUCCESS
  639.     JMP    EXIT
  640. SUBTTL    OUTPUT STATUS REQUEST ROUTINE
  641. ;        OUTPUT STATUS REQUEST
  642. ;
  643. TXSTAT:
  644.     MOV    AX,OFIRST[SI]        ;GET POINTER TO NEXT CHAR OUT
  645.     DEC    AX            ;SUBTRACT ONE FROM IT,
  646.     AND    AX,BUFMSK        ;MODULO 128.
  647.     CMP    AX,OAVAIL[SI]        ;IF THAT EQUALS THE INPUT PNTR,
  648.     JNE    TXROOM
  649.     MOV    AX,STSBSY        ;THEN THE DEVICE IS BUISY.
  650.     JMP    EXIT
  651. TXROOM:
  652.     MOV    AX,0            ;OTHERWIZE THE DEVICE IS OK.
  653.     JMP    EXIT
  654. SUBTTL    I/O CONTROL READ REQUEST
  655. PAGE
  656. ;
  657. ;        IOCONTROL READ REQUEST, RETURN LINE PARAMETERS
  658. ;
  659. IOCTLIN:
  660.     MOV    CX,ES:COUNT[BX]        ;GET THE REQUESTED NUMBER OF BYTES
  661.     MOV    DI,ES:XFER[BX]        ;DI IS OFFSET TO USER BUFFER
  662.     MOV    DX,ES:XSEG[BX]        ;SEGMENT IS LAST I NEED FROM PACKET,
  663.     MOV    ES,DX            ;NOW ES:DI POINTS TO USER BUFFER.
  664.     CMP    CX,10            ;ONLY WORKS WHEN YOU GIVE ME AN
  665.     JE    DOIOCIN            ;10 BYTE BUFFER TO STOMP ON.
  666.     MOV    AX,ERRBSL        ;RETURN AN ERROR IF NOT 10 BYTES.
  667.     JMP    EXIT
  668. DOIOCIN:
  669.     MOV    DX,PORT[SI]        ;GET PORT NUMBER
  670.     ADD    DX,LCTRL        ;SLIDE UP TO LINE CONTROL
  671.     MOV    CX,4            ;SET UP FOR PORT LOOP.
  672. GETPORT:
  673.     IN    AL,DX            ;GET NEXT BYTE FROM DEVICE
  674.     STOS    BYTE PTR [DI]        ;STORE THEM IN USER BUFFER
  675.     INC    DX            ;SKIP TO NEXT BYTE
  676.     LOOP    GETPORT            ;READ AND STORE 4 BYTES OF INFO
  677.  
  678.     MOV    AX,INSPEC[SI]        ;GET THE SPECIAL INPUT BITS
  679.     STOS    WORD PTR [DI]        ;SEND BACK TO USER BUFFER
  680.     MOV    AX,OUTSPEC[SI]        ;GET THE SPECIAL OUTPUT BITS
  681.     STOS    WORD PTR [DI]        ;SEND BACK TO USER BUFFER
  682.     MOV    AX,BAUD[SI]        ;GET BAUD RATE DIVISOR
  683.     MOV    BX,DI            ;SAVE DI FOR A WHILE.
  684.     MOV    DI,OFFSET ASY_BAUDT+2    ;POINT AT BAUD RATE CONVERSION.
  685.     MOV    CX,15            ;JUST IN CASE, STOP AT 15 BAUDS
  686. BAUDCIN:
  687.     CMP    [DI],AX            ;IS THIS THE BAUD I AM USING?
  688.     JE    YESINB            ;YES, RETURN THAT
  689.     ADD    DI,4            ;NO, SKIP TO NEXT ONE
  690.     LOOP    BAUDCIN            ;KEEP LOOKING.
  691. YESINB:            ;SEARCH SHOULD ALWAYS TERMINATE ON COMPARE
  692.     MOV    AX,-2[DI]        ;GET THE ASSOCIATED BAUD RATE
  693.     MOV    DI,BX            ;GET DI'S OLD VALUE BACK
  694.     STOS    WORD PTR [DI]        ;STORE THE BAUD RATE BACK.
  695.     MOV    AX,0            ;RETURN NO ERRORS
  696.     JMP    EXIT
  697.  
  698. ;
  699. ;        FLUSH OUTPUT BUFFER REQUEST
  700. ;
  701. TXFLUSH:
  702.     MOV    AX,OAVAIL[SI]        ;GET NEXT FREE BYTE OFFSET,
  703.     MOV    OFIRST[SI],AX        ;POINT THE FIRST BYTE OFFSET AT IT.
  704.     MOV    AX,0
  705.     JMP    EXIT
  706. SUBTTL    I/O CONTROL WRITE REQUEST ROUTINE
  707. PAGE
  708. ;        IOCONTROL REQUEST: CHANGE LINE PARAMETERS FOR THIS DRIVER
  709. ;
  710. IOCTLOUT:
  711.     MOV    CX,ES:COUNT[BX]        ;GET THE REQUESTED NUMBER OF BYTES
  712.     MOV    DI,ES:XFER[BX]        ;DI IS OFFSET TO USER BUFFER
  713.     MOV    DX,ES:XSEG[BX]        ;SEGMENT IS LAST I NEED FROM PACKET,
  714.     MOV    ES,DX            ;NOW ES:DI POINTS TO USER BUFFER.
  715.     CMP    CX,10            ;ONLY WORKS WHEN YOU GIVE ME A
  716.     JE    DOIOCOUT        ;10 BYTE BUFFER TO READ FROM
  717.     MOV    AX,ERRBSL        ;RETURN AN ERROR IF NOT 10 BYTES.
  718.     JMP    EXIT
  719. DOIOCOUT:
  720.     MOV    DX,PORT[SI]        ;GET PORT NUMBER
  721.     ADD    DX,LCTRL        ;SLIDE UP TO LINE CONTROL
  722.     MOV    AL,ES:[DI]        ;GET LINE CONTROL FROM USER BUF.
  723.     INC    DI
  724.     OR    AL,080H            ;SET DLAB BIT FOR BAUD RATE
  725.     OUT    DX,AL            ;OUTPUT TO DEVICE
  726.     INC    DX            ;SKIP TO NEXT BYTE
  727.     MOV    AL,ES:[DI]        ;GET MODEM CONTROL FROM USER BUF.
  728.     INC    DI
  729.     OR    AL,08H            ;MAKE SURE INTERUPTS ARE ENABLED.
  730.     OUT    DX,AL            ;SEND IT TO DEVICE.
  731.     ADD    DI,2            ;SKIP OVER THE STATUS BYTES
  732.     MOV    AX,ES:[DI]        ;GET THE SPECIAL INPUT BITS
  733.     ADD    DI,2
  734.     MOV    INSPEC[SI],AX        ;STORE THE NEW BITS IN UNIT
  735.     MOV    AX,ES:[DI]        ;GET THE OUTPUT SPECIAL BITS
  736.     ADD    DI,2
  737.     MOV    OUTSPEC[SI],AX        ;STORE THEM ALSO.
  738.     MOV    AX,ES:[DI]        ;GET THE REQUESTED BAUD RATE
  739.     MOV    BX,DI            ;SAVE DI FOR A WHILE.
  740.     MOV    DI,OFFSET ASY_BAUDT    ;POINT AT BAUD RATE CONVERSION
  741.     MOV    CX,15            ;JUST IN CASE, STOP AT 15 BAUDS
  742. BAUDCOUT:
  743.     CMP    [DI],AX            ;IS THIS THE BAUD I AM USING?
  744.     JE    YESOUTB            ;YES, RETURN THAT
  745.     ADD    DI,4            ;NO, SKIP TO NEXT ONE
  746.     LOOP    BAUDCOUT        ;KEEP LOOKING.
  747.     IN    AL,DX            ;GET LINE CONTROL REGESTER AGAIN,
  748.     AND    AL,NOT 080H        ;CLEAR DLAB BIT.
  749.     DEC    DX
  750.     OUT    DX,AL            ;AND WRITE IT BACK OUT.
  751.     MOV    AX,ERRUM        ;RETURN AN ERROR NUMBER IF
  752.     JMP    EXIT            ;BAUD RATE IS NOT IN TABLE.
  753. YESOUTB:
  754.     MOV    AX,2[DI]        ;GET THE ASSOCIATED BAUD RATE
  755.     MOV    BAUD[SI],AX        ;STORE IT IN UNIT TABLE
  756.     MOV    DX,PORT[SI]        ;GET PORT ADDRESS AGAIN,
  757.     OUT    DX,AL            ;WRITE THE LOW BYTE,
  758.     INC    DX            ;SKIP TO NEXT ONE,
  759.     MOV    AL,AH            ;GET HIGH BYTE INTO AL
  760.     OUT    DX,AL            ;OUTPUT IT AS WELL.
  761.     ADD    DX,LCTRL-BAUD1        ;POINT AT THE LINE CONTROL REG.
  762.     IN    AL,DX            ;READ IT IN,
  763.     AND    AL,NOT 080H        ;CLEAR THE DLAB BIT.
  764.     OUT    DX,AL            ;OUTPUT IT BACK.
  765.     MOV    AX,0            ;RETURN NO ERROR
  766.     JMP    EXIT
  767. SUBTTL    RING BUFFER ROUTINES
  768. PAGE
  769. ;        LOCAL ROUTINES FOR MANAGING THE RING BUFFERS ON INPUT
  770. ;    AND OUTPUT.  THE FOLLOWING FOUR ROUTINES ARE ALL CALLED WITH THE
  771. ;    SAME CONTEXT:
  772. ;
  773. ;    DS:SI    POINTS TO THE UNIT STRUCTURE FOR THIS UNIT
  774. ;    AL    IS THE CHARACTER TO BE PLACED IN OR REMOVED FROM A BUFFER
  775. ;    AH    IS THE RETURN STATUS FLAG: 0=SUCESS, -1=FAILURE
  776. ;
  777. ;    ALL OTHER REGESTERS ARE PRESERVED.
  778. ;
  779. PUT_OUT    PROC    NEAR    ;PUTS AL INTO THE OUTPUT RING BUFFER
  780.     PUSH    CX
  781.     PUSH    DI
  782.     PUSHF
  783.     CLI            ;DISABLE INTERUPTS WHILE I HAVE OAVAIL
  784.     MOV    CX,OAVAIL[SI]    ;GET POINTER TO NEXT AVAILABLE BYTE IN
  785.     MOV    DI,CX        ;OUTPUT BUFFER.
  786.     INC    CX        ;INCRIMENT A COPY OF IT TO SEE IF THE
  787.     AND    CX,BUFMSK    ;BUFFER IS FULL.
  788.     CMP    CX,OFIRST[SI]    ;IS IT?
  789.     JE    POERR        ;YES, RETURN AN ERROR
  790.     ADD    DI,OBUF[SI]    ;NO, CALCULATE ACTUAL OFFSET OF CHAR
  791.     MOV    [DI],AL        ;AND STUFF THE CHARACTER INTO BUFFER
  792.     MOV    OAVAIL[SI],CX    ;UPDATE THE POINTER
  793.     MOV    AH,0        ;INDICATE SUCCESS
  794.     JMP    PORET        ;AND RETURN
  795. POERR:
  796.     MOV    AH,-1        ;INDICATE FAILURE.
  797. PORET:
  798.     POPF        ;RE-ENABLE INTERUPTS
  799.     POP    DI
  800.     POP    CX
  801.     RET
  802. PUT_OUT    ENDP
  803.  
  804. GET_OUT    PROC    NEAR    ;GETS THE NEXT CHARACTER FROM OUTPUT RING BUFFER
  805.             ;SURE YOU DISABLE INTERUPTS FIRST.
  806.     PUSH    CX
  807.     PUSH    DI
  808.     PUSHF            ;JUST IN CASE, DISABLE INTERUPTS
  809.     CLI            ;WHILE IN THIS ROUTINE.
  810.     MOV    DI,OFIRST[SI]    ;GET POINTER TO FIRST CHARACTER TO OUTPUT
  811.     CMP    DI,OAVAIL[SI]    ;IS THE BUFFER EMPTY?
  812.     JNE    NGOERR        ;NO.
  813.     MOV    AH,-1        ;YES, INDICATE  FAILURE
  814.     JMP    GORET        ;AND RETURN
  815. NGOERR:
  816.     MOV    CX,DI        ;SAVE A COPY OF THE POINTER
  817.     ADD    DI,OBUF[SI]    ;CALCULATE ACTUAL ADDRESS
  818.     MOV    AL,[DI]        ;GET THE CHAR INTO AL
  819.     MOV    AH,0        ;INDICATE SUCCESS.
  820.     INC    CX        ;INCRIMENT THE OFFSET
  821.     AND    CX,BUFMSK    ;MODULO 128
  822.     MOV    OFIRST[SI],CX    ;STORE BACK IN UNIT TABLE.
  823. GORET:
  824.     POPF
  825.     POP    DI
  826.     POP    CX
  827.     RET
  828. GET_OUT    ENDP
  829.  
  830. PUT_IN    PROC    NEAR    ;PUT THE CHAR FROM AL INTO INPUT RING BUFFER
  831.     PUSH    CX
  832.     PUSH    DI
  833.     PUSHF            ;DISABLE INTS WHILE IN THIS ROUTINE
  834.     CLI
  835.     MOV    DI,IAVAIL[SI]    ;GET POINTER TO NEXT AVAILABLE SLOT IN BUFFER
  836.     MOV    CX,DI        ;SAVE A COPY OF IT,
  837.     INC    CX        ;AND INCRIMENT THAT COPY (MODULO
  838.     AND    CX,BUFMSK        ;128) TO SEE IF THE BUFFER IS FULL.
  839.     CMP    CX,IFIRST[SI]    ;WELL, IS IT?
  840.     JNE    NPIERR        ;NO, THERE`S ROOM.
  841.     MOV    AH,-1        ;YES, INDICATE FAILURE
  842.     JMP    PIRET        ;AND RETURN
  843. NPIERR:
  844.     ADD    DI,IBUF[SI]    ;CALCULATE ACTUAL ADDRES,
  845.     MOV    [DI],AL        ;STORE THE CHARACTER THERE
  846.     MOV    IAVAIL[SI],CX    ;UPDATE THE POINTER.
  847.     MOV    AH,0        ;AND INDICATE SUCCESS.
  848. PIRET:
  849.     POPF
  850.     POP    DI
  851.     POP    CX
  852.     RET
  853. PUT_IN    ENDP
  854.  
  855. GET_IN    PROC    NEAR    ;GETS ONE CARACTER FROM INPUT RING BUFFER INTO AL
  856.     PUSH    CX
  857.     PUSH    DI
  858.     PUSHF
  859.     CLI        ;DISABLE INTERUPTS WHILE I LOOK AT IFIRST.
  860.     MOV    DI,IFIRST[SI]    ;GET POINTER TO FIRST CHAR TO READ
  861.     CMP    DI,IAVAIL[SI]    ;IS THE BUFFER EMPTY?
  862.     JE    GIERR        ;THEN YOU CAN`T VERY WELL SQUEEZE WATER OUT OF IT
  863.     MOV    CX,DI        ;MAKE A COPY OF POINTER,
  864.     ADD    DI,IBUF[SI]    ;CALCULATE ACTUAL ADDRESS OF CHAR
  865.     MOV    AL,[DI]        ;GET THE CHAR INTO AL
  866.     MOV    AH,0        ;INDICATE SUCCESS
  867.     INC    CX        ;INCRIMENT THAT COPY OF YOUR POINTER,
  868.     AND    CX,BUFMSK    ;MODULO THE BUFFER SIZE,
  869.     MOV    IFIRST[SI],CX    ;SO YOU CAN UPDATE THE POINTER.
  870.     JMP    GIRET
  871. GIERR:
  872.     MOV    AH,-1        ;RETURN FAILURE INDICATOR
  873. GIRET:
  874.     POPF        ;RE-ENABLE INTERUPTS BEFORE YOU RETURN
  875.     POP    DI
  876.     POP    CX
  877.     RET
  878. GET_IN    ENDP
  879. SUBTTL    INTERUPT SERVICE ROUTINES
  880. PAGE
  881. ;        THE FOLLOWING ROUTINES ARE  WHAT I REALLY CALL AN INTERUPT
  882. ;    ROUTINE!  THESE ROUTINES ARE ONLY CALLED WHEN AN INTERUPT IS GENERATED
  883. ;    BY THE 8088, NOT BY A SOFWARE CALL THROUGH A LINKED LIST! ONE EASY
  884. ;    WAY TO TELL A REAL INTERUPT ROUTINE WHEN YOU SEE IT IS TO LOOK AT THE
  885. ;    LAST INSTRUCTION, WHICH IS AN "INTERUPT RETURN",  NOT A FAR RETURN
  886. ;    LIKE THE SO-CALLED MSDOS "INTERUPT ROUTINE" DOES.
  887. ;    THESE INTERUPT ROUTINES ARE ENVOKED WHENEVER A CHAR ARRIVES IN THE
  888. ;    UART, THE UART FINISHES SENDING A CHARACTER OUT, AN ERROR OCCURS
  889. ;    WHILE READING A CHARACTER INTO THE UART, OR THE MODEM STATUS LINES
  890. ;    CHANGE.
  891.  
  892. ASY1ISR:
  893.     CLI
  894.     PUSH    SI
  895.     LEA    SI,ASY_TAB1    ;POINT AT THE CORRECT TABLE FOR THIS UART,
  896.     JMP    INT_SERVE    ;JUMP INTO THE COMMON INTERUPT SERVER CODE.
  897. ASY2ISR:
  898.     CLI
  899.     PUSH    SI
  900.     LEA    SI,ASY_TAB2    ;GET UNIT TABLE
  901. ;
  902. ;            IF YOU ADD MORE UNITS, YOU CAN ADD THEM HERE,
  903. ;            BUT DON'T FORGET TO ADD A JUMP INT_SERVE AFTER
  904. ;            ASY2ISR'S LEA INSTRUCTION!
  905. ;
  906. ;        THE FOLLOWING CODE IS THE COMMON SHARED CODE THAT ALL THE
  907. ;    ASYNC PORTS SHARE.  IT "KNOWS" WHICH ONE TO TALK TO BY REFERENCING
  908. ;    THE STRUCTURE POINTED TO BY CS:SI.
  909.  
  910. INT_SERVE:
  911.     PUSH    AX    ;PUSH ALL THE GP REGESTERS
  912.     PUSH    BX
  913.     PUSH    CX
  914.     PUSH    DX
  915.     PUSH    DI
  916.     PUSH    DS    ;SAVE THE DATA SEGMENT
  917.     PUSH    CS    ;SO YOU CAN LOAD CS
  918.     POP    DS    ;INTO DS AND FIND YOUR OWN STRUCTURES.
  919. INT_EXIT:
  920.     MOV    DX,PORT[SI]    ;GET THE PORT ADDRESS OF THIS DEVICE
  921.     ADD    DX,INTID    ;SLIDE UP TO THE INTERUPT ID REGISTER
  922.     IN    AL,DX        ;GET THE INTERUPT REASON
  923.     TEST    AL,1        ;MAKE SURE IT IS VALID
  924.     JNE    INT_DONE    ;IT IS NOT.
  925.     MOV    AH,0        ;CONVERT IT TO A 16 BIT NUMBER
  926.     ADD    AX,OFFSET INT_REASON    ;ADD IT TO THE JUMP TABLE ADDRESS
  927.     MOV    DI,AX        ;PUT IT IN AN INDEX REGESTER,
  928.     JMP    [DI]        ;AND GO PROCESS THAT TYPE OF INTERUPT
  929.  
  930. INT_DONE:
  931.     ADD    DX,LSTAT-INTID    ;BECAUSE IT SEEMS TO BE NECESSARY,
  932.     IN    Al,DX        ;READ THE STATUS PORT BEFORE YOU EXIT.
  933.     MOV    AL,020H        ;OUTPUT A 20H TO THE UNDOCUMENTED INTERUPT
  934.     OUT    020H,AL        ;COMMAND PORT TO ENABLE FURTHER INTERUPTS?
  935.     POP    DS    ;RECOVER ALL THE REGESTERS
  936.     POP    DI
  937.     POP    DX
  938.     POP    CX
  939.     POP    BX
  940.     POP    AX
  941.     POP    SI
  942.     IRET
  943.  
  944. ;
  945. ;        JUMP TABLE OF INTERUPT REASONS. INTERUPT ID REGISTER
  946. ;        IS USED AS INDEX TO THIS TABLE.
  947. INT_REASON:
  948.     DW    INT_MODEM    ;INT WAS CAUSED BY A MODEM LINE TRANSITION
  949.     DW    INT_TXMIT    ;INT WAS CAUSED BY A TX REGISTER EMPTY
  950.     DW    INT_RECEIVE    ;NEW CHARACTER AVAILABLE IN UART
  951.     DW    INT_RXSTAT    ;CHANGE IN RECEIVER STATUS REGESTER
  952. SUBTTL    RECEIVER INTERUPT SERVICE ROUTINE
  953. PAGE
  954. ;
  955. ;        THE INTERUPT SERVICE ROUTINES BELOW ALL HAVE THE
  956. ;    FOLLOWING CONTEXT:
  957. ;    -CS AND DS POINT TO THE DRIVER SEGMENT.
  958. ;    -DS:[SI] POINTS TO THE UNIT STRUCTURE FOR THE ASYNC LINE THAT
  959. ;        FIRED THE INTERUPT.
  960. ;    -AX BX CX DX AND DI ARE AVAILABLE FOR SCRATCH.  ALL OTHERS
  961. ;        MUST BE LEFT ALONE OR SAVED AND RECOVERED.
  962. ;    TO EXIT FROM AN INTERUPT SERVICE ROUTINE, THESE SERVERS MUST
  963. ;    JUMP TO INT_EXIT.
  964. ;
  965. SUBTTL    RECEIVER INTERUPT SERVICE ROUTINE
  966. INT_RECEIVE:    ;THE UART HAS RECEIVED A NEW CHARACTER, I MUST COPY IT
  967.         ;INTO THE INPUT TYPEAHEAD BUFFER.
  968.     MOV    DX,PORT[SI]    ;POINT DX BACK AT THE RXBUF REGESTER
  969.     IN    AL,DX        ;GET THE CHARACTER
  970. ;
  971. ;            BEFORE I STORE THE CHARACTER BACK IN THE RING
  972. ;            BUFFER, I CHECK TO SEE IF ANY OF THE SPECIAL
  973. ;            INPUT SEQUENCES ARE ENABLED, AND IF THEY
  974. ;            HAVE BEEN FOUND IN THE INPUT.
  975. ;
  976. ;
  977. ;        CHECK FOR XON/XOFF
  978. ;
  979.     TEST    OUTSPEC[SI],OUTXON    ;IS XON/XOFF ENABLED?
  980.     JE    NOXON            ;NO, SKIP THIS WHOLE SECTION
  981.     CMP    AL,'S' AND 01FH        ;IS THIS A CONTROL-S?
  982.     JNE    ISQ            ;NO, CHECK FOR CONTROL-Q
  983.     OR    LINE[SI],LINXOF        ;DISABLE OUTPUT.
  984.     JMP    INT_EXIT        ;DON'T STORE THIS CHAR.
  985. ISQ:
  986.     CMP    AL,'Q' AND 01FH        ;IS THIS A CONTROL-Q?
  987.     JNE    NOXON            ;NO, SKIP TO THE NEXT TEST.
  988.     TEST    LINE[SI],LINXOF        ;AM I WAITING FOR THIS ^Q?
  989.     JE    INT_EXIT        ;NO, DON'T STIR UP DRIVER.
  990.     AND    LINE[SI],NOT LINXOF    ;CLEAR THE XOFF BIT,
  991.     CALL    START_OUTPUT
  992.     JMP    INT_EXIT        ;DON'T BUFFER ^Q'S
  993. NOXON:
  994. ;
  995. ;        CHECK FOR THE SKIP OUTPUT ESCAPE SEQUENCE
  996. ;
  997.     TEST    INSPEC[SI],INCTO    ;IS THIS ENABLED?
  998.     JE    NOCTO            ;NOPE.
  999.     MOV    DI,SKIPP[SI]        ;GET OFFSET TO NEXT CHAR
  1000.     MOV    SKIPP[SI],0        ;RESET RECOG. OF THIS SEQ.
  1001.     CMP    SKIPO[DI],AL        ;THIS IT?
  1002.     JNE    NOCTO            ;NOPE, GO CHECK FOR OTHERS.
  1003.     INC    DI            ;YES, INCRIMENT TO NEXT CHAR.
  1004.     CMP    SKIPO[DI],0        ;WAS THAT THE LAST ONE?
  1005.     JNE    NEXTO            ;NO, PASS THIS CHAR ON.
  1006.     XOR    LINE[SI],LINSKP        ;YES, TOGGLE THE SKIP BIT.
  1007.     CALL    START_OUTPUT        ;RATTLE THE XMITTERS CAGE.
  1008. INT_EXIT3:
  1009.     JMP    INT_EXIT        ;AND EXIT.
  1010. NEXTO:
  1011.     MOV    SKIPP[SI],DI        ;SET OFFSET TO NEXT CHAR.
  1012. NOCTO:
  1013.  
  1014. ;
  1015. ;        CHECK FOR THE FLUSH INPUT BUFFER SEQUENCE.
  1016. ;
  1017.     TEST    INSPEC[SI],INCTX    ;IS THIS ENABLED?
  1018.     JE    NOCTX            ;NOPE.
  1019.     MOV    DI,FLSHP[SI]        ;GET OFFSET TO NEXT CHAR
  1020.     MOV    FLSHP[SI],0        ;RESET RECOG. OF THIS SEQ.
  1021.     CMP    FLUSH[DI],AL        ;THIS IT?
  1022.     JNE    NOCTX            ;NOPE, GO CHECK FOR OTHERS.
  1023.     INC    DI            ;YES, INCRIMENT TO NEXT CHAR.
  1024.     CMP    FLUSH[DI],0        ;WAS THAT THE LAST ONE?
  1025.     JNE    NEXTX            ;NO, PASS THIS CHAR ON.
  1026.     MOV    AX,IFIRST[SI]        ;YES! FLUSH THE BUFFER BY
  1027.     MOV    IAVAIL[SI],AX        ;POINTING INPUT TO OUTPUT.
  1028.     JMP    INT_EXIT        ;AND EXIT.
  1029. NEXTX:
  1030.     MOV    FLSHP[SI],DI        ;SET OFFSET TO NEXT CHAR.
  1031. NOCTX:
  1032. ;
  1033. ;        CHECK FOR THE RE-BOOT SYSTEM ESCAPE SEQUENCE.
  1034. ;
  1035.     TEST    INSPEC[SI],INRES    ;IS THIS ENABLED NOW?
  1036.     JE    NOREB            ;NO.
  1037.     MOV    DI,REBTP[SI]        ;GET OFFSET TO NEXT CHAR
  1038.     MOV    REBTP[SI],0        ;RESET RECOG. OF THIS SEQ.
  1039.     CMP    REBOOT[DI],AL        ;THIS IT?
  1040.     JNE    NOREB            ;NOPE, GO CHECK FOR OTHERS.
  1041.     INC    DI            ;YES, INCRIMENT TO NECT CHAR.
  1042.     CMP    REBOOT[DI],0        ;WAS THAT THE LAST ONE?
  1043.     JNE    NEXTB            ;NO, PASS THIS CHAR ON.
  1044.     MOV    AX,0            ;YES, SET UP TO DO A KEYBOARD
  1045.     MOV    DS,AX            ;RESET.
  1046.     ASSUME    DS:VECS
  1047.     MOV    AX,1232H        ;GET THE QUICK BOOT FLAG,
  1048.     MOV    FLAG,AX            ;WARN RESET THIS IS QUICK BOOT
  1049.     JMP    RE_BOOT            ;JUMP TO THE RE-BOOT VECTOR.
  1050.  
  1051. NEXTB:
  1052.     MOV    REBTP[SI],DI        ;SET OFFSET TO NEXT CHAR.
  1053. NOREB:
  1054. ;
  1055. ;        CHECK FOR THE RE-DRAW LAST LINE SEQUENCE.
  1056. ;
  1057.     TEST    INSPEC[SI],INCTR    ;IS THIS ENABLED?
  1058.     JE    NOCTR            ;NOPE.
  1059.     MOV    DI,REDRP[SI]        ;YES, GET POINTER TO NEXT
  1060.     MOV    REDRP[SI],0        ;RESET IN CASE THIS ISNT IT.
  1061.     CMP    REDRAW[DI],AL        ;IS THIS THE NEXT CHAR?
  1062.     JNE    NOCTR            ;NO.
  1063.     INC    DI            ;YES, INCRIMENT TO NEXT
  1064.     CMP    REDRAW[DI],0        ;WAS THAT THE LAST ONE?
  1065.     JNE    NEXTR            ;NO, PASS THIS CHAR ON.
  1066.     MOV    DI,OFIRST[SI]        ;YES, THEN SEARCH BACKWARDS
  1067.     MOV    BX,OBUF[SI]        ;FOR THE LAST CR.
  1068. CRLUP:
  1069.     DEC    DI            ;STEP BACK ONE CHAR IN TIME
  1070.     AND    DI,BUFMSK        ;(MODULO THE BUFFER SIZE)
  1071.     CMP    DI,OAVAIL[SI]        ;BUT STOP IF YOU BACK INTO
  1072.     JE    NOCTR            ;THE OTHER END OF BUFFER
  1073.     CMP    BYTE PTR [BX+DI],0DH    ;IS THIS A CR?
  1074.     JNE    CRLUP            ;NO, KEEP LOOKING.
  1075.     MOV    OFIRST[SI],DI        ;YES, SET BUFFER BACK.
  1076.     CALL    START_OUTPUT        ;AND MAKE SURE XMITTER SEES IT.
  1077. INT_EXIT2:
  1078.     JMP    INT_EXIT
  1079. NEXTR:
  1080.     MOV    REDRP[SI],DI        ;UPDATE PTR TO PARTIAL SEQ.
  1081. NOCTR:
  1082. ;
  1083. ;        CHECK FOR THE ERASE TO BEGENING OF LINE ESCAPE SEQ.
  1084. ;
  1085.     TEST    INSPEC[SI],INCTU    ;IS THIS ENABLED?
  1086.     JE    NOCTU            ;NOPE.
  1087.     MOV    DI,BACKP[SI]        ;YES, GET POINTER TO NEXT
  1088.     MOV    BACKP[SI],0        ;RESET IN CASE THIS ISNT IT.
  1089.     CMP    BACKL[DI],AL        ;IS THIS THE NEXT CHAR?
  1090.     JNE    NOCTU            ;NO.
  1091.     INC    DI            ;YES, INCRIMENT TO NEXT
  1092.     CMP    BACKL[DI],0        ;WAS THAT THE LAST ONE?
  1093.     JNE    NEXTU            ;NO, PASS THIS CHAR ON.
  1094.     MOV    DI,IFIRST[SI]        ;YES, THEN SEARCH BACKWARDS
  1095.     MOV    BX,IBUF[SI]        ;FOR THE LAST CR.
  1096.     MOV    CX,-1            ;COUNTING THEM IN CX.
  1097. BCRLUP:
  1098.     INC    CX
  1099.     DEC    DI            ;STEP BACK ONE CHAR IN TIME
  1100.     AND    DI,BUFMSK        ;(MODULO THE BUFFER SIZE)
  1101.     CMP    DI,IAVAIL[SI]        ;BUT STOP IF YOU BACK INTO
  1102.     JE    NOCTU            ;THE OTHER END OF BUFFER
  1103.     CMP    BYTE PTR [BX+DI],0DH    ;IS THIS A CR?
  1104.     JNE    BCRLUP            ;NO, KEEP LOOKING.
  1105.             ;NOW CX CONTAINS THE NUMBER OF CHARACTERS TO
  1106.             ;DELETE.  I DO THIS THE DUMB WAY: BY SENDING
  1107.             ;THAT MANY BACKSPACE CHARACTERS
  1108.     MOV    AL,8            ;PUT A BACKSPACE IN AL
  1109. BAKLUP:
  1110.     CALL    PUT_IN            ;PUT IT IN THE INPUT BUFFER
  1111.     LOOP    BAKLUP            ;PUT IN A BUNCH OF THEM
  1112.     JMP    INT_EXIT        ;WON'T MSDOS BE SUPRISED?
  1113. NEXTU:
  1114.     MOV    BACKP[SI],DI        ;UPDATE PTR TO PARTIAL SEQ.
  1115. NOCTU:
  1116. ;
  1117. ;        NONE OF THE SPECIAL INPUT SEQUENCES PANNED OUT, SO
  1118. ;        I'LL JUST STUFF THE CHARACTER INTO THE INPUT RING 
  1119. ;        BUFFER THIS TIME.
  1120. STUFF_IN:
  1121.     CALL    PUT_IN        ;PUT THE CHARACTER IN THE RING BUFFER
  1122.     CMP    AH,0        ;WAS THERE ROOM?
  1123.     JE    INT_EXIT2    ;YES, JUST RETURN
  1124.     OR    MODEM[SI],MODOVR    ;NO, SET THE OVERFLOW BIT
  1125.     TEST    INSPEC[SI],INBEL ;ARE OVERFLOW BELLS ENABLED?
  1126.     JE    INT_EXIT2    ;NO, SKIP IT.
  1127.     TEST    LINE[SI],LINEXP    ;IS XMITTER EXPECTING AN INTERUPT?
  1128.     JNE    INT_EXIT2    ;YES, LEAVE HIM ALONE.
  1129.     MOV    AL,7        ;NO, SEND A BELL IMMEDIATELY
  1130.     MOV    DX,PORT[SI]    ;GET PORT ADDRESS,
  1131.     OUT    DX,AL        ;AND SEND A CHAR TO XMITTER TO START 
  1132.     OR    LINE[SI],LINEXP    ;SET INTERUPT EXPECTED BIT.
  1133.     JMP    INT_EXIT
  1134. SUBTTL    RECEIVER LINE STATUS INTERUPT ROUTINE
  1135. PAGE
  1136. ;        THE LSTAT REGISTER DETECTED A RECEIVER ERROR CONDITION
  1137. INT_RXSTAT:
  1138.     ADD    DX,LSTAT-INTID    ;READ THE REGESTER AND FIND OUT WHY
  1139.     IN    AL,DX
  1140.     TEST    INSPEC[SI],INEPC    ;DO I RETURN THEM AS CODES?
  1141.     JE    NOCODE            ;NO, WHAT ELSE?
  1142.     AND    AL,01EH            ;YES, MASK OFF ALL BUT ERROR BITS,
  1143.     OR    AL,080H            ;SET THE PARITY BIT TO MAKE IT
  1144.                     ;AN ILLEGAL CHARACTER,
  1145.     JMP    STUFF_IN        ;AND PUT IT IN THE INPUT BUFFER.
  1146. NOCODE:
  1147.     OR    MODEM[SI],MODERR    ;SET A STATUS BIT THAT WILL
  1148.                     ;NOTIFY MSDOS ON THE NEXT REQUEST
  1149.     JMP    INT_EXIT
  1150. PAGE
  1151. SUBTTL    MODEM STATUS INTERUPT SERVICE ROUTINE
  1152. ;        THE MODEM STATUS REGESTER DETECTED A CHANGE IN ONE OF THE
  1153. ;    MODEM LINES.  I COULD CHECK THE "DELTA BITS" TO SEE EXACTLY WHICH
  1154. ;    LINE TRIGGERED THIS INTERUPT, BUT I JUST CHECK ALL OF THEM WHEN
  1155. ;    I GET ANY MODEM STATUS INTERUPT.
  1156. INT_MODEM:
  1157.     ADD    DX,MSTAT-INTID    ;READ THE MODEM STATUS REGESTER
  1158.     IN    AL,DX
  1159.             ;*********************************
  1160.             ;CHECK THE CARIER-DETECT BIT (CD)
  1161.     TEST    AL,080H        ;IS CARRIER DETECT OFF?
  1162.     JNE    MSDSR        ;NO, CHECK DSR NEXT
  1163.     TEST    OUTSPEC[SI],OUTCDF    ;IS CD THE OFF-LINE SIGNAL?
  1164.     JE    MSDSR        ;NO, IGNORE CD THEN.
  1165.     OR    MODEM[SI],MODOFF    ;YES,SET OFLINE FOR NEXT READ REQUEST
  1166.             ;**************************************
  1167.             ;CHECK THE DATA-SET-READY BIT (DSR)
  1168. MSDSR:
  1169.     TEST    AL,020H        ;IS DSR OFF?
  1170.     JNE    DSRON        ;NO, GO CHECK TO SEE IF I WAS WAITING ON IT.
  1171.     TEST    OUTSPEC[SI],OUTDSR    ;IS DSR THE OUTPUT DATA THROTTLE FLG?
  1172.     JE    DSROFF            ;NO, MABY IT'S OFFLINE SIGNAL
  1173.     OR    LINE[SI],LINDSR        ;YES, SUSPEND OUTPUT WAITING ON DSR
  1174. DSROFF:
  1175.     TEST    OUTSPEC[SI],OUTDRF    ;IS DSR THE OFFLINE SIGNAL?
  1176.     JE    MSCTS            ;NOPE.
  1177.     OR    MODEM[SI],MODOFF    ;YES, SET FLAG FOR NEXT READ.
  1178.     JMP    MSCTS
  1179. DSRON:
  1180.     TEST    LINE[SI],LINDSR        ;WAS I WAITING FOR DSR TO COME ON?
  1181.     JE    MSCTS            ;NO, IGNORE IT.
  1182.     AND    LINE[SI],NOT LINDSR    ;YES, CLEAR THE BIT, AND
  1183.     CALL    START_OUTPUT        ;START OUTPUT BACK UP AGAIN.
  1184.             ;****************************************
  1185.             ;CHECK THE CLEAR-TO-SEND BIT (CTS)
  1186. MSCTS:
  1187.     TEST    AL,010H            ;IS CTS OFF?
  1188.     JNE    CTSON            ;NO, GO CHECK TO SEE IF ITS EXPECTED
  1189.     TEST    OUTSPEC[SI],OUTCTS    ;IS CSR THE OUTPUT DATA THROTTLER?
  1190.     JE    CTSOFF            ;NO, MABY IT'S OFFLINE SIGNAL
  1191.     OR    LINE[SI],LINCTS        ;YES, SUSPEND OUTPUT.
  1192. CTSOFF:
  1193.     TEST    OUTSPEC[SI],OUTCTS    ;IS CTS THE OFF-LINE SIGNAL?
  1194.     JE    INT_EXIT4        ;NOPE.
  1195.     OR    MODEM[SI],MODOFF    ;YES, SET FLAG FOR NEXT READ.
  1196.     JMP    INT_EXIT
  1197. CTSON:
  1198.     TEST    LINE[SI],LINCTS        ;WAS I WAITING FOR THIS CTS?
  1199.     JE    INT_EXIT4        ;NO, THERE'S NOTHING LEFT TO CHECK.
  1200.     AND    LINE[SI],NOT LINCTS    ;YES, CLEAR THE BIT, AND
  1201.     CALL    START_OUTPUT        ;START OUTPUT UP AGAIN.
  1202. INT_EXIT4:
  1203.     JMP    INT_EXIT
  1204. SUBTTL    TRANSMITTER INTERUPT SERVICE ROUTINE
  1205. PAGE
  1206. ;        THE TRANSMITTER HOLDING REGESTER IS EMPTY, LOOK TO SEE IF
  1207. INT_TXMIT:    ;THERE ARE MORE CHARS TO PRINT NOW.
  1208.     AND    LINE[SI],NOT LINEXP    ;CLEAR INTERUPT EXPECTED BIT.
  1209.     CALL    START_OUTPUT        ;START THE NEXT CHARACTER
  1210.     JMP    INT_EXIT
  1211.  
  1212. ;ROUTINE TO START THE NEXT CHARACTER PRINTING ON THE UART, IF OUTPUT
  1213. ;IS NOT BEING SUSPENDED FOR ONE REASON OR ANOTHER.
  1214. ;THIS ROUTINE MAY BE CALLED FROM REQUEST ROUTINES, OR FROM INTERUPT
  1215. ;SEVICE ROUTINES.
  1216. ;    THIS ROUTINE DESTROYS AX AND DX.
  1217. ;    SX MUST POINT AT THE UNIT STRUCTURE.
  1218. START_OUTPUT    PROC    NEAR
  1219.     PUSHF                ;SAVE THE FLAGS SO I CAN
  1220.     CLI                ;DISABLE INTERUPTS
  1221.     TEST    LINE[SI],LINIDL        ;AM I IN HOLD OUTPUT MODE?
  1222.     JNE    DONT_START        ;YES, DON'T SEND ANY MORE CHARS.
  1223.     CALL    GET_OUT        ;CHECK TO SEE IF THERE IS A CHAR IN THE BUF
  1224.     CMP    AH,0        ;WELL, WAS THERE?
  1225.     JNE    DONT_START    ;NO, BUFFER IS EMPTY
  1226.     MOV    DX,PORT[SI]    ;YES, POINT DX AT THE TX OUT REGISTER
  1227.     OUT    DX,AL        ;SEND HIM THE CHARACTER
  1228.     OR    LINE[SI],LINEXP        ;WARN EVERYBODY THAT I'M BUSY.
  1229. DONT_START:
  1230.     POPF
  1231.     RET
  1232. START_OUTPUT    ENDP
  1233.  
  1234. ;        THE FOLLOWING LABEL DEFINES THE END OF THE DRIVER, SO I
  1235. ;        CAN TELL DOS HOW BIG I AM.
  1236. ASYNC_END:
  1237. SUBTTL    INITIALIZATION REQUEST ROUTINE
  1238. PAGE
  1239. ;
  1240. ;        THE INITIALIZE DRIVER ROUTINE IS STORED AFTER THE "END"
  1241. ;    OF THE DRIVER HERE SO THAT THIS CODE CAN BE THROWN AWAY AFTER
  1242. ;    THE DEVICE HAS BEEN INITIALIZED.  THIS CODE IS ONLY CALLED TWICE:
  1243. ;    ONCE TO INITIALIZE EACH OF THE ASYNC UNITS THAT THIS DRIVER
  1244. ;    CONTAINS.  (HOPEFULLY, MSDOS DOESN'T WRITE ANYTHING ON TOP OF
  1245. ;    THIS CODE UNIT BOTH UNITS ARE INITIALIZED.
  1246. ;        THE CONTEXT OF THE INITIALIZE CODE BELOW IS THE SAME AS
  1247. ;    ALL THE OTHER REQUEST ROUTINES EARLIER IN THE DRIVER.
  1248. ;
  1249. ;        INITIALIZE THE DRIVER AND DEVICE
  1250. ;
  1251. ASYNC_INIT:
  1252.     MOV    AX,OFFSET ASYNC_END    ;GET THE SIZE OF THE DRIVER
  1253.     MOV    ES:XFER[BX],AX        ;SEND THAT BACK IN PACKET
  1254.     MOV    ES:XSEG[BX],CS        ;SEND THE CODE SEGMENT ALSO.
  1255.                 ;I HAVE SATISFIED ALL THE REQIREMENTS OF THE
  1256.                 ;INIT FUNCTION TO RETURN IN THE I/O PACKET, SO
  1257.                 ;I CAN DESTROY THE CONTENTS OF ES:BX AND USE
  1258.                 ;THEM FOR OTHER THINGS.
  1259.     MOV    AX,0            ;POINT ES AT THE VECTOR SEGMENT
  1260.     MOV    ES,AX            ;SO CAN INITIALIZE THE VECTORS
  1261.     MOV    AX,ISRADR[SI]        ;GET ADRS OF INTERUPT SERVICE ROUTINE
  1262.                 ;THE FOLLOWING CODE IS SPECIFIC TO THE IBM:
  1263.                 ;BASIC USES LOCATIONS 400 AND 402 TO FIND
  1264.                 ;THE PORT ADDRESSES OF COM1 AND COM2. IF I
  1265.                 ;ZERO THESE, THEN BASIC CANNOT MUCK UP THE
  1266.                 ;REGESTERS ON ME ANY MORE!  (IT STILL
  1267.                 ;DISABLES INTERUPTS, THOUGH.  BUMMER!)
  1268.     MOV    DI,400            ;POINT AT THE ASYNC ADDRESS LIST
  1269.     CLD
  1270.     STOS    WORD PTR [DI]        ;CLOBBER THE FIRST ONE,
  1271.     STOS    WORD PTR [DI]        ;AND THE SECOND ONE.
  1272.                 ;NOW WE'RE BACK ON THE GENERIC MSDOS TRACK.
  1273.     MOV    DI,VECT[SI]        ;GET ADRS OF VECOTR,
  1274.     STOS    WORD PTR [DI]        ;STORE THE OFFSET THERE, THEN
  1275.     MOV    ES:[DI],CS        ;THE SEGMENT IN THE FOLLOWING WORD.
  1276.     MOV    CX,DI            ;GET THE VECTOR NUMBER,
  1277.     SUB    CL,022H            ;SUBTRACT BIAS TO HARDWARE INTS,
  1278.     SAR    CL,1            ;DIVIDE BY 4 TO CONVERT TO
  1279.     SAR    CL,1            ;HARDWARE INTERUPT NUMBER.
  1280.     MOV    AH,1            ;SHIFT A MASK BY THAT MUCH TO
  1281.     SAL    AH,CL            ;CREATE INTERUPT ENABLE MASK BIT,
  1282.     NOT    AH            ;WHICH IS ACTIVE LOW...
  1283.     IN    AL,021H            ;GET SYSTEM HARDWARE INTERUPT MASK
  1284.     AND    AL,AH            ;AND MY BIT OUT OF IT,
  1285.     OUT    021H,AL            ;WRITE IT BACK OUT AGAIN.
  1286.     MOV    DX,PORT[SI]        ;GET THE PORT ADDRESS OF THIS LINE
  1287.     ADD    DX,INTID
  1288. INT_CAN:
  1289.     IN    AL,DX            ;GET INTERUPT ID REGESTER
  1290.     TEST    AL,1            ;IF HE HAS ANYTHING TO COMPLAINE
  1291.     JNZ    INT_NONE        ;ABOUT, READ THEM ALL AND IGNORE.
  1292.     ADD    DX,LSTAT-INTID        ;JUST TO MAKE UART HAPPY, READ THE
  1293.     IN    AL,DX            ;LINE STATUS AND
  1294.     ADD    DX,MSTAT-LSTAT        ;THE MODEM STATUS TO
  1295.     IN    AL,DX            ;"RESET INTERUPT CONTROL"
  1296.     ADD    DX,RXBUF-MSTAT        ;READING THE RECEIVER MIGHT
  1297.     IN    AL,DX            ;HELP ALSO.
  1298.     ADD    DX,INTID-RXBUF        ;POINT BACK AT INTERUPT ID,
  1299.     JMP    INT_CAN            ;AND DO THIS AGAIN.
  1300. INT_NONE:
  1301.     ADD    DX,LSTAT-INTID        ;CALC ADDRESS OF LINE STATUS,
  1302.     IN    AL,DX            ;INPUT IT OR SOMETIMES IT DOESN'T WORK
  1303.  
  1304.     ADD    DX,LCTRL-LSTAT        ;CALC ADDRESS OF LINE CONTROL REG
  1305.     MOV    AL,LINE[SI]        ;GET THE DEFAULT LINE 
  1306.     OR    AL,DLAB            ;SET THE DIVISOR LATCH BIT
  1307.     OUT    DX,AL            ;SET UP DEFAULT LINE CHARS
  1308.     SUB    DX,LCTRL        ;POINT BACK AT FIRST PORT
  1309.     MOV    AX,BAUD[SI]        ;GET DIVISOR VALUE FOR BAUD RATE
  1310.     OUT    DX,AL            ;SEND LOW BYTE
  1311.     INC    DX            ;INC TO HIGH BYTE PORT
  1312.     MOV    AL,AH            ;GET HIGH BYTE,
  1313.     OUT    DX,AL            ;AND SEND TO BOARD.
  1314.     ADD    DX,LCTRL-1        ;POINT AT LINE CONTROL AGAIN,
  1315.     MOV    AL,LINE[SI]        ;GET DEFAULT LINE CONTROL BITS AGAIN
  1316.     OUT    DX,AL            ;SET THEM WITHOUT DLAB ON.
  1317.     MOV    LINE[SI],0        ;RE-USE LINE OFFSET AS STATUS
  1318.     SUB    DX,LCTRL-INTEN        ;POINT DX AT INTERUPT ENABLE PORT
  1319.     MOV    AL,ALLINT        ;SET UP TO GET ALL POSSIBLE INTS
  1320.     OUT    DX,AL            ;IN THE INTEN REGESTER.
  1321.     ADD    DX,MCTRL-INTEN        ;POINT AT MODEM STATUS REGESTER
  1322.     MOV    AL,MODEM[SI]        ;GET THE DEFAULT MODEM STATUS BITS,
  1323.     OUT    DX,AL            ;AND SET THEM IN MCTRL.
  1324.     MOV    MODEM[SI],0        ;RE-USE THIS BYTE FOR INPUT STATUS.
  1325.     TEST    INSPEC[SI],INXON    ;IS INPUT THROTTLED WITH XON?
  1326.     JE    DONE_INIT        ;NO, LEAVE HIM BE.
  1327.     MOV    AL,'Q' AND 01FH        ;YES, SEND A CONTROL-Q
  1328.     MOV    DX,PORT[SI]        ;TO THE DEVICE AT INIT TIME,
  1329.     OUT    DX,AL            ;TO MAKE SURE IT WAKES UP.
  1330. DONE_INIT:
  1331.     MOV    AX,0            ;RETURN NO ERRORS.
  1332.     JMP    EXIT
  1333.  
  1334. DRIVER    ENDS
  1335.     END
  1336.