Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1374 lines
32 KiB

  1. page,132
  2. ;---------------------------Module-Header-------------------------------
  3. ; Module Name: IBMINT.ASM
  4. ;
  5. ; Created: Fri 06-Feb-1987 10:45:12
  6. ; Author: Walt Moore [waltm]
  7. ;
  8. ; Copyright (c) Microsoft Corporation 1985-1990. All Rights Reserved
  9. ;
  10. ; General Description:
  11. ; This file contains the interrupt time routines for the
  12. ; IBM Windows communications driver.
  13. ;
  14. ; The interrupt code is preloaded and fixed.
  15. ;
  16. ; History:
  17. ;
  18. ; **********************************************************************
  19. ; Tue Dec 19 1989 09:35:15 -by- Amit Chatterjee [amitc]
  20. ; ----------------------------------------------------------------------
  21. ; Added a far entry point 'FakeCOMIntFar' so that the routine 'FakeCOMInt'
  22. ; could be called from the 'InitAPort' routine in IBMCOM.ASM
  23. ;
  24. ; 26.Nov.90 richp
  25. ;
  26. ; Changed interrupt routines to use new VPICD services for bi-modal/multi-
  27. ; modal interrupt handling. They now work in straight real mode for real
  28. ; mode Windows, but can also handle interrupts in real mode or protected
  29. ; mode for standard mode Windows, and handle interrupts in RING 0 protected
  30. ; mode for enhanced mode Windows, even when the Windows VM is not currently
  31. ; executing.
  32. ;
  33. ; sudeepb 10-Jan-1993 changed the costly cli/sti with non-trapping
  34. ; FCLI/FSTI macros
  35. ;-----------------------------------------------------------------------;
  36. subttl Communications Hardware Interrupt Service Routines
  37. .xlist
  38. include cmacros.inc
  39. include comdev.inc
  40. include ibmcom.inc
  41. include ins8250.inc
  42. include BIMODINT.INC
  43. include vint.inc
  44. .list
  45. externFP GetSystemMsecCount
  46. externW COMptrs
  47. externW activeCOMs
  48. externD lpPostMessage
  49. sBegin Data
  50. PUBLIC IRQhooks
  51. IRQhooks label byte
  52. DefineIRQhook MACRO num
  53. IFDEF No_DOSX_Bimodal_Services
  54. IRQhook&num IRQ_Hook_Struc <,,,,IntCodeOFFSET DEF_COM_INT_&num,,,, \
  55. IntCodeOFFSET DEF_RM_COM_INT_&num>
  56. ELSE
  57. IRQhook&num IRQ_Hook_Struc <,,,,IntCodeOFFSET DEF_COM_INT_&num>
  58. ENDIF
  59. ENDM
  60. ??portnum = 1
  61. REPT MAXCOM+1
  62. DefineIRQhook %??portnum
  63. ??portnum = ??portnum+1
  64. ENDM
  65. PURGE DefineIRQhook
  66. EXTRN VCD_int_callback:fword
  67. sEnd data
  68. createSeg _INTERRUPT,IntCode,word,public,CODE
  69. sBegin IntCode
  70. assumes cs,IntCode
  71. page
  72. IFDEF No_DOSX_Bimodal_Services
  73. public RM_IntDataSeg
  74. RM_IntDataSeg dw 0
  75. ; this variable is written into by a routine in inicom
  76. ; if the 286 DOS extender is present. This variable
  77. ; contains the SEGMENT value of the data selector "_DATA"
  78. ; so that the real mode interrupt handler may use the
  79. ; data segment, and not it's selector !
  80. PUBLIC RM_CallBack
  81. RM_CallBack dd 0
  82. ENDIF
  83. Control proc far
  84. ret
  85. Control endp
  86. IFDEF No_DOSX_Bimodal_Services
  87. DEF_RM_Handler proc far
  88. push es
  89. push di
  90. push ax
  91. mov es, cs:[RM_IntDataSeg]
  92. mov di, es:[di.First_DEB] ; ES:DI -> ComDEB
  93. add di, SIZE ComDEB ; ES:DI -> BIS
  94. mov es:[di.BIS_Mode], 4
  95. push cs
  96. call NEAR PTR COMHandler
  97. mov es:[di.BIS_Mode], 0
  98. pop ax
  99. pop di ; ES:DI -> IRQ_Hook_Struc
  100. jc short DEF_RM_chain
  101. pop es
  102. pop di
  103. add sp, 4
  104. iret
  105. DEF_RM_chain:
  106. call DOCLI
  107. push bp
  108. mov bp, sp ;stack frame:
  109. ; bp+8 -> OldInt CS
  110. ; bp+6 -> OldInt IP
  111. ; bp+4 -> di
  112. ; bp+2 -> es
  113. ; bp+0 -> bp
  114. les di, es:[di.RM_OldIntVec]
  115. mov [bp+6], di
  116. mov [bp+8], es
  117. pop bp
  118. pop es
  119. pop di
  120. ret ; far ret to OldInt handler
  121. DEF_RM_Handler endp
  122. ENDIF ;No_DOSX_Bimodal_Services
  123. Define_DEF_COM_INT MACRO num
  124. IFDEF No_DOSX_Bimodal_Services
  125. PUBLIC DEF_RM_COM_INT_&num
  126. DEF_RM_COM_INT_&num proc far
  127. sub sp, 4
  128. push di
  129. mov di, DataOFFSET IRQhook&num
  130. jmp DEF_RM_Handler
  131. DEF_RM_COM_INT_&num endp
  132. ENDIF
  133. PUBLIC DEF_COM_INT_&num
  134. DEF_COM_INT_&num proc far
  135. sub sp, 4
  136. push di
  137. mov di, DataOFFSET IRQhook&num
  138. jmp DEF_Handler
  139. DEF_COM_INT_&num endp
  140. ENDM
  141. ??portnum = 2
  142. REPT MAXCOM
  143. Define_DEF_COM_INT %??portnum
  144. ??portnum = ??portnum+1
  145. ENDM
  146. PURGE Define_DEF_COM_INT
  147. IFDEF No_DOSX_Bimodal_Services
  148. PUBLIC DEF_RM_COM_INT_1
  149. DEF_RM_COM_INT_1 proc far
  150. sub sp, 4
  151. push di
  152. mov di, DataOFFSET IRQhook1
  153. jmp DEF_RM_Handler
  154. DEF_RM_COM_INT_1 endp
  155. ENDIF
  156. PUBLIC DEF_COM_INT_1
  157. DEF_COM_INT_1 proc far
  158. sub sp, 4
  159. push di
  160. mov di, DataOFFSET IRQhook1
  161. IF2
  162. .errnz $ - OFFSET DEF_Handler
  163. ENDIF
  164. DEF_COM_INT_1 endp
  165. DEF_Handler proc far
  166. push es
  167. push di
  168. push ax
  169. mov ax, _DATA
  170. mov es, ax
  171. mov di, es:[di.First_DEB] ; ES:DI -> ComDEB
  172. add di, SIZE ComDEB ; ES:DI -> BIS
  173. push cs
  174. call NEAR PTR COMHandler
  175. pop ax
  176. pop di ; ES:DI -> IRQ_Hook_Struc
  177. jc short DEF_chain
  178. pop es
  179. pop di
  180. add sp, 4
  181. iret
  182. DEF_chain:
  183. call DOCLI
  184. push bp
  185. mov bp, sp ;stack frame:
  186. ; bp+8 -> OldInt CS
  187. ; bp+6 -> OldInt IP
  188. ; bp+4 -> di
  189. ; bp+2 -> es
  190. ; bp+0 -> bp
  191. les di, es:[di.OldIntVec]
  192. mov [bp+6], di
  193. mov [bp+8], es
  194. pop bp
  195. pop es
  196. pop di
  197. ret ; far ret to OldInt handler
  198. DEF_Handler endp
  199. ;------------------------------------------------------------------------------
  200. ;
  201. ; ENTER: ES:DI -> BIS
  202. ;
  203. ; EXIT: Carry set, if IRQ not handled by any com ports
  204. ;
  205. COMHandler proc far
  206. push ds
  207. push si
  208. push ax
  209. push bx
  210. mov si, es
  211. mov ds, si
  212. mov bh, -1
  213. ch_chk_all:
  214. lea si, [di-SIZE ComDEB] ;ds:si -> ComDEB
  215. mov si, [si.IRQhook]
  216. mov si, [si.First_DEB]
  217. mov bl, -1
  218. ch_next_com:
  219. inc bl ; first time bl = 0
  220. xor ax, ax
  221. xchg ax, [di.BIS_Mode]
  222. lea di, [si+SIZE ComDEB]
  223. mov [di.BIS_Mode], ax
  224. call CommInt
  225. and al, 80h
  226. or bl, al
  227. mov si, [si.NextDEB]
  228. or si, si
  229. jnz ch_next_com
  230. test bl, 7Fh ;Q: more than 1 com port?
  231. jnz short ch_shared ; Y: check if handled
  232. or bl, bl ;Q: int handled by port?
  233. stc
  234. jns ch_exit ; N:
  235. ch_eoi:
  236. xor ax, ax
  237. .errnz BIH_API_EOI
  238. xor bx, bx
  239. xchg bx, es:[di.BIS_Mode]
  240. call es:[bx][di.BIS_User_Mode_API]
  241. lea si, [di-SIZE ComDEB] ; ds:si -> ComDEB
  242. mov si, [si.IRQhook]
  243. mov al, [si.OldMask]
  244. shr al, 1 ; shift bit 0 into Carry (0, if unmasked
  245. cmc ; -1, if originally masked)
  246. ch_exit:
  247. pop bx
  248. pop ax
  249. pop si
  250. pop ds
  251. ret
  252. ch_shared:
  253. inc bh ; count loop
  254. or bl, bl ;Q: int handled by any port?
  255. js ch_chk_all ; Y: check all ports again
  256. or bh, bh ;Q: first time thru loop?
  257. stc
  258. jz ch_exit ; Y: int wasn't for a COM port, so
  259. ; chain to next IRQ handler
  260. jmp ch_eoi
  261. COMHandler endp
  262. IFDEF No_DOSX_Bimodal_Services
  263. PUBLIC Entry_From_RM
  264. Entry_From_RM proc far
  265. ;
  266. ; Simulate the far ret
  267. ;
  268. cld
  269. lodsw
  270. mov es:[di.RealMode_IP], ax
  271. lodsw
  272. mov es:[di.RealMode_CS], ax
  273. add es:[di.RealMode_SP], 4
  274. push es
  275. push di
  276. .286
  277. ;
  278. ; Push far addr of Ret_To_IRET to cleanup stack and return to DPMI host
  279. ;
  280. push cs
  281. push IntCodeOFFSET Ret_To_IRET
  282. ;
  283. ; Push far addr of proc to call, so we can do a far ret to it
  284. ;
  285. push es:[di.RealMode_CX] ; segment of callback
  286. push es:[di.RealMode_DX] ; offset of callback
  287. mov di, es:[di.RealMode_DI]
  288. ret ; far ret to cx:dx
  289. ; called proc will do a far ret
  290. Ret_To_IRET: ; <- to here
  291. pop di
  292. pop es
  293. iret
  294. .8086
  295. Entry_From_RM endp
  296. PUBLIC RM_APIHandler
  297. RM_APIHandler proc far
  298. cmp ax, BIH_API_Call_Back
  299. jne APIHandler
  300. call cs:[RM_CallBack]
  301. ret
  302. RM_APIHandler endp
  303. ENDIF
  304. ;------------------------------------------------------------------------------
  305. ;
  306. ; ENTER: ES:DI -> BIS
  307. ;
  308. APIHandler proc far
  309. or ax, ax
  310. jnz short api_not_EOI
  311. .errnz BIH_API_EOI
  312. mov ax, es:[di.BIS_IRQ_Number]
  313. cmp al,8 ;Q: slave IRQ?
  314. mov al,EOI
  315. jb short api_master ; N:
  316. out 0A0h,al ; Y: EOI slave
  317. api_master:
  318. out INTA0,al ; EOI master
  319. ret
  320. api_not_EOI:
  321. cmp ax, BIH_API_Call_Back
  322. jae short api_callme
  323. push dx
  324. push cx
  325. mov dx, INTA1
  326. mov cx, es:[di.BIS_IRQ_Number]
  327. cmp cl, 8 ;Q: 2nd PIC?
  328. jb @f ; N:
  329. mov dx, 0A1h ; Y: dx = mask port
  330. sub cl, 8
  331. @@:
  332. cmp al, BIH_API_Get_Mask ;Q: get IRQ mask?
  333. jae api_get_mask ; Y:
  334. mov ah, al
  335. mov ch, 1
  336. shl ch, cl ; ch = mask byte
  337. pushf
  338. call DOCLI
  339. in al, dx ; get current PIC mask state
  340. cmp ah, BIH_API_Mask ;Q: mask IRQ?
  341. jne @f ; N:
  342. or al, ch ; Y: set IRQ's bit
  343. jmp short api_mask_exit
  344. @@:
  345. not ch ; N: clear IRQ's bit to unmask
  346. and al, ch
  347. api_mask_exit:
  348. out dx, al
  349. pop ax
  350. test ah, 2 ;Q: ints were enabled?
  351. jz @f ; N:
  352. call DOSTI
  353. @@:
  354. pop cx
  355. pop dx
  356. ret
  357. api_get_mask:
  358. in al, dx ; get current PIC mask state
  359. inc cl
  360. shr al, cl ; move IRQ's bit into carry
  361. ; Carry set, if IRQ masked
  362. pop cx
  363. pop dx
  364. ret
  365. api_callme:
  366. push cx
  367. push dx
  368. ret ; far ret to call back, which will
  369. ; do a far ret to our caller
  370. APIHandler endp
  371. ;--------------------------Fake a Hardware Interrupt----------------------;
  372. ; FakeCOMInt
  373. ;
  374. ; This routine fakes a hardware interrupt to IRQ3 or IRQ4
  375. ; to clear out characters pending in the buffer
  376. ;
  377. ; Entry:
  378. ; DS:SI --> DEB
  379. ; INTERRUPTS DISABLED!
  380. ; Returns:
  381. ; None
  382. ; Error Returns:
  383. ; None
  384. ; Registers Preserved:
  385. ;
  386. ; Registers Destroyed:
  387. ; AX,DX,FLAGS
  388. ; History: glenn steffler 5/17/89
  389. ;-----------------------------------------------------------------------;
  390. FakeCOMInt proc near
  391. ; call DOCLI ;Done by caller
  392. ;
  393. ; WARNING: jumping into the middle of CommInt, so the stack must be set
  394. ; properly.
  395. ;
  396. push dx
  397. push bx
  398. push cx
  399. push di
  400. push es
  401. push EvtWord[si]
  402. mov dx,Port[si] ;Get device I/O address
  403. add dl, ACE_IIDR
  404. push dx
  405. jmp FakeXmitEmpty ;Process the fake interrupt, DS:SI is
  406. ; already pointing to proper DEB
  407. ;
  408. ; FakeXmitEmpty falls in XmitEmpty which jumps back into CommInt. When CommInt
  409. ; determines that no interrupt is pending, then it will near return back to
  410. ; FakeCOMIntFar which can far ret back to its caller.
  411. ;
  412. FakeCOMInt endp
  413. public FakeCOMIntFar
  414. FakeCOMIntFar proc far
  415. call FakeCOMInt
  416. ret
  417. FakeCOMIntFar endp
  418. ;--------------------------Interrupt Handler----------------------------
  419. ;
  420. ; CommInt - Interrupt handler for com ports
  421. ;
  422. ; Interrupt handlers for PC com ports. This is the communications
  423. ; interrupt service routine for RS232 communications. When an RS232
  424. ; event occurs the interrupt vectors here. This routine determines
  425. ; who the caller was and services the appropriate interrupt. The
  426. ; interrupts are prioritized in the following order:
  427. ;
  428. ; 1. line status interrupt
  429. ; 2. read data available interrupt
  430. ; 3. transmit buffer empty interrupt
  431. ; 4. modem service interrupt
  432. ;
  433. ; This routine continues to service until all interrupts have been
  434. ; satisfied.
  435. ;
  436. ; Entry:
  437. ; DS:SI --> DEB
  438. ; INTERRUPTS DISABLED!
  439. ; Returns:
  440. ; AL = 0, if not handled, -1, if handled
  441. ;
  442. ;-----------------------------------------------------------------------
  443. assumes ds,Data
  444. assumes es,nothing
  445. ; Dispatch table for interrupt types
  446. SrvTab label word
  447. dw OFFSET ModemStatus ;[0] Modem Status Interrupt
  448. dw OFFSET XmitEmpty ;[2] Tx Holding Reg. Interrupt
  449. dw OFFSET DataAvail ;[4] Rx Data Available Interrupt
  450. ; or [C] if 16550 & 16550A
  451. dw OFFSET LineStat ;[6] Reciever Line Status Interrupt
  452. public CommInt
  453. CommInt proc near
  454. xor al, al
  455. cmp word ptr [VCD_int_callback+4], 0
  456. je short @F ; jump if no callback (not 3.1 VCD)
  457. test [si.VCDflags], fCOM_ignore_ints ;Q: we still own port?
  458. jnz IntLoop40 ; N: ignore the int
  459. .386
  460. push esi
  461. mov esi, [si.VCD_data]
  462. call [VCD_int_callback]
  463. pop esi
  464. .8086
  465. @@:
  466. push dx
  467. mov dx,Port[si] ;Get comm I/O port
  468. add dl,ACE_IIDR ;--> Interrupt ID Register
  469. in al, dx
  470. test al, 1 ;Q: interrupt pending?
  471. jnz short IntLoop30 ; N:
  472. push bx
  473. push cx
  474. push di
  475. push es
  476. mov cx, EvtWord[si]
  477. push cx
  478. jmp short IntLoop10
  479. InterruptLoop_ChkTx:
  480. cmp QOutCount[si],0 ;Output queue empty?
  481. je short InterruptLoop ; Y: don't chk tx
  482. pop dx
  483. push dx
  484. dec dx ; to IER
  485. .errnz ACE_IIDR - ACE_IER - 1
  486. in al, dx
  487. and al,NOT ACE_ETBEI ; disable it
  488. iodelay
  489. out dx, al
  490. or al, ACE_ETBEI ; enable it again
  491. iodelay
  492. out dx, al
  493. iodelay
  494. out dx, al
  495. InterruptLoop:
  496. pop dx ;Get ID reg I/O address
  497. in al,dx ;Get Interrupt Id
  498. test al,1 ;Interrupt need servicing?
  499. jnz IntLoop20 ;No, all done
  500. IntLoop10:
  501. and ax, 07h
  502. mov di,ax
  503. push dx ;Save Id register
  504. jmp SrvTab[di] ;Service the Interrupt
  505. IntLoop20:
  506. mov ax,EvtMask[si] ;Mask the event word to only the
  507. and ax, EvtWord[si] ; user specified bits
  508. mov EvtWord[si], ax
  509. pop bx
  510. test [si.NotifyFlagsHI], CN_Notify
  511. jz short ci_exit
  512. not bx
  513. and ax, bx ; bits set in ax are new events
  514. jnz short ci_new_events
  515. ci_exit:
  516. pop es
  517. assumes es,nothing
  518. pop di
  519. pop cx
  520. pop bx
  521. xor al, al
  522. IntLoop30:
  523. pop dx
  524. and al, 1
  525. dec al ; 0->-1, 1->0
  526. IntLoop40:
  527. ret
  528. ci_new_events:
  529. mov ax, CN_EVENT
  530. call notify_owner
  531. jmp ci_exit
  532. CommInt endp
  533. page
  534. ;----------------------------Private-Routine----------------------------;
  535. ;
  536. ; LineStat - Line Status Interrupt Handler
  537. ;
  538. ; Break detection is handled and set in the event word if
  539. ; enabled. Other errors (overrun, parity, framing) are
  540. ; saved for the data available interrupt.
  541. ;
  542. ; This routine used to fall into DataAvail for the bulk of its processing.
  543. ; This is no longer the case... A very popular internal modem seems to
  544. ; operate differently than a real 8250 when parity errors occur. Falling
  545. ; into the DataAvail handler on a parity error caused the same character
  546. ; to be received twice. Having this routine save the LSR status, and
  547. ; return to InterruptLoop fixes the problem, and still works on real COMM
  548. ; ports. The extra overhead isn't a big deal since this routine is only
  549. ; entered when there is an exception like a parity error.
  550. ;
  551. ; This routine is jumped to, and will perform a jump back into
  552. ; the dispatch loop.
  553. ;
  554. ; Entry:
  555. ; DS:SI --> DEB
  556. ; DX = Port.IIDR
  557. ; Returns:
  558. ; None
  559. ; Error Returns:
  560. ; None
  561. ; Registers Destroyed:
  562. ; AX,FLAGS
  563. ; History:
  564. ;-----------------------------------------------------------------------;
  565. ; assumes ds,Data
  566. assumes es,nothing
  567. public LineStat ;Public for debugging
  568. LineStat proc near
  569. or by EvtWord[si],EV_Err ;Show line status error
  570. add dl,ACE_LSR-ACE_IIDR ;--> Line Status Register
  571. in al,dx
  572. test al,ACE_PE+ACE_FE+ACE_OR ;Parity, Framing, Overrun error?
  573. jz @f
  574. mov LSRShadow[si],al ;yes, save status for DataAvail
  575. @@:
  576. test al,ACE_BI ;Break detect?
  577. jz InterruptLoop_ChkTx ;Not break detect interrupt
  578. or by EvtWord[si],EV_Break ;Show break
  579. jmp short InterruptLoop_ChkTx
  580. LineStat endp
  581. page
  582. ;----------------------------Private-Routine----------------------------;
  583. ;
  584. ; DataAvail - Data Available Interrupt Handler
  585. ;
  586. ; The available character is read and stored in the input queue.
  587. ; If the queue has reached the point that a handshake is needed,
  588. ; one is issued (if enabled). EOF detection, Line Status errors,
  589. ; and lots of other stuff is checked.
  590. ;
  591. ; This routine is jumped to, and will perform a jump back into
  592. ; the dispatch loop.
  593. ;
  594. ; Entry:
  595. ; DS:SI --> DEB
  596. ; DX = Port.IIDR
  597. ; Returns:
  598. ; None
  599. ; Error Returns:
  600. ; None
  601. ; Registers Destroyed:
  602. ; AX,BX,CX,DI,ES,FLAGS
  603. ; History:
  604. ;-----------------------------------------------------------------------;
  605. ; assumes ds,Data
  606. assumes es,nothing
  607. public DataAvail ;public for debugging
  608. DataAvail proc near
  609. sub dl,ACE_IIDR-ACE_RBR ;--> receiver buffer register
  610. in al,dx ;Read received character
  611. and [si.NotifyFlagsHI], NOT CN_Idle ; flag as not idle
  612. mov ah,LSRShadow[si] ;what did the last Line Status intrpt
  613. mov bh,ah ; have to say?
  614. or ah,ah
  615. jz @f
  616. and ah,ErrorMask[si] ;there was an error, record it
  617. or by ComErr[si],ah
  618. mov LSRShadow[si],0
  619. .errnz ACE_OR-CE_OVERRUN ;Must be the same bits
  620. .errnz ACE_PE-CE_RXPARITY
  621. .errnz ACE_FE-CE_FRAME
  622. .errnz ACE_BI-CE_BREAK
  623. @@:
  624. ; Regardless of the character received, flag the event in case
  625. ; the user wants to see it.
  626. or by EvtWord[si],EV_RxChar ;Show a character received
  627. .errnz HIGH EV_RxChar
  628. ; Check the input queue, and see if there is room for another
  629. ; character. If not, or if the end of file character has already
  630. ; been received, then go declare overflow.
  631. DataAvail00:
  632. mov cx,QInCount[si] ;Get queue count (used later too)
  633. cmp cx,QInSize[si] ;Is queue full?
  634. jge DataAvail20 ; Yes, comm overrun
  635. test EFlags[si],fEOF ;Has end of file been received?
  636. jnz DataAvail20 ; Yes - treat as overflow
  637. ; Test to see if there was a parity error, and replace
  638. ; the character with the parity character if so
  639. test bh,ACE_PE ;Parity error
  640. jz DataAvail25 ; No
  641. test [si.DCB_Flags2],fPErrChar ;Parity error replacement character?
  642. jz DataAvail25 ; No
  643. mov al,[si.DCB_PEChar] ; Yes, get parity replacement char
  644. ; Skip all other processing except event checking and the queing
  645. ; of the parity error replacement character
  646. jmp short DataAvail80 ;Skip all but event check, queing
  647. DataAvail20:
  648. or by ComErr[si],CE_RXOVER ;Show queue overrun
  649. jmp short DataAvail50
  650. ; See if we need to strip null characters, and skip
  651. ; queueing if this is one. Also remove any parity bits.
  652. DataAvail25:
  653. and al,RxMask[si] ;Remove any parity bits
  654. jnz DataAvail30 ;Not a Null character
  655. test [si.DCB_Flags2],fNullStrip ;Are we stripping received nulls?
  656. jnz DataAvail50 ; Yes, put char in the bit bucket
  657. ; Check to see if we need to check for EOF characters, and if so
  658. ; see if this character is it.
  659. DataAvail30:
  660. test [si.DCB_Flags],fBinary ;Is this binary stuff?
  661. jnz DataAvail60 ; Yes, skip EOF check
  662. cmp al,[si.DCB_EOFChar] ;Is this the EOF character?
  663. jnz DataAvail60 ; No, see about queing the charcter
  664. or EFlags[si],fEOF ;Set end of file flag
  665. DataAvail50:
  666. jmp DataAvail140 ;Skip the queing process
  667. ; If output XOn/XOff is enabled, see if the character just received
  668. ; is either an XOn or XOff character. If it is, then set or
  669. ; clear the XOffReceived flag as appropriate.
  670. DataAvail60:
  671. test [si.DCB_Flags2],fOutX ;Output handshaking?
  672. jz DataAvail80 ; No
  673. cmp al,[si.DCB_XoffChar] ;Is this an X-Off character?
  674. jnz DataAvail70 ; No, see about XOn or Ack
  675. or HSFlag[si],XOffReceived ;Show XOff received, ENQ or ETX [rkh]
  676. test [si.DCB_Flags],fEnqAck+fEtxAck ;Enq or Etx Ack?
  677. jz DataAvail50 ; No
  678. cmp cx,[si.DCB_XonLim] ;See if at XOn limit
  679. ja DataAvail50 ; No
  680. and HSFlag[si],NOT XOffReceived ;Show ENQ or ETX not received
  681. and HSFlag[si], NOT XOnPending+XOffSent
  682. mov al, [si.DCB_XonChar]
  683. call OutHandshakingChar
  684. jmp DataAvail50 ;Done
  685. DataAvail70:
  686. cmp al,[si.DCB_XonChar] ;Is this an XOn character?
  687. jnz DataAvail80 ; No, just a normal character
  688. and HSFlag[si],NOT XOffReceived
  689. test [si.DCB_Flags],fEnqAck+fEtxAck ;Enq or Etx Ack?
  690. jz DataAvail75 ; No - jump to FakeXmitEmpty to get
  691. ; transmitting going again
  692. and HSFlag[si],NOT EnqSent
  693. DataAvail75:
  694. jmp FakeXmitEmpty ;Restart transmit
  695. ; Now see if this is a character for which we need to set an event as
  696. ; having occured. If it is, then set the appropriate event flag
  697. DataAvail80:
  698. cmp al,[si.DCB_EVTChar] ;Is it the event generating character?
  699. jne DataAvail90 ; No
  700. or by EvtWord[si],EV_RxFlag ;Show received specific character
  701. ; Finally, a valid character that we want to keep, and we have
  702. ; room in the queue. Place the character in the queue.
  703. ; If the discard flag is set, then discard the character
  704. DataAvail90:
  705. test MiscFlags[si], Discard ;Discarding characters ?
  706. jnz DataAvail50 ; Yes
  707. lea bx, [si+SIZE ComDEB] ; DS:BX -> BIS
  708. mov bx, [bx.BIS_Mode] ; mode will be either 0 or 4
  709. les di,QInAddr[si][bx] ;Get queue base pointer from either
  710. assumes es,nothing ; QInAddr or AltQInAddr
  711. mov bx,QInPut[si] ;Get index into queue
  712. mov es:[bx][di],al ;Store the character
  713. inc bx ;Update queue index
  714. cmp bx,QInSize[si] ;See if time for wrap-around
  715. jc DataAvail100 ;Not time to wrap
  716. xor bx,bx ;Wrap-around is a new zero pointer
  717. DataAvail100:
  718. mov QInPut[si],bx ;Store updated pointer
  719. inc cx ;And update queue population
  720. mov QInCount[si],cx
  721. ; If flow control has been enabled, see if we are within the
  722. ; limit that requires us to halt the host's transmissions
  723. cmp cx,XOffPoint[si] ;Time to see about XOff?
  724. jc DataAvail120 ; Not yet
  725. test HSFlag[si],HSSent ;Handshake already sent?
  726. jnz DataAvail120 ; Yes, don't send it again
  727. mov ah,HHSLines[si] ;Should hardware lines be dropped?
  728. or ah,ah ; (i.e. do we have HW HS enabled?)
  729. jz DataAvail110 ; No
  730. add dl,ACE_MCR ; Yes
  731. in al,dx ;Clear the necessary bits
  732. not ah
  733. and al,ah
  734. or HSFlag[si],HHSDropped ;Show lines have been dropped
  735. out dx,al ; and drop the lines
  736. sub dl,ACE_MCR
  737. DataAvail110:
  738. test [si.DCB_Flags2],fInX ;Input Xon/XOff handshaking
  739. jz DataAvail120 ; No
  740. or HSFlag[si], XOffSent
  741. mov al, [si.DCB_XoffChar]
  742. call OutHandshakingChar
  743. DataAvail120:
  744. cmp cx, [si.RecvTrigger] ;Q: time to call owner's callback?
  745. jb short DataAvail130 ; N:
  746. test [si.NotifyFlagsHI], CN_RECEIVE
  747. jnz short DataAvail140 ; jump if notify already sent and
  748. ; data in buffer hasn't dropped
  749. ; below threshold
  750. mov ax, IntCodeOFFSET DataAvail140
  751. push ax
  752. mov ax, CN_RECEIVE
  753. %OUT probably should just set a flag and notify after EOI
  754. jmp notify_owner
  755. DataAvail130:
  756. and [si.NotifyFlagsHI], NOT CN_RECEIVE
  757. DataAvail140:
  758. pop dx
  759. push dx
  760. add dl, ACE_LSR-ACE_IIDR
  761. in al, dx
  762. test al, ACE_DR ;Q: more data available?
  763. jz @F ; N:
  764. sub dl, ACE_LSR ; Y: go read it
  765. in al, dx ;Read available character
  766. jmp DataAvail00
  767. @@:
  768. jmp InterruptLoop_ChkTx
  769. DataAvail endp
  770. OutHandshakingChar proc near
  771. add dl, ACE_LSR
  772. mov ah, al
  773. @@:
  774. in al, dx
  775. test al, ACE_THRE
  776. jz @B
  777. sub dl, ACE_LSR
  778. mov al, ah
  779. out dx, al
  780. ret
  781. OutHandshakingChar endp
  782. page
  783. ;----------------------------Private-Routine----------------------------;
  784. ;
  785. ; XmitEmpty - Transmitter Register Empty
  786. ;
  787. ; Entry:
  788. ; DS:SI --> DEB
  789. ; DX = Port.IIDR
  790. ; Returns:
  791. ; None
  792. ; Error Returns:
  793. ; None
  794. ; Registers Destroyed:
  795. ; AX,BX,CX,DI,ES,FLAGS
  796. ; History:
  797. ;-----------------------------------------------------------------------;
  798. ; assumes ds,Data
  799. assumes es,nothing
  800. public FakeXmitEmpty
  801. FakeXmitEmpty:
  802. pop dx
  803. push dx
  804. ; "Kick" the transmitter interrupt routine into operation.
  805. dec dl
  806. .errnz ACE_IIDR - ACE_IER-1
  807. in al,dx ;Get current IER state
  808. test al,ACE_ETBEI ;Interrupt already enabled?
  809. jnz @F ; Yes, don't reenable it
  810. or al,ACE_ETBEI ; No, enable it
  811. out dx,al
  812. iodelay ;8250, 8250-B bug requires
  813. out dx,al ; writting register twice
  814. @@:
  815. add dl,ACE_LSR-ACE_IER ;--> Line Status Register
  816. iodelay
  817. in al,dx ;Is xmit really empty?
  818. sub dl,ACE_LSR-ACE_THR ;--> Transmitter Holding Register
  819. test al,ACE_THRE
  820. jnz short XmitEmpty5 ; Y: send next char
  821. jmp InterruptLoop ; N: return to processing loop
  822. public XmitEmpty
  823. XmitEmpty proc near
  824. add dl,ACE_LSR-ACE_IIDR ;--> Line Status Register
  825. in al,dx ;Is xmit really empty?
  826. sub dl,ACE_LSR-ACE_THR ;--> Transmitter Holding Register
  827. test al,ACE_THRE
  828. jz Xmit_jumpto90 ;Transmitter not empty, cannot send
  829. ; If the hardware handshake lines are down, then XOff/XOn cannot
  830. ; be sent. If they are up and XOff/XOn has been received, still
  831. ; allow us to transmit an XOff/XOn character. It will make
  832. ; a dead lock situation less possible (even though there are
  833. ; some which could happen that cannot be handled).
  834. XmitEmpty5:
  835. mov ah,HSFlag[si] ;Get handshaking flag
  836. test ah,HHSDown+BreakSet ;Hardware lines down or break set?
  837. jnz Xmit_jumpto100 ; Yes, cannot transmit
  838. ; Give priority to any handshake character waiting to be
  839. ; sent. If there are none, then check to see if there is
  840. ; an "immediate" character to be sent. If not, try the queue.
  841. XmitEmpty10:
  842. test [si.DCB_Flags],fEnqAck+fEtxAck ;Enq or Etx Ack?
  843. jnz XmitEmpty40 ; Yes
  844. XmitEmpty15:
  845. test ah,HSPending ;XOff or XOn pending
  846. jz XmitEmpty40 ; No
  847. XmitEmpty20:
  848. and ah,NOT XOnPending+XOffSent
  849. mov al,[si.DCB_XonChar] ;Get XOn character
  850. XmitEmpty30:
  851. mov HSFlag[si],ah ;Save updated handshake flag
  852. jmp XmitEmpty110 ;Go output the character
  853. Xmit_jumpto90:
  854. jmp XmitEmpty90
  855. ; If any of the lines which were specified for a timeout are low, then
  856. ; don't send any characters. Note that by putting the check here,
  857. ; XOff and Xon can still be sent even though the lines might be low.
  858. ; Also test to see if a software handshake was received. If so,
  859. ; then transmission cannot continue. By delaying the software check
  860. ; to here, XOn/XOff can still be issued even though the host told
  861. ; us to stop transmission.
  862. XmitEmpty40:
  863. test ah,CannotXmit ;Anything preventing transmission?
  864. jz XmitEmpty45 ; No
  865. Xmit_jumpto100:
  866. jmp XmitEmpty100 ; Yes, disarm and exit
  867. ; If a character has been placed in the single character "transmit
  868. ; immediately" buffer, clear that flag and pick up that character
  869. ; without affecting the transmitt queue.
  870. XmitEmpty45:
  871. test EFlags[si],fTxImmed ;Character to xmit immediately?
  872. jz XmitEmpty515 ; No, try the queue
  873. and EFlags[si],NOT fTxImmed ;Clear xmit immediate flag
  874. mov al,ImmedChar[si] ;Get char to xmit
  875. jmp XmitEmpty110 ;Transmit the character
  876. XmitEmpty515:
  877. mov cx,QOutCount[si] ;Output queue empty?
  878. jcxz Xmit_jumpto90 ; Yes, go set an event
  879. test [si.DCB_Flags],fEtxAck ;Etx Ack?
  880. jz XmitEmpty55 ; No
  881. mov cx,QOutMod[si] ;Get number bytes sent since last ETX
  882. cmp cx,[si.DCB_XonLim] ;At Etx limit yet?
  883. jne XmitEmpty51 ; No, inc counter
  884. mov QOutMod[si],0 ; Yes, zero counter
  885. or HSFlag[si],EtxSent ;Show ETX sent
  886. jmp short XE_sendXOFF
  887. XmitEmpty51:
  888. inc cx ; Update counter
  889. mov QOutMod[si],cx ; Save counter
  890. jmp short XmitEmpty59 ; Send queue character
  891. XmitEmpty55:
  892. test [si.DCB_Flags],fEnqAck ;Enq Ack?
  893. jz XmitEmpty59 ; No, send queue character
  894. mov cx,QOutMod[si] ;Get number bytes sent since last ENQ
  895. or cx,cx ;At the front again?
  896. jnz XmitEmpty56 ; No, inc counter
  897. mov QOutMod[si],1 ; Yes, send ENQ
  898. or HSFlag[si],EnqSent ;Show ENQ sent
  899. XE_sendXOFF:
  900. mov al,[si.DCB_XoffChar]
  901. jmp short XmitEmpty110 ;Go output the character
  902. XmitEmpty56:
  903. inc cx ;Update counter
  904. cmp cx,[si.DCB_XonLim] ;At end of our out buffer len?
  905. jne XmitEmpty58 ; No
  906. xor cx,cx ;Show at front again.
  907. XmitEmpty58:
  908. mov QOutMod[si],cx ;Save counter
  909. XmitEmpty59:
  910. lea bx, [si+SIZE ComDEB] ; DS:BX -> BIS
  911. mov bx, [bx.BIS_Mode] ; mode will be either 0 or 4
  912. les di,QOutAddr[si][bx] ;Get queue base pointer from either
  913. assumes es,nothing ; QOutAddr or AltQOutAddr
  914. mov bx,QOutGet[si] ;Get pointer into queue
  915. mov al,es:[bx][di] ;Get the character
  916. inc bx ;Update queue pointer
  917. cmp bx,QOutSize[si] ;See if time for wrap-around
  918. jc XmitEmpty60 ;Not time for wrap
  919. xor bx,bx ;Wrap by zeroing the index
  920. XmitEmpty60:
  921. mov QOutGet[si],bx ;Save queue index
  922. mov cx,QOutCount[si] ;Output queue empty?
  923. dec cx ;Dec # of bytes in queue
  924. mov QOutCount[si],cx ; and save new population
  925. out dx,al ;Send char
  926. cmp cx, [si.SendTrigger] ;Q: time to call owner's callback?
  927. jae short XmitEmpty70 ; N:
  928. test [si.NotifyFlagsHI], CN_TRANSMIT
  929. jnz short XmitEmpty80 ; jump if notify already sent and
  930. ; data in buffer hasn't raised
  931. ; above threshold
  932. mov ax, IntCodeOFFSET XmitEmpty80
  933. push ax
  934. mov ax, CN_TRANSMIT
  935. jmp short notify_owner
  936. XmitEmpty70:
  937. and [si.NotifyFlagsHI], NOT CN_TRANSMIT
  938. XmitEmpty80:
  939. %OUT check fNoFIFO in EFlags[si] to determine if we can queue more output
  940. jmp InterruptLoop
  941. ; No more characters to transmit. Flag this as an event.
  942. XmitEmpty90:
  943. or by EvtWord[si],EV_TxEmpty
  944. ; Cannot continue transmitting (for any of a number of reasons).
  945. ; Disable the transmit interrupt. When it's time resume, the
  946. ; transmit interrupt will be reenabled, which will generate an
  947. ; interrupt.
  948. XmitEmpty100:
  949. inc dx ;--> Interrupt Enable Register
  950. .errnz ACE_IER-ACE_THR-1
  951. in al,dx ;I don't know why it has to be read
  952. and al,NOT ACE_ETBEI ; first, but it works this way
  953. XmitEmpty110:
  954. out dx,al
  955. jmp InterruptLoop
  956. XmitEmpty endp
  957. page
  958. ;----------------------------Private-Routine----------------------------;
  959. ;
  960. ; ModemStatus - Modem Status Interrupt Handler
  961. ;
  962. ; Entry:
  963. ; DS:SI --> DEB
  964. ; DX = Port.IIDR
  965. ; Returns:
  966. ; None
  967. ; Error Returns:
  968. ; None
  969. ; Registers Destroyed:
  970. ; AX,BX,CX,DI,ES,FLAGS
  971. ; History:
  972. ;-----------------------------------------------------------------------;
  973. ; assumes ds,Data
  974. assumes es,nothing
  975. public ModemStatus ;Public for debugging
  976. ModemStatus proc near
  977. ; Get the modem status value and shadow it for MSRWait.
  978. add dl,ACE_MSR-ACE_IIDR ;--> Modem Status Register
  979. in al,dx
  980. mov MSRShadow[si],al ;Save MSR data for others
  981. mov ch,al ;Save a local copy
  982. ; Create the event mask for the delta signals
  983. mov ah,al ;Just a lot of shifting
  984. shr ax,1
  985. shr ax,1
  986. shr ah,1
  987. mov cl,3
  988. shr ax,cl
  989. and ax,EV_CTS+EV_DSR+EV_RLSD+EV_Ring
  990. or EvtWord[si],ax
  991. mov ah,ch ;[rkh]...
  992. shr ah,1
  993. shr ah,1
  994. and ax,EV_CTSS+EV_DSRS
  995. or EvtWord[si],ax
  996. mov ah,ch
  997. mov cl,3
  998. shr ah,cl
  999. and ax,EV_RLSD
  1000. or EvtWord[si],ax
  1001. mov ah,ch
  1002. mov cl,3
  1003. shl ah,cl
  1004. and ax,EV_RingTe
  1005. or EvtWord[si],ax
  1006. .errnz EV_CTS-0000000000001000b
  1007. .errnz EV_DSR-0000000000010000b
  1008. .errnz EV_RLSD-0000000000100000b
  1009. .errnz EV_Ring-0000000100000000b
  1010. .errnz EV_CTSS-0000010000000000b ;[rkh]
  1011. .errnz EV_DSRS-0000100000000000b
  1012. .errnz EV_RLSDS-0001000000000000b
  1013. .errnz EV_RingTe-0010000000000000b
  1014. .errnz ACE_DCTS-00000001b
  1015. .errnz ACE_DDSR-00000010b
  1016. .errnz ACE_DRLSD-00001000b
  1017. .errnz ACE_RI-01000000b
  1018. .errnz ACE_TERI-00000100b ;[rkh]
  1019. .errnz ACE_CTS-00010000b
  1020. .errnz ACE_DSR-00100000b
  1021. .errnz ACE_RLSD-10000000b
  1022. ModemStatus10:
  1023. mov al,OutHHSLines[si] ;Get output hardware handshake lines
  1024. or al,al ;Any lines that must be set?
  1025. jz ModemStatus40 ;No hardware handshake on output
  1026. and ch,al ;Mask bits of interest
  1027. cmp ch,al ;Lines set for Xmit?
  1028. je ModemStatus20 ; Yes
  1029. or HSFlag[si],HHSDown ;Show hardware lines have dropped
  1030. ModemStatus30:
  1031. jmp InterruptLoop
  1032. ModemStatus40:
  1033. jmp InterruptLoop_ChkTx
  1034. ; Lines are set for xmit. Kick an xmit interrupt if needed
  1035. ModemStatus20:
  1036. and HSFlag[si],NOT (HHSDown OR HHSAlwaysDown)
  1037. ;Show hardware lines back up
  1038. mov cx,QOutCount[si] ;Output queue empty?
  1039. jcxz ModemStatus30 ; Yes, return to InterruptLoop
  1040. jmp FakeXmitEmpty ;Restart transmit
  1041. ModemStatus endp
  1042. page
  1043. ;------------------------------------------------------------------------------
  1044. ;
  1045. ; ENTER: AX = message #
  1046. ; DS:SI -> DEB
  1047. notify_owner proc near
  1048. or [si.NotifyFlags], ax
  1049. lea di, [si+SIZE ComDEB]
  1050. mov ax, ds
  1051. mov es, ax
  1052. mov ax, BIH_API_Call_Back ; call immediate, or in protected mode
  1053. mov bx, 1 ; force SYS VM, if enhanced mode
  1054. mov cx, _INTERRUPT
  1055. mov dx, IntCodeOFFSET callback_event
  1056. %OUT use equate
  1057. push ds
  1058. push si
  1059. mov si, 1 ; low priority boost
  1060. push bp
  1061. mov bp, es:[di.BIS_Mode]
  1062. call es:[bp][di.BIS_User_Mode_API]
  1063. pop bp
  1064. pop si
  1065. pop ds
  1066. ret
  1067. notify_owner endp
  1068. ;------------------------------------------------------------------------------
  1069. ;
  1070. ; ENTER: ES:DI -> BIS
  1071. ;
  1072. callback_event proc far
  1073. lea si, [di-SIZE ComDEB]
  1074. mov ax, es
  1075. mov ds, ax
  1076. mov ax, [si.NotifyHandle]
  1077. push ax ; push hWnd
  1078. mov ax, WM_COMMNOTIFY
  1079. push ax ; push wMsg
  1080. xor ax, ax
  1081. mov al, [si.DCB_Id]
  1082. push ax ; push wParam = ComID
  1083. xor al, al
  1084. push ax ; push high word of lParam
  1085. xchg al, [si.NotifyFlagsLO]
  1086. or [si.NotifyFlagsHI], al
  1087. push ax ; push low word of lParam = event flags
  1088. call [lpPostMessage]
  1089. ret
  1090. callback_event endp
  1091. PUBLIC TimerProc
  1092. TimerProc proc far
  1093. push ds
  1094. mov ax, _DATA
  1095. mov ds, ax
  1096. assumes ds,data
  1097. mov ax, [activeCOMs]
  1098. or ax, ax
  1099. jz short tp_nonactive
  1100. push si
  1101. mov si, DataOFFSET COMptrs
  1102. mov cx, MAXCOM+1
  1103. tp_lp:
  1104. push si
  1105. mov si, [si] ; si -> ComDEB
  1106. shr ax, 1
  1107. jnc tp_lpend
  1108. cmp [si.RecvTrigger], -1 ;Q: owner wants notification?
  1109. je short tp_lpend ; N: skip notify
  1110. cmp [si.QInCount], 0 ;Q: anything in input queue?
  1111. je short tp_lpend ; N: skip notify
  1112. test [si.NotifyFlagsHI], CN_RECEIVE ;Q: timeout notify already given?
  1113. jnz short tp_lpend ; N: skip notify
  1114. xor [si.NotifyFlagsHI], CN_Idle ;Q: first timer call?
  1115. js short tp_lpend ; Y: skip notify
  1116. push ax
  1117. push cx
  1118. mov ax, CN_RECEIVE ; N: notify owner
  1119. call notify_owner
  1120. pop cx
  1121. pop ax
  1122. tp_lpend:
  1123. pop si
  1124. inc si ; inc to ptr to next ComDEB
  1125. inc si
  1126. or ax, ax
  1127. loopnz tp_lp
  1128. pop si
  1129. tp_nonactive:
  1130. pop ds
  1131. assumes ds,nothing
  1132. ret
  1133. TimerProc endp
  1134. page
  1135. ifdef DEBUG
  1136. public Control, DEF_Handler, COMHandler, APIHandler
  1137. public InterruptLoop, IntLoop10, IntLoop20
  1138. public DataAvail25, DataAvail30, DataAvail50
  1139. public DataAvail60, DataAvail70, DataAvail80, DataAvail90
  1140. public DataAvail100, DataAvail110, DataAvail120
  1141. public DataAvail130, DataAvail140, OutHandshakingChar
  1142. public XmitEmpty10, XmitEmpty20, XmitEmpty30, XmitEmpty40
  1143. public XmitEmpty59, XmitEmpty60
  1144. public XmitEmpty90, XmitEmpty100, XmitEmpty110
  1145. public ModemStatus10, ModemStatus20, ModemStatus30
  1146. public notify_owner, callback_event
  1147. endif
  1148. DOSTI proc near
  1149. FSTI
  1150. ret
  1151. DOSTI endp
  1152. DOCLI proc near
  1153. FCLI
  1154. ret
  1155. DOCLI endp
  1156. sEnd IntCode
  1157. end