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.

2878 lines
72 KiB

  1. page,132
  2. ;---------------------------Module-Header-------------------------------;
  3. ; Module Name: IBMSETUP.ASM
  4. ;
  5. ; Copyright (c) Microsoft Corporation 1985-1990. All Rights Reserved.
  6. ;
  7. ; General Description:
  8. ;
  9. ; History:
  10. ; sudeepb 10-Jan-1993 changed the costly cli/sti with non-trapping
  11. ; FCLI/FSTI macros
  12. ;
  13. ;-----------------------------------------------------------------------;
  14. title IBMSetup - IBM PC, PC-XT, PC-AT, PS/2 Communications Interface
  15. .xlist
  16. include cmacros.inc
  17. include comdev.inc
  18. include ins8250.inc
  19. include ibmcom.inc
  20. include BIMODINT.INC
  21. include vint.inc
  22. .list
  23. EBIS_Sel1 equ SIZE Bimodal_Int_Struc
  24. EBIS_Sel2 equ EBIS_Sel1 + (SIZE EBIS_Sel_Struc)
  25. externA __WinFlags
  26. externFP GetSystemMsecCount
  27. externFP CreateSystemTimer
  28. externFP AllocCStoDSAlias
  29. externFP LockSegment
  30. externFP UnlockSegment
  31. externFP FreeSelector
  32. externFP GetSelectorBase
  33. externFP GetModuleHandle
  34. externFP GetProcAddress
  35. externFP GetPrivateProfileInt
  36. externFP GetPrivateProfileString
  37. externFP GetAppCompatFlags
  38. externFP WowCloseComPort
  39. externNP $RECCOM
  40. externA __0040H
  41. externA __F000h
  42. externB IRQhooks
  43. IF 0
  44. externD OldIntVecIntB
  45. externD OldIntVecIntC
  46. externD OurIntVecIntB
  47. externD OurIntVecIntC
  48. ENDIF
  49. externB szMessage
  50. externB pLPTByte
  51. externB szCOMMessage
  52. externB pCOMByte
  53. externB _szTitle
  54. MULTIPLEX equ 2Fh ; multiplex interrupt number
  55. GET386API equ 1684h ; Get API entry point from VxD
  56. VPD equ 000Fh ; device ID of VPD device
  57. VPD_GETPORT equ 0004h ; function: assign port to current VM
  58. VPD_RELPORT equ 0005h ; function: release port
  59. VCD equ 000Eh ; device ID of VCD device
  60. VCD_GETVER equ 0000h ; get version API
  61. VCD_GETPORT equ 0004h ; function: assign port to current VM
  62. VCD_RELPORT equ 0005h ; function: release port
  63. VCD_STEALPORT equ 0006h
  64. VPICD equ 0003h ; device ID of VPICD device
  65. POSTMESSAGE equ 110 ; export ordinal of PostMessage()
  66. MESSAGEBOX equ 1 ; export ordinal of MessageBox()
  67. MB_TASKMODAL equ 2000h
  68. MB_YESNO equ 0004h ; messagebox flags
  69. MB_ICONEXCLAMATION equ 0030h
  70. IDYES equ 6
  71. createSeg _INTERRUPT,IntCode,word,public,CODE
  72. sBegin IntCode
  73. assumes cs,IntCode
  74. externFP FakeCOMIntFar
  75. externFP TimerProc
  76. externFP Control
  77. externFP COMHandler
  78. externFP APIHandler
  79. IFDEF No_DOSX_Bimodal_Services
  80. externW RM_IntDataSeg
  81. externFP RM_APIHandler
  82. externFP Entry_From_RM
  83. externD RM_CallBack
  84. ENDIF
  85. sEnd IntCode
  86. page
  87. sBegin Data
  88. externB lpCommBase
  89. externB CommBaseX
  90. externB lpCommIrq
  91. externB CommIrqX
  92. externB lpCommFifo
  93. externB CommFifoX
  94. externB lpCommDSR
  95. externB CommDSRx
  96. externB lpCommSection
  97. externB lpSYSTEMINI
  98. ;------------------------------------------------------------------------------
  99. ;
  100. ; Reserve data space for COM ports
  101. ;
  102. DefineCommX MACRO num
  103. public Comm&num
  104. Comm&num label byte
  105. db num-1
  106. .errnz DCB_Id
  107. db ((DCBSize+1) AND 0FFFEh)-1 DUP (0) ; ComDCB
  108. dw 0 ; ComErr
  109. dw 0 ; Port
  110. dw 0 ; NotifyHandle
  111. dw 0 ; NotifyFlags
  112. dw -1 ; RecvTrigger
  113. dw 0 ; SendTrigger
  114. .errnz IRQhook - SendTrigger - 2
  115. db (SIZE ComDEB) - IRQhook DUP(0)
  116. .errnz $ - Comm&num - (SIZE ComDEB)
  117. Declare_PM_BIS 0,Control,COMHandler,APIHandler,_INTERRUPT,_DATA
  118. db (SIZE EBIS_Sel_Struc) * 2 DUP(0) ; res space for 2 selectors
  119. ENDM
  120. DW_OFFSET_CommX MACRO num
  121. dw DataOFFSET Comm&num
  122. ENDM
  123. ??portnum = 1
  124. REPT MAXCOM+1
  125. DefineCommX %??portnum
  126. ??portnum = ??portnum+1
  127. ENDM
  128. PUBLIC COMptrs ; table of offsets to CommX's declared above
  129. COMptrs label word
  130. ??portnum = 1
  131. REPT MAXCOM+1
  132. DW_OFFSET_CommX %??portnum
  133. ??portnum = ??portnum+1
  134. ENDM
  135. PURGE DefineCommX
  136. PURGE DW_OFFSET_CommX
  137. ;------------------------------------------------------------------------------
  138. ;
  139. ; Reserve data space for LPT ports
  140. ;
  141. DefineLPTx MACRO num
  142. public LPT&num
  143. LPT&num label byte
  144. db num-1+LPTx
  145. .errnz DCB_Id
  146. db ((DCBSize+1) AND 0FFFEh)-1 DUP (0) ; xComDCB
  147. dw 0 ; xComErr
  148. dw 0 ; xPort
  149. dw 0 ; xNotifyHandle
  150. dw 0 ; xNotifyFlags
  151. dw -1 ; xRecvTrigger
  152. dw 0 ; xSendTrigger
  153. IF num LE 3
  154. dw LPTB + (num-1)*2
  155. ELSE
  156. dw 0 ; BIOSPortLoc
  157. ENDIF
  158. .errnz $-LPT&num - SIZE LptDEB
  159. ENDM
  160. ??portnum = 1
  161. REPT MAXLPT+1
  162. DefineLPTx %??portnum
  163. ??portnum = ??portnum+1
  164. ENDM
  165. PURGE DefineLPTx
  166. page
  167. PUBLIC $MachineID, Using_DPMI
  168. $MachineID db 0 ;IBM Machine ID
  169. Using_DPMI db 0 ; 0FFh, if TRUE
  170. ALIGN 2
  171. PUBLIC activeCOMs
  172. activeCOMs dw 0
  173. PUBLIC lpPostMessage, lpfnMessageBox, lpfnVPD, fVPD
  174. lpPostMessage dd 0
  175. lpfnMessageBox dd 0
  176. lpfnVPD dd 0 ; far pointer to win 386 VPD entry point
  177. lpfnVCD dd 0 ; far pointer to win 386 VCD entry point
  178. lpfnVPICD dd 0 ; far pointer to win 386 VPICD entry point
  179. PUBLIC VCD_int_callback
  180. VCD_int_callback df 0 ; VCD returns the address for this callback
  181. ; on every call to acquire a COM port, but
  182. ; it is always the same address, so we will
  183. ; just maintain it globally.
  184. fVPD db 0 ; 0-not checked, 1 vpd present, -1 no vpd
  185. fVCD db 0 ; 0-not checked, 1 vcd present, -1 no vcd
  186. fVPICD db 0 ; 0-not checked, 1 vpicd present, -1 no vpicd
  187. szUser db 'USER',0
  188. default_table db 4, 3, 4, 3, 0 ; Default IRQ's (COM3 default is changed to
  189. ; 3 for PS/2's during LoadLib)
  190. IFDEF No_DOSX_Bimodal_Services
  191. RM_Call_Struc Real_Mode_Call_Struc <>
  192. ENDIF
  193. IFDEF DEBUG_TimeOut
  194. %OUT including code to display MsgBox, if closing comm with data in buffer
  195. szSendTO db 'TimedOut CloseComm with data in buffer. Retry?', 0
  196. ENDIF
  197. sEnd Data
  198. ROMBios segment at 0F000h
  199. org 0FFFEh
  200. MachineID label byte
  201. RomBios Ends
  202. sBegin Code
  203. assumes cs,Code
  204. assumes ds,Data
  205. page
  206. IFDEF No_DOSX_Bimodal_Services
  207. ;----------------------------Private-Routine----------------------------;
  208. ; SegmentFromSelector
  209. ;
  210. ; Converts a selector to a segment...note that this routine assumes
  211. ; the memory pointed to by the selector is below the 1Meg line!
  212. ;
  213. ; Params:
  214. ; AX = selector to convert to segment
  215. ;
  216. ; Returns:
  217. ; AX = segment of selector given
  218. ;
  219. ; Error Returns:
  220. ; None
  221. ;
  222. ; Registers Destroyed:
  223. ; CX
  224. ;
  225. ;-----------------------------------------------------------------------;
  226. assumes ds,Data
  227. assumes es,nothing
  228. public SegmentFromSelector
  229. SegmentFromSelector proc far
  230. .286
  231. push dx
  232. cCall GetSelectorBase,<ax> ;DX:AX = segment of selector
  233. shr ax, 4
  234. shl dl, 4
  235. or ah, dl ;AX now points to interrupt *segment*
  236. pop dx
  237. ret
  238. .8086
  239. SegmentFromSelector endp
  240. ENDIF
  241. page
  242. ;------------------------------------------------------------------------------
  243. ;
  244. ; Get_API_Entry
  245. ;
  246. ; entry - BX = device id
  247. ; DS:DI -> DWORD for proc address
  248. ; exit - Z flag set, if failed
  249. ;
  250. Get_API_Entry proc near
  251. push di
  252. xor di, di
  253. mov es, di
  254. mov ax, GET386API
  255. int MULTIPLEX
  256. mov ax, di
  257. pop di
  258. mov [di], ax
  259. mov [di+2], es
  260. or ax, [di+2]
  261. ret
  262. Get_API_Entry endp
  263. ;----------------------------Private-Routine----------------------------;
  264. ;
  265. ; Contention_Dlg
  266. ;
  267. ; If running under Win386, this routine can be called to ask the user to
  268. ; resolve contention for a COM or LPT port.
  269. ;
  270. ; entry - CX is offset of message string for dialog box
  271. ;
  272. ; exit - Z flag set, if user specified that Windows should steal the port
  273. Contention_Dlg proc near
  274. PUBLIC Contention_Dlg
  275. xor ax,ax
  276. push ax ; hwndOwner
  277. push ds
  278. push cx ; message ptr
  279. cmp wo lpfnMessageBox[2], 0 ;Q: ptr to MessageBox proc valid?
  280. jne short gmbp_done ; Y: we can call it
  281. push ds ; N: get module handle of USER
  282. lea ax, szUser
  283. push ax
  284. cCall GetModuleHandle
  285. push ax ; module handle
  286. mov ax, MESSAGEBOX
  287. cwd
  288. push dx
  289. push ax
  290. cCall GetProcAddress
  291. mov wo lpfnMessageBox[0], ax ; save received proc address
  292. mov wo lpfnMessageBox[2], dx
  293. gmbp_done:
  294. push ds
  295. lea ax, _szTitle
  296. push ax
  297. mov ax, MB_ICONEXCLAMATION or MB_YESNO or MB_TASKMODAL
  298. push ax
  299. cCall lpfnMessageBox
  300. cmp ax, IDYES ; user allows us to take the port?
  301. ret
  302. Contention_Dlg endp
  303. ;----------------------------Private-Routine----------------------------;
  304. ;
  305. ; GetPort386
  306. ;
  307. ; If running under Win386, tell the VPD to assign an LPT port to us.
  308. ; The comm driver will handle contention.
  309. ;
  310. ; entry - DI contains offset in ROM area of port...
  311. ; 8 - LPT1, A - LPT2, etc
  312. ;
  313. ; exit - registers saved, carry = clear if OK to proceed, set if
  314. ; user won't allow assignment of port or Win386 error
  315. ;
  316. GetPort386 proc near
  317. public GetPort386
  318. cmp fVPD, 0
  319. jl getport_VPDNotInstalled
  320. jnz short getport_CallVPD
  321. push di
  322. mov bx, VPD
  323. mov di, DataOFFSET lpfnVPD
  324. call Get_API_Entry
  325. pop di
  326. jnz short getport_CallVPD
  327. mov fVPD, -1
  328. getport_VPDNotInstalled:
  329. clc
  330. jmp short getport_exit
  331. getport_CallVPD:
  332. mov fVPD, 1
  333. push di
  334. sub di, LPTB
  335. shr di, 1 ; turn DI into port number
  336. xor ax, ax
  337. mov dx, VPD_GETPORT
  338. mov cx, di
  339. call [lpfnVPD]
  340. jnc getport_gotit
  341. ; port owned by another VM... ask the user for it
  342. add cl, '1' ; fix up the port name...
  343. mov pLPTByte, cl ; HACK HACK HACK
  344. lea cx, szMessage
  345. call Contention_Dlg
  346. jnz getport_userwontallow
  347. mov ax, 1 ; tell win386 we really do want it
  348. mov cx, di ;
  349. mov dx, VPD_GETPORT ;
  350. call [lpfnVPD] ; return with C set or clear...
  351. jmp short getport_gotit
  352. getport_userwontallow:
  353. stc
  354. getport_gotit:
  355. pop di
  356. getport_exit:
  357. ret
  358. GetPort386 endp
  359. ;----------------------------Private-Routine----------------------------;
  360. ;
  361. ; ReleasePort386
  362. ;
  363. ; If running under Win386, tell the VPD to deassign an LPT port.
  364. ;
  365. ; entry - DS:SI -> COMDEB
  366. ;
  367. ReleasePort386 proc near
  368. cmp fVPD, 1
  369. jne release_noVPD
  370. xor cx, cx
  371. mov cl, [si.DCB_id]
  372. and cl, NOT LPTx ; clear high bit
  373. mov dx, VPD_RELPORT
  374. call [lpfnVPD]
  375. release_noVPD:
  376. ret
  377. ReleasePort386 endp
  378. ;----------------------------Private-Routine----------------------------;
  379. ;
  380. ; GetCOMport386
  381. ;
  382. ; If running under Win386, tell the VCD to assign a COM port to us.
  383. ; The comm driver will handle contention.
  384. ;
  385. ; entry - DS:SI -> COMDEB
  386. ;
  387. ; exit - registers saved, carry = clear if OK to proceed, set if
  388. ; user won't allow assignment of port or Win386 error
  389. ;
  390. .386
  391. GetCOMport386 proc near
  392. public GetCOMport386
  393. push es
  394. pushad
  395. cmp fVCD, 0
  396. jl short getcomport_VCDNotInstalled
  397. jnz short getcomport_CallVCD
  398. mov bx, VCD
  399. mov di, DataOFFSET lpfnVCD
  400. call Get_API_Entry
  401. jz short getcomport_checknoVCD
  402. mov dx, VCD_GETVER
  403. call [lpfnVCD]
  404. cmp ax, 30Ah ;Q: 3.1 or greater?
  405. jae short getcomport_CallVCD ; Y:
  406. getcomport_checknoVCD:
  407. mov fVCD, -1
  408. getcomport_VCDNotInstalled:
  409. clc
  410. jmp short getcomport_exit
  411. getcomport_CallVCD:
  412. mov fVCD, 1
  413. mov ax, 10b ; flag ring0 int handler
  414. call VCD_GetPort_API
  415. jnc short getcomport_success ; jump if acquire worked
  416. jnz short getcomport_noport ; jump if port doesn't exist
  417. ; port owned by another VM... ask the user for it
  418. mov cl, [si.DCB_id]
  419. add cl, '1' ; fix up the port name...
  420. mov pCOMByte, cl
  421. lea cx, szCOMMessage
  422. call Contention_Dlg
  423. stc
  424. jnz short getcomport_exit
  425. mov ax, 11b ; tell win386 we really do want it
  426. call VCD_GetPort_API
  427. jc short getcomport_exit
  428. getcomport_success:
  429. mov dword ptr [VCD_int_callback], edi
  430. mov word ptr [VCD_int_callback+4], cx
  431. mov [si.VCD_data], ebx
  432. xchg ax, [si.Port]
  433. or ax, ax ;Q: already had port base?
  434. jnz short getcomport_exit ; Y: don't update vector #, or FIFO
  435. mov [si.IntVecNum], dl
  436. call GetPortFlags
  437. clc
  438. getcomport_exit:
  439. popad
  440. pop es
  441. ret
  442. getcomport_noport:
  443. mov [si.Port], -1
  444. jmp getcomport_exit
  445. GetCOMport386 endp
  446. VCD_GetPort_API proc near
  447. mov dx, VCD_GETPORT
  448. xor cx, cx
  449. mov cl, [si.DCB_Id] ; cx = port #
  450. mov di, VCDflags ; offset from start of DEB
  451. call [lpfnVCD]
  452. ret
  453. VCD_GetPort_API endp
  454. .8086
  455. ;----------------------------Private-Routine----------------------------;
  456. ;
  457. ; ReleaseCOMport386
  458. ;
  459. ; If running under Win386, tell the VCD to deassign a COM port.
  460. ;
  461. ; entry - DS:SI -> COMDEB
  462. ;
  463. ReleaseCOMport386 proc near
  464. ifndef WOW
  465. cmp fVCD, 1
  466. jne release_noVCD
  467. xor cx, cx
  468. mov cl, [si.DCB_id]
  469. mov dx, VCD_RELPORT
  470. call [lpfnVCD]
  471. else
  472. xor cx, cx
  473. mov cl, [si.DCB_id]
  474. push cx
  475. call WowCloseComPort
  476. endif
  477. release_noVCD:
  478. ret
  479. ReleaseCOMport386 endp
  480. PUBLIC StealPort
  481. StealPort proc near
  482. cmp fVCD, 1
  483. jne sp_yes
  484. mov dx, VCD_STEALPORT
  485. xor cx, cx
  486. mov cl, [si.DCB_id]
  487. call [lpfnVCD]
  488. or al, al
  489. jnz sp_yes
  490. sp_no:
  491. stc
  492. ret
  493. sp_yes:
  494. clc
  495. mov [si.VCDflags], 0
  496. ret
  497. StealPort endp
  498. page
  499. ;------------------------------------------------------------------------------
  500. ;
  501. ; ENTER: DS:SI -> ComDEB
  502. ; EXIT: AL = 0, if IRQ was unmasked, else -1, if IRQ was already masked
  503. ;
  504. MaskIRQ proc near
  505. push es
  506. push di
  507. mov di, ds
  508. mov es, di
  509. lea di, [si+SIZE ComDEB]
  510. mov ax, BIH_API_Get_Mask
  511. call APIHandler ; returns Carry Set, if masked
  512. jc short already_masked
  513. pushf
  514. mov ax, BIH_API_Mask
  515. call APIHandler ; mask IRQ
  516. xor ax, ax
  517. popf
  518. jnc short mask_exit
  519. already_masked:
  520. or al, -1
  521. mask_exit:
  522. pop di
  523. pop es
  524. ret
  525. MaskIRQ endp
  526. ;------------------------------------------------------------------------------
  527. ;
  528. ; ENTER: DS:SI -> ComDEB
  529. ;
  530. UnmaskIRQ proc near
  531. push es
  532. push di
  533. mov di, ds
  534. mov es, di
  535. lea di, [si+SIZE ComDEB]
  536. mov ax, BIH_API_Unmask
  537. call APIHandler
  538. pop di
  539. pop es
  540. ret
  541. UnmaskIRQ endp
  542. page
  543. ;----------------------------Public Routine-----------------------------;
  544. ;
  545. ; $INICOM - Initialize A Port
  546. ;
  547. ; Initalizes the requested port if present, and sets
  548. ; up the port with the given attributes when they are valid.
  549. ; This routine also initializes communications buffer control
  550. ; variables. This routine is passed the address of a device
  551. ; control block.
  552. ;
  553. ; The RLSD, CTS, and DSR signals should be ignored by all COM
  554. ; routines if the corresponding timeout values are 0.
  555. ;
  556. ; For the LPT ports, a check is performed to see if the hardware
  557. ; is present (via the LPT port addresses based at 40:8h. If the
  558. ; port is unavailable, an error is returned. If the port is
  559. ; available, then the DEB is set up for the port. $SETCOM will
  560. ; be called to set up the DEB so that there will be something
  561. ; valid to pass back to the caller when he inquires the DEB.
  562. ;
  563. ; No hardware initialization will be performed to prevent the
  564. ; RESET line from being asserted and resetting the printer every
  565. ; time this routine is called.
  566. ;
  567. ; Entry:
  568. ; EX:BX --> Device Control Block with all fields set.
  569. ; Returns:
  570. ; AX = 0 if no errors occured
  571. ; Error Returns:
  572. ; AX = initialization error code otherwise
  573. ; Registers Preserved:
  574. ; None
  575. ; Registers Destroyed:
  576. ; AX,BX,CX,DX,ES,FLAGS
  577. ; History:
  578. ;-----------------------------------------------------------------------;
  579. ;------------------------------Pseudo-Code------------------------------;
  580. ; {
  581. ; }
  582. ;-----------------------------------------------------------------------;
  583. assumes ds,Data
  584. assumes es,nothing
  585. public $INICOM
  586. $INICOM proc near
  587. push si ;As usual, save register variables
  588. push di
  589. mov ah,es:[bx.DCB_Id] ;Get device i.d.
  590. call GetDEB ;--> DEB for this device
  591. mov ax, IE_BADID ; call it a bad id (spooler uses DOS)
  592. jc InitCom15 ;Invalid device
  593. jns InitCom20 ; jmp if COM port
  594. push ds
  595. mov di, [si.BIOSPortLoc]
  596. cmp di, LPTB
  597. jb short InitLPT_Installed
  598. mov cx,__0040H ;[rkh] ...
  599. mov ds,cx ;Point DS: at ROM Save Area.
  600. assumes ds,nothing
  601. mov ax, IE_HARDWARE
  602. mov cx, wo [di]
  603. jcxz InitCom10 ; if zero, no hardware
  604. mov ax,IE_BadID ;Show bad device
  605. cmp ch, 0 ; zero hibyte -> not valid (redir)
  606. jz InitCom10 ; call it a bad id (spooler uses DOS)
  607. cmp di, LPTB ; LPT1?
  608. jz InitLPT_Installed ; yes, must be installed
  609. cmp cx, wo [di-2] ;Q: duplicate of previous port
  610. je InitCom10 ; Y: (redirected port)
  611. InitLPT_Installed:
  612. pop ds
  613. mov [si.Port], cx
  614. call $SETCOM
  615. call GetPort386 ; tell win386 we're using the port
  616. mov ax, IE_OPEN ; port already open (by another VM)
  617. jc InitCom15 ; error
  618. jmp InitCom90 ;That's all
  619. InitCom10:
  620. pop ds ; get DS back
  621. InitCom15:
  622. jmp InitCom100
  623. assumes ds,Data
  624. InitCom17:
  625. mov ax, IE_OPEN
  626. cmp [si.Port], -1 ;Q: determined that port didn't exist?
  627. jne InitCom15 ; N: return IE_OPEN
  628. jmp short InitCom27 ; Y: return IE_HARDWARE
  629. ; *** Set up serial port ***
  630. ;
  631. InitCom20:
  632. cmp [si.Port], -1 ;Q: port exists?
  633. je InitCom27 ; N: report not found
  634. mov ax, __WinFlags
  635. test ax, WF_ENHANCED
  636. jz short @F
  637. call GetCOMport386
  638. jc InitCom17
  639. @@:
  640. cmp [si.Port], 0 ;Q: already got info?
  641. jnz @F
  642. call FindCOMPort
  643. jc InitCom27 ; report not found, if error
  644. mov [si.Port], ax
  645. mov [si.IntVecNum], dl
  646. @@:
  647. push es ;Save these registers
  648. push di
  649. push cx ;needed later for $SETCOM etc
  650. push bx
  651. mov al, [si.IntVecNum]
  652. xor ah, ah
  653. lea di, [si+SIZE ComDEB]
  654. mov [di.BIS_IRQ_Number], ax
  655. mov di, DataOFFSET IRQhooks
  656. mov cx, MAXCOM+1
  657. InitCom25:
  658. cmp al, [di.IRQn] ;Q: hooked IRQ matches ours?
  659. je short InitCom30 ; Y:
  660. cmp [di.IRQn], 0 ;Q: end of hooked IRQ list?
  661. je short InitCom35 ; Y:
  662. add di, SIZE IRQ_Hook_Struc ; N: check next hook
  663. loop InitCom25
  664. int 3 ; data structures corrupt if we
  665. ; get here, because no hook table
  666. ; entries exist and there is suppose
  667. ; to be at least 1 for each DEB
  668. InitCom26:
  669. call ReleaseCOMport386 ; give port back to 386...
  670. pop bx
  671. pop cx
  672. pop di
  673. pop es
  674. InitCom27:
  675. mov ax, IE_HARDWARE ; jump if port not available
  676. jmp InitCom100
  677. InitCom30:
  678. cmp [di.HookCnt], 0 ;Q: IRQ still hooked?
  679. je short InitCom35 ; N: rehook
  680. inc [di.HookCnt] ; Y: inc hook count
  681. mov [si.IRQhook], di ; & link DEB into list
  682. mov ax, [di.First_DEB]
  683. mov [si.NextDEB], ax
  684. mov [di.First_DEB], si
  685. jmp short InitCom40
  686. InitCom35:
  687. mov [di.IRQn], al ; hook IRQ for first time, or rehook
  688. mov [si.IRQhook], di
  689. mov [di.First_DEB], si
  690. mov [di.HookCnt], 1
  691. call MaskIRQ
  692. mov [di.OldMask], al
  693. InitCom40: ; di -> IRQ_Hook_Struc
  694. cmp [fVPICD], 0 ;Q: VPICD bimodel services available?
  695. jl short InitCom415 ; N:
  696. mov ax, ds ; Y: use them
  697. mov es, ax
  698. lea di, [si+SIZE ComDEB]
  699. mov [di.BIS_Descriptor_Count], 2
  700. mov ax, word ptr [si.QInAddr+2] ; get selector of in queue
  701. mov [di.EBIS_Sel1.EBIS_User_Mode_Sel], ax
  702. mov ax, word ptr [si.QOutAddr+2] ; get selector of out queue
  703. mov [di.EBIS_Sel2.EBIS_User_Mode_Sel], ax
  704. mov ax, VPICD_Install_Handler
  705. call [lpfnVPICD]
  706. jnc InitCom42
  707. cmp [di.OldMask], 0
  708. jne InitCom26
  709. call UnmaskIRQ
  710. jmp InitCom26
  711. InitCom42:
  712. ;
  713. ; save newly allocated selectors/segments into "Alt" queue pointers
  714. ;
  715. mov ax, [di.EBIS_Sel1.EBIS_Super_Mode_Sel]
  716. mov word ptr [si.AltQInAddr+2], ax
  717. mov ax, [di.EBIS_Sel2.EBIS_Super_Mode_Sel]
  718. mov word ptr [si.AltQOutAddr+2], ax
  719. InitCom414:
  720. jmp InitCom59
  721. InitCom415:
  722. cmp [di.VecN], 0FFh ;Q: int already hooked?
  723. IFDEF No_DOSX_Bimodal_Services
  724. jnz short InitCom52 ; Y: init RMode ptrs in BIS
  725. ELSE
  726. jnz InitCom414 ; Y:
  727. ENDIF
  728. mov al, [si.IntVecNum]
  729. add al, 8 ; 1st PIC starts at vector 8h
  730. cmp al, 16 ;Q: 2nd PIC?
  731. jb short InitCom418 ; N:
  732. add al, 70h-16 ; Y: 2nd PIC starts at vector 70h
  733. InitCom418:
  734. mov [di.VecN], al
  735. ; *** Set interrupt vectors ***
  736. ;
  737. mov ah,35h ;Get the DOS vector
  738. int 21h ;DOS Get Vector Function
  739. mov wo [di.OldIntVec][0], bx
  740. mov wo [di.OldIntVec][2], es
  741. InitCom50:
  742. push ds ;Save original DS
  743. mov dx, [di.HandlerOff]
  744. mov bx, _INTERRUPT
  745. mov ds, bx ;Interrupt handler address in ds:dx
  746. assumes ds,nothing
  747. mov ah, 25h ;DOS Set Vector Function
  748. int 21h ;Set the DOS vector
  749. pop ds ;Original DS
  750. assumes ds,Data
  751. IFDEF No_DOSX_Bimodal_Services
  752. InitCom52:
  753. cmp [Using_DPMI], 0
  754. jz short InitCom57
  755. mov ax, Int31_Get_Version SHL 8
  756. int 31h
  757. mov bl, [si.IntVecNum]
  758. mov bh, bl
  759. add bl, dh ; assume master PIC
  760. sub bh, 8 ;Q: IRQ in master?
  761. jb @f ; Y: add master's base vec
  762. add bh, dl ; N: add slave's base vec
  763. mov bl, bh
  764. @@:
  765. mov ax, Get_RM_IntVector
  766. int 31h
  767. mov wo [di.RM_OldIntVec][0], dx
  768. mov wo [di.RM_OldIntVec][2], cx
  769. mov dx, [di.RM_HandlerOff]
  770. mov ax, _INTERRUPT
  771. call SegmentFromSelector
  772. mov cx, ax
  773. push cx
  774. mov ax, Set_RM_IntVector
  775. int 31h
  776. lea di, [si+SIZE ComDEB]
  777. mov wo [di.BIS_Super_Mode_API], IntCodeOFFSET RM_APIHandler
  778. pop cx
  779. mov wo [di.BIS_Super_Mode_API+2], cx
  780. ;
  781. ; Get segment addresses for the Q's and set AltQInAddr and AltQOutAddr
  782. ;
  783. mov ax, wo [si.AltQInAddr+2]
  784. call SegmentFromSelector
  785. mov wo [si.AltQInAddr+2], ax
  786. mov ax, wo [si.AltQOutAddr+2]
  787. call SegmentFromSelector
  788. mov wo [si.AltQOutAddr+2], ax
  789. InitCom57:
  790. ENDIF
  791. mov ax, __WinFlags ;In Standard mode, the PIC IRQ
  792. test al, WF_STANDARD ; priorities get rotated to favor
  793. jz InitCom59 ; the comm ports.
  794. call Rotate_PIC
  795. ; *** Interrupt handler set : jump here if handler is already installed ***
  796. ;
  797. InitCom59:
  798. pop bx
  799. pop cx
  800. pop di
  801. pop es
  802. InitCom60:
  803. mov dx,[si.Port] ;Set comm card address
  804. xor ax,ax ;Need a zero
  805. inc dx ;--> Interrupt Enable Register
  806. .errnz ACE_IER-ACE_RBR-1
  807. out dx,al ;Turn off interrupts
  808. call FlagNotActive
  809. add dl,ACE_MCR-ACE_IER ;--> Modem Control Register
  810. in al,dx
  811. and al,ACE_DTR+ACE_RTS ;Leave DTR, RTS high if already so
  812. iodelay ; but tri-state IRQ line
  813. out dx,al
  814. InitCom70:
  815. push es ;Zero queue counts and indexes
  816. push ds
  817. pop es
  818. assumes es,Data
  819. lea di,QInCount[si]
  820. mov cx,(EFlags-QInCount)/2
  821. .errnz (EFlags-QInCount) AND 1
  822. xor ax,ax
  823. cld
  824. rep stosw
  825. .errnz QInGet-QInCount-2
  826. .errnz QInPut-QInGet-2
  827. .errnz QOutCount-QInPut-2
  828. .errnz QOutGet-QOutCount-2
  829. .errnz QOutPut-QOutGet-2
  830. .errnz EFlags-QOutPut-2 ;First non-queue item
  831. pop es
  832. assumes es,nothing
  833. mov HSFlag[si],al ;Show no handshakes yet
  834. mov MiscFlags[si],al ;Show not discarding
  835. mov EvtWord[si],ax ;Show no events
  836. mov [si.VCDflags], al
  837. mov [si.SendTrigger], ax
  838. dec ax
  839. mov [si.RecvTrigger], ax
  840. ;Call $SETCOM to perform further hardware initialization.
  841. InitCom80:
  842. sub dl,ACE_MCR-ACE_FCR ; dx -> FCR
  843. in al, dx
  844. iodelay
  845. test al, ACE_FIFO_E2 ;Q: FIFO already on?
  846. jz short @F ; N:
  847. or EFlags[si], fFIFOpre ; Y: flag it
  848. @@:
  849. ; needs si, di, and es to be saved from the beginning of inicom
  850. call $SETCOM ;Set up Comm Device
  851. jnz short InitCom110 ;jump if failed
  852. call UnmaskIRQ
  853. and EFlags[si], fEFlagsMask ;Clear internal state
  854. InitCom90:
  855. xor ax,ax ;Return AX = 0 to show success
  856. mov ComErr[si],ax ;Get rid of any bogus init error
  857. InitCom100:
  858. pop di
  859. pop si
  860. ret
  861. ;
  862. ; jump to here, if call to $SETCOM failed
  863. ;
  864. ; DANGER! *** Call into middle of Terminate to clean things up *** DANGER!
  865. ;
  866. InitCom110:
  867. push ax ;Failure, save error code
  868. call Terminate45 ;Restore port address, int vec
  869. pop ax ;Restore error code and exit
  870. jmp InitCom100
  871. $INICOM endp
  872. page
  873. ;----------------------------Public Routine-----------------------------;
  874. ;
  875. ; $TRMCOM - Terminate Communications Channel
  876. ;
  877. ; Wait for any outbound data to be transmitted, drop the hardware
  878. ; handshaking lines, and disable interrupts. If the output queue
  879. ; contained data when it was closed, an error will be returned
  880. ;
  881. ; LPT devices have it easy. They just need to restore the I/O port
  882. ; address.
  883. ;
  884. ; Entry:
  885. ; AH = Device ID
  886. ; Returns:
  887. ; AX = 0
  888. ; Error Returns:
  889. ; AX = 8000h if invalid device ID
  890. ; AX = -2 if output queue timeout occured
  891. ; Registers Destroyed:
  892. ; AX,BX,CX,DX,ES,FLAGS
  893. ; History:
  894. ;-----------------------------------------------------------------------;
  895. ;------------------------------Pseudo-Code------------------------------;
  896. ; {
  897. ; }
  898. ;-----------------------------------------------------------------------;
  899. assumes ds,Data
  900. assumes es,nothing
  901. public $TRMCOM
  902. $TRMCOM proc near
  903. push si
  904. push di
  905. xor cx,cx ;Show no error if LPT port
  906. call GetDEB
  907. jc TermCom60 ;ID is invalid, return error
  908. js TermCom30 ;Port is a LPT port
  909. push ax ;Save port id
  910. or MiscFlags[si],Discard ;Show discarding serial data
  911. mov ComErr[si],cx ;Clear error flags
  912. mov QInCount[si],cx ;Show no chars in input queue
  913. call $RECCOM ;Send XON if needed
  914. ;-----------------------------------------------------------------------;
  915. ; We have to wait for the output queue to empty. To do this,
  916. ; a timer will be created. If no character has been transmitted
  917. ; when the timeout occurs, then an error will be indicated and
  918. ; the port closed anyway. If the timer cannot be created, then
  919. ; just loop until the queue empties, which will be better than
  920. ; discarding charatcers if there are any
  921. ;-----------------------------------------------------------------------;
  922. test [si.HSFlag], HHSAlwaysDown ; Q: handshaking ever up?
  923. jnz TermCom17 ; N: skip wait loop
  924. TermCom10:
  925. mov cx,QOutCount[si] ;Get current queue count
  926. jcxz TermCom20 ;No characters in queue
  927. cCall GetSystemMsecCount
  928. mov di, ax
  929. TermCom15:
  930. cmp QOutCount[si],cx ;Queue count change?
  931. jne TermCom10 ; Yes, restart timeout
  932. cCall GetSystemMsecCount
  933. sub ax, di
  934. cmp ax, Timeout * 1000 ;Q: Timeout reached?
  935. jb TermCom15 ; No, keep waiting
  936. IFDEF DEBUG_TimeOut
  937. .286
  938. pusha
  939. lea cx, szSendTO
  940. call Contention_Dlg
  941. popa
  942. jz TermCom10
  943. .8086
  944. ENDIF
  945. TermCom17:
  946. mov cx, TimeoutError ; Yes, show timeout error
  947. TermCom20:
  948. pop ax ;Restore cid
  949. TermCom30:
  950. mov dx,Port[si] ;Get port base address
  951. call Terminate ;The real work is done here
  952. mov ax,cx ;Set return code
  953. TermCom60:
  954. pop di
  955. pop si
  956. ret
  957. $TRMCOM endp
  958. page
  959. ;----------------------------Private-Routine----------------------------;
  960. ;
  961. ; Terminate - Terminate Device
  962. ;
  963. ; Restore the port I/O address and make sure that interrupts are off
  964. ;
  965. ; Entry:
  966. ; AH = Device Id.
  967. ; DX = Device I/O port address.
  968. ; SI --> DEB
  969. ; Returns:
  970. ; AX = 0
  971. ; Error Returns:
  972. ; AX = -1
  973. ; Registers Destroyed:
  974. ; AX,BX,DX,FLAGS
  975. ; History:
  976. ;-----------------------------------------------------------------------;
  977. assumes ds,Data
  978. assumes es,nothing
  979. public Terminate ;Public for debugging
  980. Terminate proc near
  981. or ah,ah ;LPT port?
  982. jns Terminate10 ; No, process COM port
  983. .errnz LPTx-10000000b
  984. Terminate5:
  985. call ReleasePort386 ; give port back to 386...
  986. jmp Terminate50 ;That's all
  987. ;-----------------------------------------------------------------------;
  988. ; It is a com port!
  989. ;
  990. ; We delay for a bit while the last character finishes transmitting
  991. ; Then we drop DTR and RTS, and disable the interrupt generation at
  992. ; the 8250. Even if fRTSDisable or fDTRDisable is set, those lines
  993. ; will be dropped when the port is closed.
  994. ;-----------------------------------------------------------------------;
  995. ;
  996. ; When the OUT2 bit is reset to 0 to disable interrupts, many ports
  997. ; generate an interrupt which can not be identified, because the the
  998. ; interrupt ID register will not be set. To work around this hardware
  999. ; problem we first mask the IRQ, then set the port into loopback mode
  1000. ; and output a NULL to generate a receive interrupt request. Then we
  1001. ; reset OUT2 and unmask the IRQ. This will cause the interrupt to occur
  1002. ; and the interrupt handler will be able to correctly identify the
  1003. ; interrupt as coming from the com port.
  1004. Terminate10:
  1005. inc dx ;Disable chip interrupts
  1006. .errnz ACE_IER-ACE_RBR-1
  1007. mov al, ACE_ERBFI ; except receive
  1008. out dx,al
  1009. call FlagNotActive ; don't need to check for postmessage
  1010. ; on timer ticks
  1011. add dl,ACE_LSR-ACE_IER ;--> line status register
  1012. iodelay
  1013. Terminate20:
  1014. in al,dx ;Wait until xmit is empty
  1015. and al,ACE_THRE+ACE_TSRE
  1016. cmp al,ACE_THRE+ACE_TSRE
  1017. jne Terminate20 ;Not empty yet
  1018. Terminate30:
  1019. xor al, al
  1020. test EFlags[si], fFIFOpre ;Q: leave FIFO enabled?
  1021. jz short @F ; N:
  1022. mov al, ACE_TRIG14 OR ACE_EFIFO OR ACE_CRFIFO OR ACE_CTFIFO
  1023. @@:
  1024. sub dl, ACE_LSR-ACE_FCR
  1025. out dx, al
  1026. iodelay
  1027. call MaskIRQ
  1028. add dl, ACE_MCR-ACE_FCR ;--> Modem Control Register
  1029. in al,dx
  1030. iodelay
  1031. mov ah, al
  1032. or al,ACE_LOOP ; turn on loopback
  1033. out dx, al
  1034. iodelay
  1035. sub dl, ACE_MCR-ACE_THR
  1036. xor al, al
  1037. out dx, al ; output a NULL to generate an int
  1038. iodelay
  1039. add dl, ACE_LSR-ACE_THR
  1040. Terminate35:
  1041. in al,dx ;Wait until xmit is empty
  1042. and al,ACE_THRE+ACE_TSRE
  1043. cmp al,ACE_THRE+ACE_TSRE
  1044. jne Terminate35 ;Not empty yet
  1045. mov al, ah
  1046. dec dl ; now clear OUT2 and loopback
  1047. .errnz ACE_LSR-ACE_MCR-1
  1048. and al,ACE_DTR+ACE_RTS ;Leave DTR, RTS high if already so
  1049. out dx,al ; but tri-state IRQ line
  1050. call UnmaskIRQ ; this will cause the receive int
  1051. ; to occur and be processed
  1052. sub dl, ACE_MCR-ACE_IER ; clear the receive int enable
  1053. xor al, al
  1054. out dx, al
  1055. dec dx
  1056. .errnz ACE_IER-ACE_RBR-1
  1057. call MaskIRQ
  1058. ;******* DANGER! ***** NOTICE! ***** DANGER! ***** WARNING! ***** NOTICE!
  1059. ;
  1060. ; Terminate45 is a secondary entrypoint into this routine--it's called
  1061. ; by the initialization code when that code is unable to properly init
  1062. ; a com port and needs to clean-up the mess it's made.
  1063. ;
  1064. ;******* DANGER! ***** NOTICE! ***** DANGER! ***** WARNING! ***** NOTICE!
  1065. Terminate45:
  1066. push cx ;Save original cx
  1067. push bx ;Save original bx
  1068. cmp [fVPICD], 0 ;Q: VPICD bimodel services available?
  1069. jl short @F ; N:
  1070. mov ax, ds ; Y: use them
  1071. mov es, ax
  1072. lea di, [si+SIZE ComDEB]
  1073. mov ax, VPICD_Remove_Handler
  1074. call [lpfnVPICD]
  1075. @@:
  1076. mov di, [si.IRQhook]
  1077. dec [di.HookCnt] ;Q: last port using IRQ?
  1078. jne short Terminate495 ; N: unmask IRQ again
  1079. mov al, 0FFh
  1080. xchg al, [di.VecN] ;Interrupt vector number
  1081. cmp al, 0FFh ;Q: IRQ vector hooked?
  1082. je short Terminate49 ; no...
  1083. IFDEF No_DOSX_Bimodal_Services
  1084. cmp [Using_DPMI], 0
  1085. jz short term_no_dpmi
  1086. ;
  1087. ; unhook RM vector thru DPMI for standard mode
  1088. ;
  1089. push ax
  1090. mov ax, Int31_Get_Version SHL 8
  1091. int 31h
  1092. mov bl, [si.IntVecNum]
  1093. mov bh, bl
  1094. add bl, dh ; assume master PIC
  1095. sub bh, 8 ;Q: IRQ in master?
  1096. jb @f ; Y: add master's base vec
  1097. add bh, dl ; N: add slave's base vec
  1098. mov bl, bh
  1099. @@:
  1100. mov dx, wo [di.RM_OldIntVec][0]
  1101. mov cx, wo [di.RM_OldIntVec][2]
  1102. mov ax, Set_RM_IntVector
  1103. int 31h
  1104. pop ax
  1105. term_no_dpmi:
  1106. ENDIF
  1107. mov dx, __WinFlags ;In Standard mode the PIC interrupt
  1108. test dl, WF_STANDARD ; priorities are changed to favor
  1109. jz Terminate48 ; the comm ports.
  1110. call Rotate_PIC ;This port no longer needs priority
  1111. Terminate48:
  1112. ; *** reset int vector to it's previous state
  1113. assumes ds,nothing
  1114. push ds ;Save original DS [rkh] ...
  1115. lds dx, [di.OldIntVec]
  1116. mov ah, 25h ;DOS Set Vector Function
  1117. int 21h ;Set the DOS vector
  1118. pop ds ;Original DS
  1119. assumes ds,data
  1120. ; *** interrupt vectors have been reset if needed at this point ***
  1121. ;
  1122. Terminate49:
  1123. mov cl, [di.OldMask]
  1124. ; Set the 8259 interrupt mask bit for this IRQ. Leave interrupts enabled
  1125. ; if they were already enabled when the comm port was initialized by us.
  1126. or cl, cl
  1127. jnz @f
  1128. Terminate495:
  1129. call UnmaskIRQ
  1130. @@:
  1131. xor ax, ax
  1132. xchg ax, [si.NextDEB]
  1133. cmp [di.First_DEB], si ;Q: DEB first for IRQ hook?
  1134. je short Terminate46 ; Y:
  1135. mov bx, [di.First_DEB] ; N: get first
  1136. Terminate453:
  1137. cmp [bx.NextDEB], si ;Q: does this DEB point to one terminating?
  1138. je Terminate455 ; Y:
  1139. mov bx, [bx.NextDEB] ; N: get next DEB
  1140. jmp Terminate453
  1141. Terminate455:
  1142. mov [bx.NextDEB], ax ; link previous DEB to NextDEB
  1143. jmp short Terminate47
  1144. Terminate46:
  1145. mov [di.First_DEB], ax ; point IRQ hook at NextDEB
  1146. Terminate47:
  1147. pop bx ;Original BX
  1148. call ReleaseCOMport386 ; give port back to 386...
  1149. pop cx ;Original CX
  1150. Terminate50: ;Also called from $INICOM !
  1151. xor ax,ax ;Indicate no error
  1152. ret ;Port is closed and deallocated
  1153. Terminate endp
  1154. page
  1155. ;----------------------------Public Routine-----------------------------;
  1156. ;
  1157. ; $ENANOTIFY - Enable Event Notification
  1158. ;
  1159. ; Entry:
  1160. ; AH = Device ID
  1161. ; BX = Window handle for PostMessage
  1162. ; CX = Receive threshold
  1163. ; DX = Transmit threshold
  1164. ; Returns:
  1165. ; AX = 1, if no errors occured
  1166. ; Error Returns:
  1167. ; AX = 0
  1168. ; Registers Preserved:
  1169. ; BX,SI,DI,DS
  1170. ; Registers Destroyed:
  1171. ; AX,CX,DX,ES,FLAGS
  1172. ; History:
  1173. ;-----------------------------------------------------------------------;
  1174. ;------------------------------Pseudo-Code------------------------------;
  1175. ; {
  1176. ; }
  1177. ;-----------------------------------------------------------------------;
  1178. assumes ds,Data
  1179. assumes es,nothing
  1180. public $ENANOTIFY
  1181. $ENANOTIFY proc near
  1182. push si
  1183. call GetDEB
  1184. mov ax, 0
  1185. jc scb_exit
  1186. mov ax, cx
  1187. inc ax
  1188. jz short scb_recv_ok
  1189. cmp cx, [si.QInSize] ;Q: receive threshold reasonable?
  1190. jb short scb_recv_ok ; Y:
  1191. %OUT should we return an error, if thresholds invalid?
  1192. mov cx, [si.QInSize] ; N:
  1193. sub cx, 10
  1194. scb_recv_ok:
  1195. inc dx
  1196. jz short scb_send_ok
  1197. dec dx
  1198. cmp dx, [si.QOutSize] ;Q: receive threshold reasonable?
  1199. jb short scb_send_ok ; Y:
  1200. mov dx, [si.QOutSize] ; N:
  1201. sub dx, 10
  1202. scb_send_ok:
  1203. mov [si.NotifyHandle], bx
  1204. mov [si.NotifyFlagsHI], CN_Notify
  1205. or bx, bx ;Q: null callback?
  1206. jnz scb_save_thresholds ; N: save thresholds
  1207. or cx, -1 ; Y: zero thresholds
  1208. xor dx, dx
  1209. mov [si.NotifyFlagsHI], 0
  1210. scb_save_thresholds:
  1211. mov [si.RecvTrigger], cx
  1212. mov [si.SendTrigger], dx
  1213. or [si.NotifyFlagsHI], CN_TRANSMIT ; we don't want to send
  1214. ; a transmit trigger notification until
  1215. ; the transmit buffer has been filled
  1216. ; above the trigger level and then
  1217. ; emptied below it again!
  1218. cmp wo lpPostMessage[2], 0 ;Q: gotten addr of PostMessage yet?
  1219. jne short scb_good ; Y:
  1220. push ds ; N: get module handle of USER
  1221. lea ax, szUser
  1222. push ax
  1223. cCall GetModuleHandle
  1224. push ax ; module handle
  1225. mov ax, POSTMESSAGE
  1226. cwd
  1227. push dx
  1228. push ax
  1229. cCall GetProcAddress
  1230. mov wo lpPostMessage[0], ax ; save received proc address
  1231. mov wo lpPostMessage[2], dx
  1232. scb_good:
  1233. mov ax, 1
  1234. scb_exit:
  1235. pop si
  1236. ret
  1237. $ENANOTIFY endp
  1238. page
  1239. ;----------------------------Public Routine-----------------------------;
  1240. ;
  1241. ; $SETQUE - Set up Queue Pointers
  1242. ;
  1243. ; Sets pointers to Receive and Transmit Queues, as provided by the
  1244. ; caller, and initializes those queues to be empty.
  1245. ;
  1246. ; Queues must be set before $INICOM is called!
  1247. ;
  1248. ; Entry:
  1249. ; AH = Device ID
  1250. ; ES:BX --> Queue Definition Block
  1251. ; Returns:
  1252. ; AX = 0 if no errors occured
  1253. ; Error Returns:
  1254. ; AX = error code
  1255. ; Registers Preserved:
  1256. ; BX,DX,SI,DI,DS
  1257. ; Registers Destroyed:
  1258. ; AX,CX,ES,FLAGS
  1259. ; History:
  1260. ;-----------------------------------------------------------------------;
  1261. ;------------------------------Pseudo-Code------------------------------;
  1262. ; {
  1263. ; }
  1264. ;-----------------------------------------------------------------------;
  1265. assumes ds,Data
  1266. assumes es,nothing
  1267. public $SETQUE
  1268. $SETQUE proc near
  1269. push si ;These will be used
  1270. push di
  1271. call GetDEB ;Get DEB
  1272. jc SetQue10 ;Invalid, ignore the call
  1273. js SetQue10 ;Ignore call for LPT ports
  1274. push ds ;Set ds:si --> QDB
  1275. push es ;Set es:di --> to ComDCB.QInAddr
  1276. pop ds
  1277. assumes ds,nothing
  1278. pop es
  1279. assumes es,Data
  1280. lea di,QInAddr[si]
  1281. mov si,bx
  1282. cld
  1283. FCLI ;No one else can play with queues
  1284. movsw ; QInAddr = QueueRxAddr
  1285. movsw
  1286. .errnz QueueRxAddr
  1287. sub si, 4 ; AltQInAddr = QueueRxAddr
  1288. mov cx, 5 ; QInSize = QueueRxSize
  1289. rep movsw ; QOutAddr = QueueTxAddr
  1290. sub si, 4
  1291. mov cx, 3 ; AltQOutAddr = QueueTxAddr
  1292. rep movsw ; QOutSize = QueueTxSize
  1293. xor ax,ax ;Will do some zero filling
  1294. mov cl,(EFlags-QInCount)/2
  1295. .errnz (EFlags-QInCount) AND 0FE01h
  1296. rep stosw
  1297. FSTI
  1298. push es ;Restore the data segment
  1299. pop ds
  1300. assumes ds,Data
  1301. assumes es,nothing
  1302. SetQue10:
  1303. pop di ;Restore saved registers
  1304. pop si
  1305. ret
  1306. ; The above code made a few assumptions about how memory
  1307. ; was allocated within the structures:
  1308. .errnz AltQInAddr-QInAddr-4
  1309. .errnz (QueueRxSize-QueueRxAddr)-(QInSize-AltQInAddr)
  1310. .errnz (QueueTxAddr-QueueRxSize)-(QOutAddr-QInSize)
  1311. .errnz AltQOutAddr-QOutAddr-4
  1312. .errnz (QueueTxSize-QueueTxAddr)-(QOutSize-AltQOutAddr)
  1313. .errnz QueueRxSize-QueueRxAddr-4
  1314. .errnz QueueTxAddr-QueueRxSize-2
  1315. .errnz QueueTxSize-QueueTxAddr-4
  1316. .errnz QInSize-AltQInAddr-4
  1317. .errnz QOutAddr-QInSize-2
  1318. .errnz QOutSize-AltQOutAddr-4
  1319. .errnz QInCount-QOutSize-2
  1320. .errnz QInGet-QInCount-2
  1321. .errnz QInPut-QInGet-2
  1322. .errnz QOutCount-QInPut-2
  1323. .errnz QOutGet-QOutCount-2
  1324. .errnz QOutPut-QOutGet-2
  1325. .errnz EFlags-QOutPut-2 ;First non-queue item
  1326. $SETQUE endp
  1327. page
  1328. ;----------------------------Public Routine-----------------------------;
  1329. ;
  1330. ; $SETCOM - Set Communications parameters
  1331. ;
  1332. ; Re-initalizes the requested port if present, and sets up the
  1333. ; port with the given attributes when they are valid.
  1334. ;
  1335. ; For LPT ports, just copies whatever is given since it's ignored
  1336. ; anyway.
  1337. ;
  1338. ; Entry:
  1339. ; ES:BX --> DCB with all fields set.
  1340. ; Returns:
  1341. ; 'Z' Set if no errors occured
  1342. ; AX = 0
  1343. ; Error Returns:
  1344. ; 'Z' clear if errors occured
  1345. ; AX = initialization error code.
  1346. ; Registers Destroyed:
  1347. ; AX,BX,CX,DX,ES,FLAGS
  1348. ; History:
  1349. ;-----------------------------------------------------------------------;
  1350. ;------------------------------Pseudo-Code------------------------------;
  1351. ; {
  1352. ; }
  1353. ;-----------------------------------------------------------------------;
  1354. assumes ds,Data
  1355. assumes es,nothing
  1356. public $SETCOM
  1357. $SETCOM proc near
  1358. cld
  1359. push si
  1360. push di
  1361. mov ah,es:[bx.DCB_Id] ;Get device i.d.
  1362. call GetDEB ;Get DEB pointer in SI
  1363. mov ax,IE_BadID ;Assume unknown device
  1364. jc SetCom10 ;Invalid device, return error
  1365. jns SetCom20 ;COM port
  1366. call SetCom100 ;Copy the DCB
  1367. SetCom5:
  1368. xor ax,ax ;Show no error
  1369. SetCom10:
  1370. or ax,ax ;Set/clear 'Z'
  1371. pop di ; and exit
  1372. pop si
  1373. ret
  1374. ;-----------------------------------------------------------------------;
  1375. ; Have a comm device, check all the serial parameters to make
  1376. ; sure they are correct before moving the new DCB into our space
  1377. ; and changing the ACE parameters.
  1378. ;-----------------------------------------------------------------------;
  1379. SetCom20:
  1380. call SetCom300 ;Baud rate valid?
  1381. jcxz SetCom10 ; No, return error
  1382. call SetCom400 ;Byte size/parity/stop bits correct?
  1383. jc SetCom10 ; No, return error
  1384. ; The parameters seem correct. Copy the DCB into our space and
  1385. ; initialize the ACE with the new parameters
  1386. mov dx,Port[si] ;Disable interrupts from the 8250
  1387. inc dx
  1388. .errnz ACE_IER-1
  1389. xor ax,ax
  1390. out dx,al
  1391. call FlagNotActive
  1392. call SetCom100 ;Copy the DCB
  1393. mov bx,si ;Set ES:BX --> DCB
  1394. call SetCom200 ;Get timeout masks
  1395. xchg al,ah ;Want them in the correct registers
  1396. mov wo MSRMask[si],ax
  1397. .errnz MSRInfinite-MSRMask-1
  1398. call SetCom400 ;Get line control byte
  1399. push ax ; and save LCR value
  1400. inc dx ;--> LCR
  1401. inc dx
  1402. .errnz ACE_LCR-ACE_IER-2
  1403. or al,ACE_DLAB ;Want access to divisor latch
  1404. out dx,al
  1405. mov RxMask[si],ah ;Save Receive character mask
  1406. mov ax,di ;Get flags mask, error mask
  1407. and [si.DCB_Flags],ah ;Disable parity checking if no parity
  1408. mov ErrorMask[si],al ;Save line status error mask
  1409. call SetCom300 ;Get baud rate
  1410. sub dl,ACE_LCR-ACE_DLL ;--> LSB of divisor latch
  1411. mov al,cl
  1412. out dx,al
  1413. mov al,ch
  1414. inc dx ;--> MSB of divisor latch
  1415. .errnz ACE_DLM-ACE_DLL-1
  1416. iodelay
  1417. out dx,al
  1418. inc dx ;--> LCR and clear divisor access bit
  1419. inc dx
  1420. .errnz ACE_LCR-ACE_DLM-2
  1421. pop ax
  1422. out dx,al
  1423. inc dx ;--> Modem Control Register
  1424. .errnz ACE_MCR-ACE_LCR-1
  1425. ;-----------------------------------------------------------------------;
  1426. ; Compute initial state of DTR and RTS. If they have been disabled,
  1427. ; then do not raise them, and disallow being used as a handshaking
  1428. ; line. Also compute the bits to use as hardware handshake bits
  1429. ; (DTR and/or RTS as indicated, qualified with the disabled flags).
  1430. ;-----------------------------------------------------------------------;
  1431. mov al,[si.DCB_Flags] ;Align DTR/RTS disable flags for 8250
  1432. and al,fRTSDisable+fDTRDisable
  1433. rol al,1 ;d0 = DTR, d2 = RTS (1 = disabled)
  1434. shr al,1 ;'C'= DTR, d1 = RTS
  1435. adc al,0 ;d0 = DTR, d1 = RTS
  1436. .errnz fRTSDisable-00000010b
  1437. .errnz fDTRDisable-10000000b
  1438. .errnz ACE_DTR-00000001b
  1439. .errnz ACE_RTS-00000010b
  1440. mov ah,al ;Save disable mask
  1441. xor al,ACE_DTR+ACE_RTS+ACE_OUT2
  1442. out dx,al ;Set Modem Control Register
  1443. mov al,[si.DCB_Flags2] ;Get hardware handshake flags
  1444. rol al,1 ;Align flags as needed
  1445. rol al,1
  1446. rol al,1
  1447. and al,ACE_DTR+ACE_RTS ;Mask bits of interest
  1448. not ah ;Want inverse of disable mask
  1449. and al,ah ;al = bits to handshake with
  1450. mov HHSLines[si],al ;Save for interrupt code
  1451. .errnz fDTRFlow-00100000b
  1452. .errnz fRTSFlow-01000000b
  1453. .errnz ACE_DTR-00000001b
  1454. .errnz ACE_RTS-00000010b
  1455. mov al,[si.DCB_Flags] ;Compute the mask for the output
  1456. shl al,1 ; hardware handshake lines
  1457. and al,ACE_DSR+ACE_CTS
  1458. mov OutHHSLines[si],al
  1459. .errnz fOutXCTSFlow-00001000b
  1460. .errnz fOutXDSRFlow-00010000b
  1461. .errnz ACE_CTS-00010000b
  1462. .errnz ACE_DSR-00100000b
  1463. ; Compute the queue count where XOff should be issued (or hardware
  1464. ; lines dropped). This will prevent having to do it at interrupt
  1465. ; time.
  1466. mov ax,QInSize[si] ;Get where they want it
  1467. sub ax,[si.DCB_XoffLim] ; and compute queue count
  1468. mov XOffPoint[si],ax
  1469. ; Enable FIFO if possible when baudrate >= 4800
  1470. ;
  1471. sub dl,ACE_MCR - ACE_FCR ; dx = FCR
  1472. test EFlags[si], fNoFIFO ;Q: FIFO can be enabled?
  1473. jnz sc_nofifo ; N:
  1474. mov ax, [si.DCB_BaudRate]
  1475. cmp ax, 4800
  1476. jb sc_nofifo
  1477. cmp ah, -1 ;Q: baudrate index?
  1478. jne sc_fifo ; N: baudrate >= 4800, enable FIFO
  1479. cmp ax, CBR_4800
  1480. jb sc_nofifo
  1481. %OUT this isn't correct, if lower baudrates are assigned indices above CBR_4800
  1482. sc_fifo:
  1483. mov al, ACE_TRIG14 OR ACE_EFIFO OR ACE_CRFIFO OR ACE_CTFIFO
  1484. out dx, al ; attempt to enable FIFO
  1485. test EFlags[si], fFIFOchkd ;Q: FIFO detect been done?
  1486. jnz sc_fifodone ; Y: enabled FIFO
  1487. iodelay
  1488. .errnz ACE_IIDR-ACE_FCR
  1489. in al, dx
  1490. or EFlags[si], fFIFOchkd
  1491. test al, ACE_FIFO_E2 ;Q: FIFO enabled?
  1492. jz short @F
  1493. test al, ACE_FIFO_E1 ;Q: 16550A detected?
  1494. jnz sc_fifodone ; Y: enabled FIFO
  1495. @@:
  1496. iodelay
  1497. or EFlags[si], fNoFIFO
  1498. sc_nofifo:
  1499. xor al, al
  1500. out dx, al
  1501. sc_fifodone:
  1502. sub dl,ACE_FCR-ACE_RBR ; dx -> RBR
  1503. ;
  1504. ; Delay for things to settle
  1505. ;
  1506. push dx
  1507. cCall GetSystemMsecCount
  1508. pop dx
  1509. mov cx, ax
  1510. delay_loop:
  1511. in al, dx ;Read it once
  1512. push dx
  1513. cCall GetSystemMsecCount
  1514. pop dx
  1515. sub ax, cx
  1516. cmp ax, DELAY_TIME ;Q: Timeout reached?
  1517. ifndef WOW
  1518. jb delay_loop ; N:
  1519. endif
  1520. add dl,ACE_MSR ;--> Modem Status reg
  1521. in al,dx ;Throw away 1st status read
  1522. iodelay
  1523. in al,dx ;Save 2nd for MSRWait (Clear MSR int)
  1524. mov MSRShadow[si],al
  1525. ; Win 3.0 didn't check hardware handshaking until the line status changed.
  1526. ; Allow some apps to keep that behavior.
  1527. push dx
  1528. xor ax, ax
  1529. cCall GetAppCompatFlags,<ax>
  1530. pop dx
  1531. test ax, GACF_DELAYHWHNDSHAKECHK
  1532. jnz short sc_HHSup
  1533. ;
  1534. ; HACK FOR SOME MODEMS: apparently some modems set CTS, but don't set DSR
  1535. ; which means that COMM.DRV won't send if the app specifies that hardware
  1536. ; handshaking is based on CTS & DSR being set.
  1537. ;
  1538. mov ah,OutHHSLines[si]
  1539. mov al, MSRShadow[si]
  1540. and al,ah ;Only leave bits of interest
  1541. cmp al, ah ;Q: handshaking lines ok?
  1542. je short sc_HHSup ; Y:
  1543. cmp ah, ACE_CTS OR ACE_DSR ;Q: app looking for both high?
  1544. jne short sc_HHSdown ; N: skip hack
  1545. test [si.EFlags], fUseDSR ;Q: DSR is always significant?
  1546. jnz short sc_HHSdown ; Y: skip hack
  1547. cmp al, ACE_CTS ;Q: DSR low & CTS high
  1548. jne short sc_HHSdown ; N: skip hack
  1549. and ah, NOT ACE_DSR ; Y: ignore DSR line
  1550. mov OutHHSLines[si], ah
  1551. jmp short sc_HHSup
  1552. sc_HHSdown:
  1553. or [si.HSFlag], HHSDown OR HHSAlwaysDown ; flag handshaking down
  1554. sc_HHSup:
  1555. ;-----------------------------------------------------------------------;
  1556. ; Now, at last, interrupts can be enabled. Don't enable the
  1557. ; transmitter empty interrupt. It will be enabled by the first
  1558. ; call to KickTx.
  1559. ;-----------------------------------------------------------------------;
  1560. sub dl,ACE_MSR-ACE_IER ;--> Interrupt Enable Register
  1561. ; flag port as being active
  1562. push cx
  1563. mov cl, [si.DCB_Id]
  1564. mov ax, 1
  1565. shl ax, cl
  1566. or [activeCOMs], ax
  1567. pop cx
  1568. mov al,ACE_ERBFI+ACE_ELSI+ACE_EDSSI
  1569. FCLI
  1570. out dx,al ;Enable interrupts.
  1571. add dl,ACE_LSR-ACE_IER ;--> Line Status Register
  1572. iodelay
  1573. in al,dx ;Clear any Line Status interrupt
  1574. sub dl,ACE_LSR ;--> Receiver Buffer Register
  1575. iodelay
  1576. in al,dx ;Clear any Received Data interrupt
  1577. FSTI
  1578. jmp SetCom5 ;All done
  1579. $SETCOM endp
  1580. page
  1581. FlagNotActive proc near
  1582. push cx
  1583. mov cl, [si.DCB_Id]
  1584. mov ax, NOT 1
  1585. rol ax, cl
  1586. and [activeCOMs], ax
  1587. pop cx
  1588. ret
  1589. FlagNotActive endp
  1590. ;----------------------------Private-Routine----------------------------;
  1591. ;
  1592. ; SetCom100
  1593. ;
  1594. ; Copy the given DCB into the appropriate DEB. The check has
  1595. ; already been made to determine that the ID was valid, so
  1596. ; that check can be skipped.
  1597. ;
  1598. ; Entry:
  1599. ; ES:BX --> DCB
  1600. ; DS:SI --> DEB
  1601. ; Returns:
  1602. ; DS:SI --> DEB
  1603. ; ES = Data
  1604. ; Error Returns:
  1605. ; None
  1606. ; Registers Destroyed:
  1607. ; AX,CX,ES,DI,FLAGS
  1608. ; History:
  1609. ;-----------------------------------------------------------------------;
  1610. ;------------------------------Pseudo-Code------------------------------;
  1611. ; {
  1612. ; }
  1613. ;-----------------------------------------------------------------------;
  1614. assumes ds,Data
  1615. assumes es,nothing
  1616. SetCom100 proc near
  1617. push si ;Save DEB pointer
  1618. mov di,si
  1619. mov si,bx
  1620. push es
  1621. mov ax,ds
  1622. pop ds
  1623. assumes ds,nothing
  1624. mov es,ax
  1625. assumes es,Data
  1626. mov cx,DCBSize
  1627. cld
  1628. rep movsb
  1629. mov ds,ax
  1630. assumes ds,Data
  1631. pop si ;Restore DEB pointer
  1632. ret
  1633. SetCom100 endp
  1634. page
  1635. ;----------------------------Private-Routine----------------------------;
  1636. ;
  1637. ; SetCom200
  1638. ;
  1639. ; Based on whether or not a timeout has been specified for each
  1640. ; signal, set up a mask byte which is used to mask off lines for
  1641. ; which we wish to detect timeouts. 0 indicates that the line is
  1642. ; to be ignored.
  1643. ;
  1644. ; Also set up a mask to indicate those lines which are set for
  1645. ; infinite timeout. 1 indicates that the line has infinite
  1646. ; timeout.
  1647. ;
  1648. ; Entry:
  1649. ; ES:BX --> DCB
  1650. ; Returns:
  1651. ; ES:BX --> DCB
  1652. ; AH = lines to check
  1653. ; AL = lines with infinite timeout
  1654. ; Error Returns:
  1655. ; None
  1656. ; Registers Destroyed:
  1657. ; AX,CX,FLAGS
  1658. ; History:
  1659. ;-----------------------------------------------------------------------;
  1660. ;------------------------------Pseudo-Code------------------------------;
  1661. ; {
  1662. ; }
  1663. ;-----------------------------------------------------------------------;
  1664. assumes ds,Data
  1665. assumes es,nothing
  1666. SetCom200 proc near
  1667. xor ax,ax
  1668. xor cx,cx ;Get mask of lines with timeout = 0
  1669. call SetCom210
  1670. not al ;Invert result to get lines to check
  1671. and al,ACE_CTS+ACE_DSR+ACE_RLSD
  1672. xchg ah,al
  1673. dec cx ;Get mask of infinite timeouts
  1674. SetCom210:
  1675. cmp es:[bx.DCB_RlsTimeout],cx ;Timeout set to passed value?
  1676. jne SetCom220 ; No
  1677. or al,ACE_RLSD ; Yes, show checking line
  1678. SetCom220:
  1679. cmp es:[bx.DCB_CtsTimeout],cx ;Timeout set to passed value?
  1680. jne SetCom230 ; No
  1681. or al,ACE_CTS ; Yes, show checking line
  1682. SetCom230:
  1683. cmp es:[bx.DCB_DsrTimeout],cx ;Timeout set to passed value?
  1684. jne SetCom240 ; No
  1685. or al,ACE_DSR ; Yes, show checking line
  1686. SetCom240:
  1687. ret
  1688. SetCom200 endp
  1689. page
  1690. ;----------------------------Private-Routine----------------------------;
  1691. ;
  1692. ; SetCom300
  1693. ;
  1694. ; Calculate the correct baudrate divisor for the comm chip.
  1695. ;
  1696. ; Note that the baudrate is allowed to be any integer in the
  1697. ; range 2-19200. The divisor is computed as 115,200/baudrate.
  1698. ;
  1699. ; Entry:
  1700. ; ES:BX --> DCB
  1701. ; Returns:
  1702. ; ES:BX --> DCB
  1703. ; CX = baudrate
  1704. ; Error Returns:
  1705. ; CX = 0 if error
  1706. ; AX = error code if invalid baud rate
  1707. ; Registers Destroyed:
  1708. ; AX,CX,FLAGS
  1709. ; History:
  1710. ;-----------------------------------------------------------------------;
  1711. BaudRateByIndexTable label word
  1712. dw 1047 ; CBR_110
  1713. dw 384 ; CBR_300
  1714. dw 192 ; CBR_600
  1715. dw 96 ; CBR_1200
  1716. dw 48 ; CBR_2400
  1717. dw 24 ; CBR_4800
  1718. dw 12 ; CBR_9600
  1719. dw 9 ; CBR_14400
  1720. dw 6 ; CBR_19200
  1721. dw 0 ; 0FF19h (reserved)
  1722. dw 0 ; 0FF1Ah (reserved)
  1723. dw 3 ; CBR_38400
  1724. dw 0 ; 0FF1Ch (reserved)
  1725. dw 0 ; 0FF1Dh (reserved)
  1726. dw 0 ; 0FF1Eh (reserved)
  1727. dw 2 ; CBR_56000
  1728. assumes ds,Data
  1729. assumes es,nothing
  1730. SetCom300 proc near
  1731. push dx
  1732. mov cx,es:[bx.DCB_BaudRate] ;Get requested baud rate
  1733. xor ax,ax ;Assume error
  1734. cmp cx, CBR_110 ;Q: baudrate specified as an index?
  1735. jae by_index
  1736. cmp cx,2 ;Within valid range?
  1737. jnae SetCom310 ; No, return error
  1738. mov dx,1 ;(dx:ax) = 115,200
  1739. mov ax,0C200h
  1740. div cx ;(ax) = 115,200/baud
  1741. SetCom310:
  1742. mov cx,ax ;(cx) = baud rate, or error code (0)
  1743. mov ax,IE_Baudrate ;Set error code incase bad baud
  1744. pop dx
  1745. ret
  1746. by_index:
  1747. cmp cx, CBR_56000 ;Q: above supported?
  1748. ja SetCom310 ; Y: return error
  1749. push bx
  1750. mov bx, cx
  1751. sub bx, CBR_110
  1752. shl bx, 1
  1753. mov ax, cs:[bx+BaudRateByIndexTable] ; get divisor
  1754. pop bx
  1755. jmp SetCom310 ; Y: return error
  1756. SetCom300 endp
  1757. page
  1758. ;----------------------------Private-Routine----------------------------;
  1759. ;
  1760. ; SetCom400
  1761. ;
  1762. ; Check the line configuration (Parity, Stop bits, Byte size)
  1763. ;
  1764. ; Entry:
  1765. ; ES:BX --> DCB
  1766. ; Returns:
  1767. ; ES:BX --> DCB
  1768. ; 'C' clear if OK
  1769. ; AL = Line Control Register
  1770. ; AH = RxMask
  1771. ; DI[15:8] = Flags mask (to remove parity checking)
  1772. ; DI[7:0] = Error mask (to remove parity error)
  1773. ; Error Returns:
  1774. ; 'C' set if error
  1775. ; AX = error code
  1776. ; Registers Destroyed:
  1777. ; AX,CX,DI,FLAGS
  1778. ; History:
  1779. ;-----------------------------------------------------------------------;
  1780. ;------------------------------Pseudo-Code------------------------------;
  1781. ; {
  1782. ; }
  1783. ;-----------------------------------------------------------------------;
  1784. assumes ds,Data
  1785. assumes es,nothing
  1786. SetCom400 proc near
  1787. mov ax,wo es:[bx.DCB_ByteSize] ;al = byte size, ah = parity
  1788. cmp ah,SpaceParity ;Parity out of range?
  1789. ja SetCom470 ; Yes, return error
  1790. mov di,0FF00h+ACE_OR+ACE_PE+ACE_FE+ACE_BI
  1791. or ah,ah ;Is parity "NONE"?
  1792. jnz SetCom410 ; No, something is there for parity
  1793. xor di,(fParity*256)+ACE_PE ;Disable parity checking
  1794. SetCom410:
  1795. cmp al,8 ;Byte size out of range?
  1796. ja SetCom460 ; Yes, error
  1797. SetCom420:
  1798. sub al,5 ;Shift byte size to bits 0&1
  1799. .errnz ACE_WLS-00000011b ;Word length must be these bits
  1800. jc SetCom460 ;Byte size is illegal, return error
  1801. add ah,ah ;Map parity to ACE bits
  1802. jz SetCom430 ;0=>0, 1=>1, 2=>3, 3=>5, 4=>7
  1803. dec ah
  1804. SetCom430:
  1805. shl ah,1 ;Align with 8250 parity bits
  1806. shl ah,1
  1807. shl ah,1
  1808. or al,ah ;Add to byte size
  1809. .errnz NoParity-0
  1810. .errnz OddParity-1
  1811. .errnz EvenParity-2
  1812. .errnz MarkParity-3
  1813. .errnz SpaceParity-4
  1814. .errnz ACE_PEN-00001000b
  1815. .errnz ACE_PSB-00110000b
  1816. .errnz ACE_EPS-00010000b
  1817. .errnz ACE_SP-00100000b
  1818. or al,ACE_2SB ;Assume 2 stop bits
  1819. mov ah,es:[bx.DCB_StopBits] ;Get # of stop bits 0=1,1/2= .GT. 1
  1820. or ah,ah ;Out of range?
  1821. js SetCom470 ; Yes, return error
  1822. jz SetCom440 ;One stop bit
  1823. sub ah,2
  1824. jz SetCom450 ;Two stop bits
  1825. jns SetCom470 ;Not 1.5, return error
  1826. test al,ACE_WLS ;1.5 stop bits, 5 bit words?
  1827. jnz SetCom470 ; No, illegal
  1828. .errnz OneStopBit-0
  1829. .errnz One5StopBits-1
  1830. .errnz TwoStopBits-2
  1831. .errnz ACE_5BW
  1832. SetCom440:
  1833. and al,NOT ACE_2SB ;Show 1 (or 1.5) stop bit(s)
  1834. ; From the byte size, get a mask to be used for stripping
  1835. ; off unused bits as the characters are received.
  1836. SetCom450:
  1837. push dx
  1838. mov cl,es:[bx.DCB_ByteSize] ;Get data byte size
  1839. mov dx,00FFh ;Turn into mask by shifting bits
  1840. shl dx,cl
  1841. mov ah,dh ;Return mask in ah
  1842. pop dx
  1843. clc ;Show all is fine
  1844. ret
  1845. SetCom460:
  1846. mov ax,IE_ByteSize ;Show byte size is wrong
  1847. stc ;Show error
  1848. ret
  1849. SetCom470:
  1850. mov ax,IE_Default ;Show something is wrong
  1851. stc ;Show error
  1852. ret
  1853. SetCom400 endp
  1854. page
  1855. ;----------------------------------------------------------------------------
  1856. ; SuspendOpenCommPorts:
  1857. ;
  1858. ; This routine is called from 286 Winoldaps to simply deinstall the comm port
  1859. ; hooks.
  1860. ;----------------------------------------------------------------------------
  1861. cProc SuspendOpenCommPorts,<FAR,PUBLIC,PASCAL>
  1862. cBegin nogen
  1863. assumes cs,Code
  1864. assumes ds,Data
  1865. %OUT not masking IRQ's
  1866. ; Nothing to do under 3.1!
  1867. ret
  1868. cEnd nogen
  1869. ;----------------------------------------------------------------------------;
  1870. ; ReactivateOpenCommPorts: ;
  1871. ; ;
  1872. ; This routine reinstalls the comm hooks in real mode and reads the 8250 ;
  1873. ; data and status registers to clear pending interrupts. ;
  1874. ;----------------------------------------------------------------------------;
  1875. cProc ReactivateOpenCommPorts,<FAR,PASCAL,PUBLIC>,<si,di>
  1876. cBegin
  1877. call Rotate_PIC ;make comm ports highest priority
  1878. mov cx, MAXCOM+1
  1879. mov di,dataOffset COMptrs
  1880. rcp_loop:
  1881. mov si, [di]
  1882. mov dx, Port[si]
  1883. or dx, dx
  1884. jz @f
  1885. call InitAPort ;read comm port regs to clr pending ints
  1886. @@:
  1887. add di, 2
  1888. loop rcp_loop
  1889. cEnd
  1890. ;----------------------------------------------------------------------------;
  1891. ; InitAPort: ;
  1892. ; ;
  1893. ; reads the data,status & IIR registers of a port (has to be 8250!) ;
  1894. ; ;
  1895. ; If the port has an out queue pending, then this woutine will also start ;
  1896. ; the transmit process by faking a comm interrupt. ;
  1897. ;----------------------------------------------------------------------------;
  1898. public InitAPort
  1899. InitAPort proc near
  1900. add dl,ACE_RBR ;dx=receive buffer register
  1901. in al,dx ;read the data port
  1902. jmp short $+2 ;i/o delay
  1903. add dl,ACE_LSR - ACE_RBR ;get to the status port
  1904. in al,dx ;read it too.
  1905. jmp short $+2 ;i/o delay
  1906. add dl,ACE_IIDR - ACE_LSR ;get to the line status register
  1907. in al,dx ;read it once more
  1908. jmp short $+2 ;i/o delay
  1909. add dl,ACE_MSR - ACE_IIDR ;get to the modem status register
  1910. in al,dx ;read it once more
  1911. jmp short $+2 ;i/o delay
  1912. add dl,ACE_RBR - ACE_MSR ;get to the receive buffer register
  1913. in al,dx ;read it once more
  1914. jmp short $+2 ;i/o delay
  1915. call UnmaskIRQ
  1916. ; now if the port has characters pending to be sent out then we must fake a
  1917. ; comm interrupt.
  1918. cmp [si].QOutCount,0 ;characters pending to be sent ?
  1919. jz @f ;no.
  1920. FCLI ;disable interrupts
  1921. call FakeCOMIntFar ;fake an interrupt
  1922. FSTI ;renable interrupts
  1923. @@:
  1924. ret
  1925. InitAPort endp
  1926. page
  1927. ;----------------------------Public Routine-----------------------------;
  1928. ;
  1929. ; $DCBPtr - Return Pointer To DCB
  1930. ;
  1931. ; Returns a long pointer to the DCB for the requested device.
  1932. ;
  1933. ; Entry:
  1934. ; AH = Device ID
  1935. ; Returns:
  1936. ; DX:AX = pointer to DCB.
  1937. ; Error Returns:
  1938. ; DX:AX = 0
  1939. ; Registers Preserved:
  1940. ; SI,DI,DS
  1941. ; Registers Destroyed:
  1942. ; BX,CX,ES,FLAGS
  1943. ; History:
  1944. ;-----------------------------------------------------------------------;
  1945. ;------------------------------Pseudo-Code------------------------------;
  1946. ; {
  1947. ; }
  1948. ;-----------------------------------------------------------------------;
  1949. assumes ds,Data
  1950. assumes es,nothing
  1951. public $DCBPTR
  1952. $DCBPTR proc near
  1953. push si
  1954. xor dx,dx
  1955. call GetDEB ;Get pointer to DEB
  1956. mov ax,dx
  1957. jc DCBPtr10 ;Jump if invalid device
  1958. mov ax,si ;else return value here
  1959. mov dx,ds
  1960. DCBPtr10:
  1961. pop si
  1962. ret
  1963. $DCBPTR endp
  1964. page
  1965. ;----------------------------Private-Routine----------------------------;
  1966. ;
  1967. ; GetDEB - Get Pointer To Device's DEB
  1968. ;
  1969. ; Returns a pointer to appropriate DEB, based on device number.
  1970. ;
  1971. ; Entry:
  1972. ; AH = cid
  1973. ; Returns:
  1974. ; 'C' clear
  1975. ; 'S' set if LPT device
  1976. ; DS:SI --> DEB is valid cid
  1977. ; AH = cid
  1978. ; Error Returns:
  1979. ; 'C' set if error (cid is invalid)
  1980. ; AX = 8000h
  1981. ; Registers Preserved:
  1982. ; BX,CX,DX,DI,DS,ES
  1983. ; Registers Destroyed:
  1984. ; AX,SI,FLAGS
  1985. ; History:
  1986. ;-----------------------------------------------------------------------;
  1987. ;------------------------------Pseudo-Code------------------------------;
  1988. ; {
  1989. ; }
  1990. ;-----------------------------------------------------------------------;
  1991. assumes ds,Data
  1992. assumes es,nothing
  1993. public GetDEB ;Public for debugging
  1994. GetDEB proc near
  1995. push cx
  1996. mov cl, ah
  1997. and cx, (NOT LPTx AND 0FFh)
  1998. test ah, ah ;Q: LPT id?
  1999. js short GetDEB10 ; Y:
  2000. .errnz LPTx - 80h
  2001. cmp ah, MAXCOM ;Q: Within range?
  2002. ja GetDEB30 ; N: return invalid ID
  2003. shl cx, 1
  2004. mov si, cx
  2005. mov si, [si+COMptrs]
  2006. jmp short GetDEB20
  2007. GetDEB10:
  2008. cmp ah, LPTx+MAXLPT ;Q: Within range?
  2009. ja GetDEB30 ; N: return invalid ID
  2010. mov si, DataOFFSET LPT1
  2011. jcxz GetDEB20
  2012. GetDEB15:
  2013. add si, SIZE LptDEB
  2014. loop GetDEB15
  2015. GetDEB20:
  2016. pop cx
  2017. or ah, ah ; clear Carry & set S, if LPT port
  2018. ret
  2019. GetDEB30:
  2020. pop cx
  2021. mov ax,8000h ;Set error code
  2022. stc ;Set 'C' to show error
  2023. ret
  2024. GetDEB endp
  2025. page
  2026. CvtHex proc near
  2027. ; assume DS=SS
  2028. push si
  2029. mov cl, 4
  2030. mov si, di
  2031. xor dx, dx
  2032. cld
  2033. ch_lp:
  2034. lodsb
  2035. sub al, '0' ;Q: char < '0'
  2036. jb ch_exit ; Y: return
  2037. cmp al, 9 ;Q: char <= '9'
  2038. jbe ch_got_digit ; Y: move digit into result
  2039. sub al, 'A' - '0' ;Q: char < 'A'
  2040. jb ch_exit ; Y: return
  2041. add al, 10
  2042. cmp al, 15 ;Q: char <= 'F'
  2043. jbe ch_got_digit ; Y: move hex char into result
  2044. sub al, 10 + 'a' - 'A' ;Q: char < 'a'
  2045. jb ch_exit ; Y: return
  2046. add al, 10
  2047. cmp al, 15 ;Q: char > 'f'
  2048. ja ch_exit ; Y: return
  2049. ch_got_digit:
  2050. shl dx, cl
  2051. or dl, al
  2052. jmp ch_lp
  2053. ch_exit:
  2054. mov ax, dx
  2055. pop si
  2056. ret
  2057. CvtHex endp
  2058. .286
  2059. ; attempt to read base from SYSTEM.INI
  2060. GetComBase proc near
  2061. push ds ; save our DS
  2062. sub sp, 6
  2063. mov di, sp
  2064. mov byte ptr ss:[di], 0
  2065. push ds
  2066. push DataOFFSET lpCommSection
  2067. push ds
  2068. push DataOFFSET lpCommBase
  2069. push ss ; temp buffer
  2070. push di
  2071. push ss ; default = temp buffer
  2072. push di
  2073. push 5
  2074. push ds
  2075. push DataOFFSET lpSYSTEMINI
  2076. mov cx, ss ; temporarily assign DS=SS
  2077. mov ds, cx ; to allow KERNEL to thunk
  2078. assumes ds,nothing
  2079. call GetPrivateProfileString ; our segment in real mode
  2080. or ax, ax
  2081. jz short gcb_exit
  2082. call CvtHex ; DS still equal to SS
  2083. gcb_exit:
  2084. add sp, 6
  2085. pop ds ; restore our DS
  2086. assumes ds,Data
  2087. ret
  2088. GetComBase endp
  2089. GetPortIRQ proc near
  2090. push ds ; save our DS
  2091. push ds
  2092. push DataOFFSET lpCommSection
  2093. push ds
  2094. push DataOFFSET lpCommIrq
  2095. push bx
  2096. mov bl, [si.DCB_Id]
  2097. cmp bl, 4
  2098. jb @f
  2099. mov bl, 4
  2100. @@:
  2101. xor bh, bh
  2102. mov bl, [bx+default_table]
  2103. mov cx, bx
  2104. pop bx
  2105. push cx ; default
  2106. push ds
  2107. push DataOFFSET lpSYSTEMINI
  2108. mov cx, ss ; temporarily assign DS=SS
  2109. mov ds, cx ; to allow KERNEL to thunk
  2110. assumes ds,nothing
  2111. call GetPrivateProfileInt ; our segment in real mode
  2112. pop ds ; restore our DS
  2113. assumes ds,Data
  2114. ret
  2115. GetPortIRQ endp
  2116. GetPortFlags proc near
  2117. mov al, [si.DCB_Id]
  2118. .erre MAXCOM LT 9 ;only single digit port numbers supported
  2119. add al, '1'
  2120. mov [CommFIFOX], al
  2121. mov [CommDSRx], al
  2122. call GetPortFIFO
  2123. call GetPortDSR
  2124. ret
  2125. GetPortFlags endp
  2126. GetPortFIFO proc near
  2127. push ds ; save our DS
  2128. push ds
  2129. push DataOFFSET lpCommSection
  2130. push ds
  2131. push DataOFFSET lpCommFifo
  2132. push 2
  2133. push ds
  2134. push DataOFFSET lpSYSTEMINI
  2135. mov cx, ss ; temporarily assign DS=SS
  2136. mov ds, cx ; to allow KERNEL to thunk
  2137. assumes ds,nothing
  2138. call GetPrivateProfileInt ; our segment in real mode
  2139. pop ds ; restore our DS
  2140. assumes ds,Data
  2141. cmp ax, 1
  2142. ja short gpf_exit ; just check at open
  2143. jb short gpf_no_fifo ; force OFF, if = 0
  2144. or EFlags[si], fFIFOchkd ; flag as checked, to force ON
  2145. jmp short gpf_exit
  2146. gpf_no_fifo:
  2147. or EFlags[si], fNoFIFO OR fFIFOchkd ; force OFF
  2148. gpf_exit:
  2149. ret
  2150. GetPortFIFO endp
  2151. GetPortDSR proc near
  2152. push ds ; save our DS
  2153. push ds
  2154. push DataOFFSET lpCommSection
  2155. push ds
  2156. push DataOFFSET lpCommDSR
  2157. push 0
  2158. push ds
  2159. push DataOFFSET lpSYSTEMINI
  2160. mov cx, ss ; temporarily assign DS=SS
  2161. mov ds, cx ; to allow KERNEL to thunk
  2162. assumes ds,nothing
  2163. call GetPrivateProfileInt ; our segment in real mode
  2164. pop ds ; restore our DS
  2165. assumes ds,Data
  2166. or ax, ax
  2167. jz short gpd_exit
  2168. or EFlags[si], fUseDSR
  2169. gpd_exit:
  2170. ret
  2171. GetPortDSR endp
  2172. ; FindCOMPort
  2173. ;
  2174. ; DS:SI -> DEB
  2175. ;
  2176. PUBLIC FindCOMPort
  2177. FindCOMPort proc near
  2178. ;
  2179. ; Examine BIOS data area to get base I/O addresses for COM and LPT ports
  2180. ;
  2181. push bx
  2182. push cx
  2183. push es
  2184. mov ax, __0040H
  2185. mov es, ax
  2186. assumes es,nothing
  2187. mov al, [si.DCB_Id]
  2188. mov ah, al
  2189. .erre MAXCOM LT 9 ;only single digit port numbers supported
  2190. add ah, '1'
  2191. mov [CommBaseX], ah
  2192. mov [CommIRQX], ah
  2193. mov [CommFIFOX], ah
  2194. mov [CommDSRx], ah
  2195. cmp al, 4
  2196. jae fcp_not_phys_com
  2197. xor ah, ah
  2198. shl ax, 1
  2199. mov bx, ax
  2200. mov ax, es:[bx+RS232B]
  2201. or ax, ax
  2202. jnz fcp_got_com_base
  2203. fcp_not_phys_com:
  2204. call GetComBase
  2205. or ax, ax
  2206. jnz fcp_got_com_base
  2207. mov bl, [si.DCB_Id]
  2208. cmp bl, 2
  2209. jne fcp_invalid ; jump, if base = 0 & com port <> com3
  2210. mov ax, 3E8h ; default COM3 to 3E8h
  2211. fcp_got_com_base:
  2212. push ax
  2213. call GetPortIRQ
  2214. mov dx, ax
  2215. pop ax
  2216. or dl, dl ;Q: non-zero IRQ?
  2217. jz fcp_invalid ; N:
  2218. cmp dl, 15 ;Q: IRQ in range?
  2219. ja fcp_invalid ; N:
  2220. xor dh, dh
  2221. push ax
  2222. push dx
  2223. call GetPortFIFO
  2224. call GetPortDSR
  2225. pop dx
  2226. pop ax
  2227. clc
  2228. fcp_exit:
  2229. pop es
  2230. pop cx
  2231. pop bx
  2232. ret
  2233. fcp_invalid:
  2234. or ax, -1
  2235. mov dx, ax
  2236. stc
  2237. jmp fcp_exit
  2238. FindCOMPort endp
  2239. .8086
  2240. page
  2241. ;--------------------------Private Routine-----------------------------;
  2242. ;
  2243. ; Rotate the PIC interrupt priorities so the communication ports are
  2244. ; highest priority.
  2245. ;
  2246. ; NOTE: Only rotates priorities on master PIC.
  2247. ;
  2248. ;-----------------------------------------------------------------------;
  2249. assumes ds,Data
  2250. assumes es,nothing
  2251. public Rotate_PIC
  2252. Rotate_PIC proc near
  2253. push ax
  2254. push cx
  2255. push di
  2256. mov al, 8 ; 0 - 7 rotated
  2257. mov cx, MAXCOM+1
  2258. mov di, DataOFFSET IRQhooks
  2259. rp_loop:
  2260. mov ah, [di.IRQn]
  2261. cmp ah, 0 ;End of hooked IRQ list?
  2262. je rp_set
  2263. cmp [di.VecN], 0FFh ;Hooked?
  2264. je rp_next
  2265. cmp ah, 8 ;If on slave PIC, treat as IRQ2
  2266. jb @f
  2267. mov ah, 2
  2268. @@:
  2269. cmp ah, al
  2270. jae rp_next
  2271. mov al, ah ;AL = lowest hooked comm IRQ
  2272. rp_next:
  2273. add di, SIZE IRQ_Hook_Struc
  2274. loop rp_loop
  2275. rp_set:
  2276. dec al ;Setting IRQ(n-1) as the lowest
  2277. and al, 07h ; priority makes IRQn the highest
  2278. or al, 0C0h
  2279. out INTA0, al
  2280. pop di
  2281. pop cx
  2282. pop ax
  2283. ret
  2284. Rotate_PIC endp
  2285. ifdef DEBUG
  2286. public InitCom10, InitCom20, InitCom40, InitCom50, InitCom59
  2287. public InitCom60, InitCom70, InitCom80, InitCom90, InitCom100
  2288. public TermCom10, TermCom15, TermCom20, TermCom30
  2289. public TermCom60, Terminate5, Terminate10, Terminate20, Terminate30
  2290. public Terminate45, Terminate49, Terminate50
  2291. public SetQue10
  2292. public SetCom5, SetCom10, SetCom20, SetCom210, SetCom220, SetCom230
  2293. public SetCom240, SetCom310, SetCom410, SetCom420, SetCom430
  2294. public SetCom440, SetCom450, SetCom460, SetCom470
  2295. public GetDEB10, GetDEB20, GetDEB30
  2296. public DCBPtr10
  2297. endif
  2298. sEnd code
  2299. page
  2300. createSeg _INIT,init,word,public,CODE
  2301. sBegin init
  2302. assumes cs,init
  2303. ;------------------------------------------------------------------------------
  2304. ;------------------------------------------------------------------------------
  2305. IBMmodel proc near
  2306. push ax
  2307. push bx
  2308. push es
  2309. mov ah, 0c0h
  2310. int 15h
  2311. jc IBMmodel_exit
  2312. assumes es,nothing
  2313. cmp by es:[bx+2], 0f8h ; PS/2 80
  2314. je IBMmodel_exit ; return carry clear
  2315. cmp by es:[bx+2], 0fch ; AT or PS/2 50 or 60
  2316. jne OldBios ; assume OldBios
  2317. cmp by es:[bx+3], 04h ; PS/2 50
  2318. je IBMmodel_exit ; return carry clear
  2319. cmp by es:[bx+3], 05h ; PS/2 60
  2320. je IBMmodel_exit ; return carry clear
  2321. OldBios:
  2322. stc
  2323. IBMmodel_exit:
  2324. pop es
  2325. pop bx
  2326. pop ax
  2327. ret
  2328. IBMmodel endp
  2329. cProc LoadLib, <FAR,PUBLIC,NODATA>,<si,di>
  2330. cBegin
  2331. push ds
  2332. mov ax, __F000H
  2333. mov ds, ax
  2334. assumes ds, ROMBios
  2335. mov al, [MachineID]
  2336. pop ds
  2337. assumes ds,Data
  2338. mov [$MachineID], al
  2339. call IBMmodel ;Q: PS/2?
  2340. jc @F ; N:
  2341. mov [default_table+2], 3 ; Y: change COM3 default IRQ to 3
  2342. @@:
  2343. push ds
  2344. mov ax, __0040H
  2345. mov ds, ax
  2346. assumes ds,nothing
  2347. cmp word ptr ds:[RS232B], 2F8h ;Q: COM2 base in COM1 slot?
  2348. pop ds
  2349. assumes ds,Data
  2350. jne @F ; N: leave IRQ default as 4
  2351. mov [default_table], 3 ; Y: change IRQ default to 3
  2352. @@:
  2353. mov [fVPICD], -1 ; assume no
  2354. xor di, di
  2355. mov es, di
  2356. mov ax, GET386API
  2357. mov bx, VPICD
  2358. int MULTIPLEX
  2359. mov wo [lpfnVPICD], di
  2360. mov wo [lpfnVPICD+2], es
  2361. mov ax, es
  2362. or ax, di
  2363. jz short no_VPICD ; jump if no bimodel services available
  2364. ;
  2365. ; version check VPICD
  2366. ;
  2367. mov ax, VPICD_API_Get_Ver
  2368. call [lpfnVPICD]
  2369. %OUT version check VPICD
  2370. mov [fVPICD], 1 ; flag services are available
  2371. IFDEF No_DOSX_Bimodal_Services
  2372. jmp short skip_dosx_stuff
  2373. no_VPICD:
  2374. mov ax, __WinFlags
  2375. and al, WF_PMODE or WF_WIN286
  2376. cmp al, WF_PMODE or WF_WIN286
  2377. jne skip_dosx_stuff
  2378. .286
  2379. mov ax, Int31_Get_Version SHL 8
  2380. int 31h
  2381. test bl, 10b ;Q: processor goes to real mode
  2382. ; for int reflection?
  2383. jz skip_dosx_stuff ; N:
  2384. mov [Using_DPMI], 0FFh ; Y: flag use of DPMI
  2385. mov ax, ds
  2386. cCall GetSelectorBase,<ax> ;DX:AX = segment of selector
  2387. shr ax, 4
  2388. shl dl, 4
  2389. or ah, dl ;AX now points to interrupt *segment*
  2390. push ax ;save on stack
  2391. mov ax, _INTERRUPT ;write data SEGMENT into _INTERRUPT
  2392. cCall AllocCStoDSAlias,<ax> ; code segment -- requires a data alias
  2393. mov es, ax
  2394. pop ax
  2395. mov es:[RM_IntDataSeg],ax
  2396. push ds
  2397. push es
  2398. mov ax, ds
  2399. mov es, ax
  2400. mov ax, _INTERRUPT
  2401. mov ds, ax
  2402. mov ax, (Int31_Trans_Serv SHL 8) + Trans_Call_Back
  2403. mov si, IntCodeOFFSET Entry_From_RM
  2404. mov di, DataOFFSET RM_Call_Struc
  2405. int 31h
  2406. pop es
  2407. pop ds
  2408. mov ax, 0
  2409. jnc @f
  2410. jmp short LoadExit
  2411. @@:
  2412. mov wo es:[RM_CallBack], dx
  2413. mov wo es:[RM_CallBack+2], cx
  2414. cCall FreeSelector,<es> ;don't need CS alias any longer
  2415. .8086
  2416. skip_dosx_stuff:
  2417. ELSE
  2418. no_VPICD:
  2419. ENDIF
  2420. ;
  2421. ; find base values for LPT ports
  2422. ;
  2423. mov cx, __0040h
  2424. mov es, cx
  2425. mov cx, MAXLPT+1
  2426. mov si, DataOFFSET LPT1
  2427. ll_initl_lp:
  2428. mov bx, [si.BIOSPortLoc]
  2429. or bx, bx
  2430. jz ll_not_phys_lpt
  2431. mov ax, es:[bx]
  2432. or ah, ah ;Q: lpt redirected, or 0?
  2433. jz ll_not_phys_lpt ; Y:
  2434. cmp bx, LPTB ;Q: first LPT?
  2435. je ll_got_lpt_base ; Y:
  2436. cmp ax, es:[bx-2] ;Q: base same as previous (redirected)?
  2437. jne ll_got_lpt_base ; N: must be real
  2438. ll_not_phys_lpt:
  2439. %OUT attempt to read base from SYSTEM.INI
  2440. ll_got_lpt_base:
  2441. mov [si.Port], ax
  2442. loop ll_initl_lp
  2443. ;
  2444. ; create system timer for signalling chars in receive buffer
  2445. ;
  2446. ifndef WOW
  2447. mov ax, 100 ; create 100msec timer
  2448. push ax
  2449. mov ax, _INTERRUPT
  2450. push ax
  2451. mov ax, IntCodeOFFSET TimerProc
  2452. push ax
  2453. call CreateSystemTimer ; ax = 0, if failed
  2454. %OUT should I display an error message here?
  2455. endif
  2456. assumes es,nothing
  2457. LoadExit:
  2458. cEnd
  2459. sEnd init
  2460. End LoadLib