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.

1614 lines
41 KiB

  1. title "Mouse detection"
  2. ;++
  3. ;
  4. ; Copyright (c) 1989 Microsoft Corporation
  5. ;
  6. ; Module Name:
  7. ;
  8. ; mouse.asm
  9. ;
  10. ; Abstract:
  11. ;
  12. ; This module implements the assembley code necessary to determine
  13. ; various mouse in the system.
  14. ;
  15. ; Author:
  16. ;
  17. ; Shie-Lin Tzong (shielint) 10-Dec-1991.
  18. ; Most of the code is taken from win31 setup code(with modification.)
  19. ;
  20. ; Environment:
  21. ;
  22. ; x86 Real Mode.
  23. ;
  24. ; Revision History:
  25. ;
  26. ;
  27. ;--
  28. .xlist
  29. include mouse.inc
  30. .list
  31. .386
  32. extrn _Empty8042:proc
  33. extrn Write8042:proc
  34. extrn ReadKeyboard:proc
  35. extrn _ComPortAddress:word
  36. extrn _DisableSerialMice:word
  37. extrn _FastDetect:byte
  38. _DATA SEGMENT PARA USE16 PUBLIC 'DATA'
  39. LATLSBSave db ?
  40. LATMSBSave db ?
  41. LCRSave db ?
  42. MCRSave db ?
  43. IERSave db ?
  44. fSingle8259 db 0
  45. DWFinalCount dw 2 dup (0)
  46. DWCurrCount dw 2 dup (0)
  47. NextComPort dw 0 ; Offset into ComPortAddress[]
  48. MouseInfo MouseInformation <0, 0, 0FFFFh, 0FFFFh, 0>
  49. ;
  50. ; MouseDetected is used to indicate if any mouse has been detected.
  51. ;
  52. MouseDetected dw 0 ; initialize to no
  53. InPortIoBase dw 0 ; The Base addr for inport mouse
  54. _DATA ends
  55. _TEXT SEGMENT PARA USE16 PUBLIC 'CODE'
  56. ASSUME CS: _TEXT, DS:_DATA, SS:NOTHING
  57. ;++
  58. ;
  59. ; USHORT
  60. ; LookForPS2Mouse (
  61. ; VOID
  62. ; )
  63. ;
  64. ; Routine Description:
  65. ;
  66. ; This function determines mouse type in the system.
  67. ;
  68. ; Arguments:
  69. ;
  70. ; None.
  71. ;
  72. ; Return Value:
  73. ;
  74. ; (eax): mouse Id.
  75. ;
  76. ;--
  77. public _LookForPS2Mouse
  78. _LookForPS2Mouse proc near
  79. push bx
  80. push si
  81. push di
  82. mov si, offset MouseInfo
  83. lea si, [si].DeviceId
  84. call _Empty8042
  85. int 11h
  86. test ax, 4 ; is bit 2 set?
  87. jz No_PS2_Mouse ; No, no PS/2 mouse.
  88. xor di, di
  89. ;
  90. ; Shortcut the rest of the detection and mouse reset if fast detect is set.
  91. ;
  92. cmp _FastDetect, 0
  93. jne short Is_PS2_Mouse
  94. ;
  95. ; Old Olivetti M400-60 and M400-40 will have trouble reading floppy
  96. ; and hard disk if the following call is made .
  97. ;
  98. mov ax, 0c201h ; reset PS/2 mouse
  99. int 15h
  100. jc short No_PS2_Mouse
  101. jmp short Is_PS2_Mouse
  102. mov bh, 03 ; Packet size = 3 bytes
  103. mov ax, 0c205h ; init point device interface
  104. int 15h
  105. jc short No_PS2_Mouse
  106. mov ax, 0c201h ; reset PS/2 mouse
  107. int 15h
  108. jc short No_PS2_Mouse
  109. call _Empty8042
  110. ;
  111. ; The following sequence of Int 15h calls will determine if a Logitech
  112. ; PS/2 mouse is present. This information was obtained from Logitech.
  113. ;
  114. mov ax,0C203h ; Set resolution to 1 cnt/mm
  115. mov bh,0h
  116. int 15h
  117. jc Is_PS2_Mouse
  118. mov ax,0C206h ; Set scaling to 1:1
  119. mov bh,1h
  120. int 15h
  121. jc Is_PS2_Mouse
  122. mov ax,0C206h ; Set scaling to 1:1
  123. mov bh,1h
  124. int 15h
  125. jc Is_PS2_Mouse
  126. mov ax,0C206h ; Set scaling to 1:1
  127. mov bh,1h
  128. int 15h
  129. jc Is_PS2_Mouse
  130. mov ax,0C206h ; Get status
  131. mov bh,0h
  132. int 15h
  133. jc Is_PS2_Mouse
  134. or cl,cl ; Is resolution 1 cnt/mm?
  135. jz Is_PS2_Mouse ; Yes, then not a Logitech.
  136. ;
  137. ; If cl is not zero (i.e. 1 cnt/mm) then it is the number of buttons
  138. ; and we've found a Logitech 3-button PS/2 mouse
  139. ;
  140. LT_PS2_Mouse:
  141. mov ax,LT_MOUSE + PS2_MOUSE
  142. jmp short PS2MouseFound
  143. Is_PS2_Mouse:
  144. mov ax,MS_MOUSE + PS2_MOUSE
  145. jmp short PS2MouseFound
  146. No_PS2_Mouse:
  147. mov bx, 0
  148. jmp ExitPs2Mouse
  149. PS2MouseFound:
  150. ;
  151. ; Set mouse type and subtype to mouse info structure
  152. ;
  153. mov bx, offset MouseInfo
  154. mov [bx].MouseSubtype, al
  155. mov [bx].MouseType, ah
  156. mov [bx].MouseIrq, 12
  157. mov [bx].MousePort, 0ffffh
  158. mov [bx].DeviceIdLength, di
  159. mov MouseDetected, bx
  160. ExitPs2Mouse:
  161. ;
  162. ; Drain 8042 input buffer and leave leave pointing device disabled.
  163. ; We don't want user moves the mouse and hangs the system.
  164. ;
  165. call _Empty8042
  166. mov ax, bx
  167. pop di
  168. pop si
  169. pop bx
  170. ret
  171. _LookForPS2Mouse endp
  172. ;++
  173. ;
  174. ; USHORT
  175. ; LookForInportMouse (
  176. ; VOID
  177. ; )
  178. ;
  179. ; Routine Description:
  180. ;
  181. ; This function determines mouse type in the system.
  182. ;
  183. ; Arguments:
  184. ;
  185. ; None.
  186. ;
  187. ; Return Value:
  188. ;
  189. ; (eax): mouse Id.
  190. ;
  191. ;--
  192. public _LookForInportMouse
  193. _LookForInportMouse proc near
  194. push bx
  195. mov dx,INPORT_FIRST_PORT + 2 ; Get address of ID register.
  196. inport_try_again:
  197. call TestForInport ; Does an InPort exist at this address?
  198. jnc inport_found ; No carry ! Inport found !
  199. sub dx,4 ; Nope, try the next possible port.
  200. cmp dx,INPORT_LAST_PORT + 2
  201. jae inport_try_again
  202. mov ax, 0 ; Fail to detect inport mouse
  203. jmp short no_inport
  204. inport_found:
  205. ;
  206. ; Set mouse type and subtype to mouse info structure
  207. ;
  208. mov ax,MS_MOUSE + INPORT_MOUSE
  209. mov cx, dx
  210. sub cx, 2
  211. mov bx, offset MouseInfo
  212. mov [bx].DeviceIdLength, 0
  213. mov [bx].MouseSubtype, al
  214. mov [bx].MouseType, ah
  215. mov [bx].MousePort, cx
  216. mov InportIoBase, cx
  217. mov MouseDetected, bx
  218. lea ax, [bx].MouseIrq
  219. push ax
  220. push cx ; Current Port
  221. call _InportMouseIrqDetection
  222. add sp, 4
  223. mov ax, offset MouseInfo
  224. no_inport:
  225. pop bx
  226. ret
  227. _LookForInportMouse endp
  228. ;++
  229. ;
  230. ; USHORT
  231. ; LookForBusMouse (
  232. ; VOID
  233. ; )
  234. ;
  235. ; Routine Description:
  236. ;
  237. ; This procedure will attempt to find a bus mouse adaptor in the system
  238. ; and will return the results of this search.
  239. ;
  240. ; Arguments:
  241. ;
  242. ; None.
  243. ;
  244. ; Return Value:
  245. ;
  246. ; (ax) = Mouse ID.
  247. ;
  248. ;--
  249. public _LookForBusMouse
  250. _LookForBusMouse proc near
  251. ;
  252. ; If We already found Inport mouse and its IO base is 23ch, it is
  253. ; impossible to have a BUS mouse.
  254. ;
  255. cmp InportIoBase, BUS_MOUSE_BASE
  256. jne short @f
  257. mov ax, 0
  258. ret
  259. @@:
  260. push bx
  261. ;
  262. ; We determine if the bus mouse adaptor is present by attempting to
  263. ; program the 8255A, and then seeing if we can write a value out to
  264. ; Port B on the 8255A and get that value back. If we can, we assume
  265. ; that we have a bus mouse adaptor.
  266. ;
  267. mov dx,BUS_INIT ; Get address of 8255A control port.
  268. mov al,BUS_INIT_VALUE ; Get proper value.
  269. DelayOut ; Set up 8255A.
  270. mov ax,0A5A5h ; Get a signature byte.
  271. address BUS_SIG BUS_INIT ; Get address of Port B.
  272. DelayOut ; Set Port B with signature.
  273. DelayIn ; Read back Port B.
  274. cmp al,ah ; Does it match signature byte?
  275. jne No_Bus_Mouse ; Nope - no bus mouse adaptor
  276. mov ax,MS_MOUSE + BUS_MOUSE
  277. jmp short Bus_Mouse_Found
  278. No_Bus_Mouse:
  279. mov ax, 0 ; No Bus Mouse detected
  280. jmp short Bus_Exit
  281. Bus_Mouse_Found:
  282. ;
  283. ; Set mouse type and subtype to mouse info structure
  284. ;
  285. mov dx, BUS_MOUSE_BASE
  286. mov bx, offset MouseInfo
  287. mov [bx].DeviceIdLength, 0
  288. mov [bx].MouseSubtype, al
  289. mov [bx].MouseType, ah
  290. mov [bx].MousePort, dx
  291. mov MouseDetected, bx
  292. call BusMouseIrqDetection
  293. mov [bx].MouseIrq, ax ; if (ax) = 0xffff, no irq detected
  294. mov ax, offset MouseInfo ; return MouseInfor
  295. Bus_Exit:
  296. pop bx
  297. ret
  298. _LookForBusMouse endp
  299. ;++
  300. ;
  301. ; USHORT
  302. ; BusMouseIrqDetection (
  303. ; USHORT Port
  304. ; )
  305. ;
  306. ; Routine Description:
  307. ;
  308. ; This procedure will attempt to find the irq level associated with the
  309. ; Bus mouse in the machine.
  310. ;
  311. ; Arguments:
  312. ;
  313. ; (dx) = Bus mouse base I/O port.
  314. ;
  315. ; Return Value:
  316. ;
  317. ; (ax) = Irq level. if (ax)= 0xffff, detection failed.
  318. ;
  319. ;--
  320. BusMouseIrqDetection proc near
  321. push bx
  322. add dx, 2 ; use adaptor control port
  323. in al,dx ; Get irq 2-5 states
  324. IOdelay
  325. mov ah,al ; Save states
  326. mov cx,10000 ; Set loop count
  327. xor bh,bh ; Clear changes buffer
  328. @@:
  329. in al,dx ; Get current states of irq 2-5
  330. IOdelay
  331. xor ah,al ; Compare with last state
  332. or bh,ah ; Mark any changes
  333. mov ah,al ; Previous := current state
  334. loop @B ; Keep looking
  335. mov ax, 0ffffh
  336. or bh,bh ; Any irq found?
  337. jz short BusIntExit ; Branch if no interrupt was found
  338. BusIntFound:
  339. mov ax,5 ; Assume irq5
  340. test bh,0001b ; Is it off?
  341. jnz short BusIntExit ; Yes..have irq5
  342. mov ax,2 ; Assume irq2
  343. test bh,1000b
  344. jnz short BusIntExit
  345. inc ax ; Try irq3
  346. test bh,0100b
  347. jnz short BusIntExit
  348. inc ax ; Must be irq4
  349. BusIntExit: ; ax contains the IRQ number
  350. pop bx
  351. ret
  352. BusMouseIrqDetection endp
  353. ;++
  354. ;
  355. ; USHORT
  356. ; LookForSerialMouse (
  357. ; VOID
  358. ; )
  359. ;
  360. ; Routine Description:
  361. ;
  362. ; This procedure will attempt to find a serial mouse adaptor in the system
  363. ; and will return the results of this search.
  364. ;
  365. ; Arguments:
  366. ;
  367. ; None.
  368. ;
  369. ; Return Value:
  370. ;
  371. ; (ax) = Mouse ID.
  372. ;
  373. ;--
  374. public _LookForSerialMouse
  375. _LookForSerialMouse proc near
  376. push di
  377. push bx
  378. mov di, NextComPort ; Get untested comport
  379. cmp di, 8 ; Have we over the comport limit?
  380. jae short No_Serial_Mouse ; if above or e, yes, exit
  381. serial_try_again:
  382. mov cx, di
  383. mov al, 1
  384. shr cx, 1
  385. inc cx
  386. shl ax, cl
  387. test _DisableSerialMice, ax ; Should we skip this com port?
  388. jnz short serial_next_port ; yes, try next one.
  389. mov dx, _ComPortAddress[di] ; Get base address of COM port to test.
  390. or dx,dx ; Does this port exist?
  391. jz serial_next_port ; No, try next one.
  392. serial_test_port:
  393. ;
  394. ; The comport address is initialized by com detection routine. if the port
  395. ; value is not zero, it means that the port exist.
  396. ;
  397. call TestForSerial ; Is a serial mouse attached to port?
  398. cmp ax,NO_MOUSE
  399. jne Serial_Mouse_Found ; Yes! found a serial mouse
  400. serial_next_port: ; No serial mouse on this COM port.
  401. add di,2 ; move to the next possible port
  402. cmp di,8 ; Are we over com limit?
  403. jb serial_try_again ; if b, no, go test it.
  404. mov NextComport, di
  405. No_Serial_Mouse:
  406. mov ax, 0 ; No serial mouse detected
  407. jmp short SerialMouseExit
  408. Serial_Mouse_Found:
  409. mov NextComport, di
  410. add NextComport, 2 ; Next comport to test
  411. shr di, 1 ; divide di by 2
  412. ;
  413. ; Set mouse type and subtype to mouse info structure
  414. ;
  415. mov bx, offset MouseInfo
  416. mov [bx].DeviceIdLength, 0
  417. cmp ax, MS_MOUSE + SERIAL_MOUSE_WITH_WHEEL
  418. jnz short @f
  419. mov [bx].DeviceIdLength, 7
  420. @@:
  421. mov [bx].MouseSubtype, al
  422. mov [bx].MouseType, ah
  423. mov [bx].MousePort, di
  424. mov [bx].MouseIrq, 0ffffh
  425. mov MouseDetected, bx
  426. mov ax, bx
  427. SerialMouseExit:
  428. pop bx
  429. pop di
  430. ret
  431. _LookForSerialMouse endp
  432. ;++
  433. ;
  434. ; BOOLEAN
  435. ; TestForInport (
  436. ; USHORT Port
  437. ; )
  438. ;
  439. ; Routine Description:
  440. ;
  441. ; This procedure will attempt to find an InPort mouse at the given base
  442. ; I/O address. Note that if an InPort is found, it will be left
  443. ; in a state where it will not be generating any interrupts.
  444. ;
  445. ; Arguments:
  446. ;
  447. ; Port (DX) - I/O address of Inport identification register.
  448. ;
  449. ; Return Value:
  450. ;
  451. ; NC - An Inport was found
  452. ; CY - No Inport was found
  453. ;
  454. ;--
  455. TestForInport PROC NEAR
  456. push bx
  457. push si
  458. ;
  459. ; Since the identification register alternates between returning back
  460. ; the Inport chip signature and the version/revision, if we have an
  461. ; InPort chip, the chip signature will be read in one of the following
  462. ; two reads. If it isn't, we do not have an InPort chip.
  463. ;
  464. mov bl,INPORT_ID
  465. in al,dx ; Read ID register.
  466. cmp al,bl ; Is value the InPort chip signature?
  467. je possible_inport ; Yes, go make sure we have an InPort.
  468. in al,dx ; Read ID register again.
  469. cmp al,bl ; Is value the InPort chip signature?
  470. jne inport_not_found ; No, return error
  471. ;
  472. ; At this point, we managed to read the InPort chip signature, so we have
  473. ; a possible InPort chip. The next read from the ID register will
  474. ; return the version/revision. We then make sure that the ID register
  475. ; alternates between the chip signature and this version/revision. If
  476. ; it does, we have an InPort chip.
  477. ;
  478. possible_inport:
  479. in al,dx ; Read version/revision.
  480. mov ah,al ; Save it.
  481. mov cx,5 ; Test ID register 5 times.
  482. inport_check:
  483. in al,dx ; Read ID register.
  484. cmp al,bl ; Make sure it is the chip signature.
  485. jne inport_not_found ; If not, we don't have an InPort chip.
  486. in al,dx ; Read ID register.
  487. cmp al,ah ; Make sure version/revision is same.
  488. jne inport_not_found ; If not, we don't have an InPort chip.
  489. loop inport_check ; Test desired number of times.
  490. clc
  491. pop si
  492. pop bx
  493. ret
  494. ;
  495. ; At this point, we know we have an InPort chip.
  496. ;
  497. inport_not_found: ; We don't have an InPort chip.
  498. stc ; Show failure.
  499. pop si
  500. pop bx
  501. ret ; Return to caller.
  502. TestForInport ENDP
  503. ;++
  504. ;
  505. ; BOOLEAN
  506. ; TestForSerial (
  507. ; USHORT Port
  508. ; )
  509. ;
  510. ; Routine Description:
  511. ;
  512. ; This procedure will attempt to find a serial mouse adaptor in the system
  513. ; and will return the results of this search.
  514. ;
  515. ; Arguments:
  516. ;
  517. ; (dx) = Port Address.
  518. ;
  519. ; Return Value:
  520. ;
  521. ; (ax) = Mouse ID.
  522. ;
  523. ;--
  524. TestForSerial PROC NEAR
  525. call SaveCOMSetting
  526. call SetupCOMForMouse ; Set up COM port to talk to mouse.
  527. mov cx,SHORTDELAY ; Use a short delay time.
  528. call ResetSerialMouse ; Reset mouse to see if it is there.
  529. cmp ax,NO_MOUSE
  530. jne TFS_Found
  531. ;
  532. ; If a mouse has been detected, most likely there won't be second mouse.
  533. ; so we don't test for LONGDELAY to save some time
  534. ;
  535. cmp MouseDetected, 0
  536. jne short @f
  537. mov cx,LONGDELAY ; Maybe the mouse is just slow.
  538. call ResetSerialMouse ; Reset mouse to see if it is there.
  539. cmp ax,NO_MOUSE
  540. jne TFS_Found
  541. @@:
  542. call TestForLogitechSerial ; Maybe it's a Logitech Series C
  543. TFS_Found:
  544. push ax ; Save return value
  545. call RestoreCOMSetting
  546. pop ax
  547. ret
  548. TestForSerial ENDP
  549. ;++
  550. ;
  551. ; VOID
  552. ; SaveCOMSetting (
  553. ; USHORT Port
  554. ; )
  555. ;
  556. ; Routine Description:
  557. ;
  558. ; This procedure will save the current state of the COM port given.
  559. ;
  560. ; Arguments:
  561. ;
  562. ; Port (DX) - Base address of COM port.
  563. ;
  564. ; Return Value:
  565. ;
  566. ; None.
  567. ;
  568. ;--
  569. SaveCOMSetting PROC NEAR
  570. push dx ; Save base I/O address.
  571. address LCR RXB ; Get address of Line Control Register.
  572. DelayIn ; Get current contents.
  573. mov [LCRSave],al ; Save them.
  574. or al,LC_DLAB ; Set up to access divisor latches.
  575. DelayOut
  576. address LATMSB LCR ; Get address of high word of divisor
  577. DelayIn ; latch and save its current contents.
  578. mov [LATMSBSave],al
  579. address LATLSB LATMSB ; Get address of low word of divisor
  580. DelayIn ; latch and save its current contents.
  581. mov [LATLSBSave],al
  582. address LCR LATLSB ; Get address of Line Control Register
  583. mov al,[LCRSave] ; and disable access to divisor.
  584. and al,NOT LC_DLAB
  585. DelayOut
  586. address MCR LCR ; Get address of Modem Control Register
  587. DelayIn ; and save its current contents.
  588. mov [MCRSave],al
  589. address IER MCR ; Get address of Interrupt Enable Reg-
  590. DelayIn ; ister and save its current contents.
  591. mov [IERSave],al
  592. pop dx ; Restore base I/O address.
  593. ret
  594. SaveCOMSetting ENDP
  595. ;++
  596. ;
  597. ; VOID
  598. ; RestoreCOMSetting (
  599. ; USHORT Port
  600. ; )
  601. ;
  602. ; Routine Description:
  603. ;
  604. ; This procedure will restore the current state of the COM port given.
  605. ;
  606. ; Arguments:
  607. ;
  608. ; Port (DX) - Base address of COM port.
  609. ;
  610. ; Return Value:
  611. ;
  612. ; None.
  613. ;
  614. ;--
  615. RestoreCOMSetting PROC NEAR
  616. push dx ; Save base I/O address.
  617. address LCR RXB ; Get address of Line Control Register.
  618. mov al,LC_DLAB ; Set up to access divisor latches.
  619. DelayOut
  620. address LATMSB LCR ; Get address of high word of divisor
  621. mov al,[LATMSBSave] ; and restore it.
  622. DelayOut
  623. address LATLSB LATMSB ; Get address of low word of divisor
  624. mov al,[LATLSBSave] ; and restore it.
  625. DelayOut
  626. address LCR LATLSB ; Get address of Line Control Register
  627. mov al,[LCRSave] ; and restore it, disabling access to
  628. and al,NOT LC_DLAB ; the divisor latches.
  629. DelayOut
  630. address MCR LCR ; Get addres of Modem Control Register
  631. mov al,[MCRSave] ; and restore it.
  632. DelayOut
  633. address IER MCR ; Get address of Interrupt Enable Reg-
  634. mov al,[IERSave] ; ister and restore it.
  635. DelayOut
  636. pop dx ; Restore base I/O address.
  637. ret
  638. RestoreCOMSetting ENDP
  639. ;++
  640. ;
  641. ; VOID
  642. ; SetupCOMForMouse (
  643. ; USHORT Port
  644. ; )
  645. ;
  646. ; Routine Description:
  647. ;
  648. ; This procedure will set up the given COM port so that it can talk to
  649. ; a serial mouse.
  650. ;
  651. ; Arguments:
  652. ;
  653. ; Port (DX) - Base address of COM port to set up.
  654. ;
  655. ; Return Value:
  656. ;
  657. ; COM port set up, all interrupts disabled at COM port
  658. ;
  659. ;--
  660. SetupCOMForMouse PROC NEAR
  661. push dx ; Save base I/O address.
  662. mov cx, 60h
  663. call SetBaudRate
  664. address LCR RXB
  665. mov al,LC_BITS7 + LC_STOP1 + LC_PNONE
  666. DelayOut ; Set 7,n,1; disable access to divisor.
  667. address IER LCR ; Get address of Int. Enable Register
  668. xor al,al ; Disable all interrupts at the COM
  669. DelayOut ; port level.
  670. address LSR IER ; Get address of Line Status Reg.
  671. DelayIn ; Read it to clear any errors.
  672. pop dx ; Restore base I/O address
  673. ret
  674. SetupCOMForMouse ENDP
  675. ;++
  676. ;
  677. ; USHORT
  678. ; ResetSerialMouse (
  679. ; USHORT Port,
  680. ; USHORT Delay
  681. ; )
  682. ;
  683. ; Routine Description:
  684. ;
  685. ; This procedure will reset a serial mouse on the given COM port and will
  686. ; return an indication of whether a mouse responded or not.
  687. ;
  688. ; The function now also checks for the presence of a 'B' as well as an
  689. ; 'M' to determine the presence of a pointing device. Also, if the 'M' is
  690. ; followed by a '3' the serial mouse is a Logitech.
  691. ;
  692. ; Mouse returns M
  693. ; Ballpoint returns B
  694. ;
  695. ; Arguments:
  696. ;
  697. ; Port (DX) - Base I/O address of COM port to use
  698. ; Delay (CX) - Number of msecs to use for delays
  699. ;
  700. ; Return Value:
  701. ;
  702. ; (ax) = Mouse Type.
  703. ;
  704. ;--
  705. ResetSerialMouse PROC NEAR
  706. push dx ; Save environment.
  707. push si
  708. push di
  709. push es
  710. address IER RXB ; Get address of Interrupt Enable Reg.
  711. DelayIn ; Get current contents of IER and
  712. push ax ; save them.
  713. push dx ; Save address of IER.
  714. xor al,al ; Disable all interrupts at the
  715. DelayOut ; COM port level.
  716. address MCR IER ; Get address of Modem Control Reg.
  717. mov al,MC_DTR ; Set DTR active; RTS, OUT1, and OUT2
  718. DelayOut ; inactive. This powers down mouse.
  719. push cx ; Save amount of time to delay.
  720. call SetupForWait ; Set up BX:CX and ES:DI properly for
  721. assume es:nothing ; upcoming delay loop.
  722. address RXB MCR ; Get address of Receive Buffer.
  723. ;
  724. ; Now, we wait the specified amount of time, throwing away any stray
  725. ; data that we receive. This gives the mouse time to properly reset
  726. ; itself.
  727. ;
  728. rsm_waitloop:
  729. in al, dx ; Read and ignore any stray data.
  730. call IsWaitOver ; Determine if we've delayed enough.
  731. jnc rsm_waitloop ; If not, keep waiting.
  732. ;
  733. ; Wait is over.
  734. ;
  735. address LSR RXB ; Get address of Line Status Reg.
  736. DelayIn ; Read it to clear any errors.
  737. address MCR LSR ; Get address of Modem COntrol Reg.
  738. mov al,MC_DTR+MC_RTS ; Set DTR, RTS, and OUT2 active
  739. ; OUT1 inactive.
  740. DelayOut ; This powers up the mouse.
  741. pop cx ; Get amount of time to delay.
  742. call SetupForWait ; Set up BX:CX and ES:DI properly for
  743. assume es:nothing ; the upcoming delay loop.
  744. ;
  745. ; We give the mouse the specified amount of time to respond by sending
  746. ; us an M. If it doesn't, or we get more than 5 characters that aren't
  747. ; an M, we return a failure indication.
  748. ;
  749. address LSR MCR ; Get address of Line Status Reg.
  750. mov si, 5 ; Read up to 5 chars from port.
  751. mov bl,'3' ; '3' will follow 'M' on Logitech.
  752. mov bh,'B' ; 'B' for BALLPOINT
  753. mov ah,'M' ; Get an M. (We avoid doing a cmp al,M
  754. ; because the M could be left floating
  755. ; due to capacitance.)
  756. rsm_getchar:
  757. DelayIn ; Get current status.
  758. test al,LS_DR ; Is there a character in Receive Buff?
  759. jnz rsm_gotchar ; Yes! Go and read it.
  760. call IsWaitOver ; No, determine if we've timed out.
  761. jnc rsm_getchar ; Haven't timed out; keep looking.
  762. mov bx,NO_MOUSE
  763. jmp rsm_leave ; Timed out. Leave with NO_MOUSE.
  764. rsm_gotchar:
  765. address RXB LSR ; Get address of Receive Buffer.
  766. DelayIn ; Get character that was sent to us.
  767. cmp al,ah ; Is it an M?
  768. jne check_for_b
  769. ;
  770. ; We received an 'M', now wait for next character to see if it is a '3'.
  771. ;
  772. mov cx,1 ; Wait between 55.5 and 111ms for
  773. call SetupForWait ; next character.
  774. address LSR RXB
  775. rsm_waitfor3:
  776. DelayIn ; Get current status.
  777. test al,LS_DR ; Is there a character in Receive Buff?
  778. jnz rsm_gotchar3 ; Yes! Go and read it.
  779. call IsWaitOver ; No, determine if we've timed out.
  780. jnc rsm_waitfor3 ; Haven't timed out; keep looking.
  781. ;
  782. ; Not a Logitech - must be a standard Microsoft compatible serial mouse.
  783. ;
  784. jmp rsm_notLT
  785. rsm_gotchar3:
  786. address RXB LSR ; Get address of Receive Buffer.
  787. DelayIn ; Get character that was sent to us.
  788. cmp al,bl ; Is it a 3?
  789. jne short rsm_check_for_z
  790. mov bx,LT_MOUSE + SERIAL_MOUSE ; Yes, we've found a Logitech M+
  791. jmp rsm_leave ; series, 3 button mouse
  792. rsm_check_for_z:
  793. ;
  794. ; Determine if this is Microsoft mouse with wheel.
  795. ; 'M', 'Z', 0x40, 0x00, 0x00, 0x00, PnP String
  796. ;
  797. cmp al, 'Z'
  798. jnz rsm_notLT
  799. ;
  800. ; Check for 0x40, 0x00, 0x00, 0x00
  801. ;
  802. mov ebx, 040h
  803. mov cx, 4
  804. address LSR RXB
  805. rsm_get_byte:
  806. push cx
  807. mov cx,1 ; Wait between 55.5 and 111ms for
  808. call SetupForWait ; next character.
  809. @@:
  810. DelayIn ; Get current status.
  811. test al,LS_DR ; Is there a character in Receive Buff?
  812. jnz short @f ; Yes! Go and read it.
  813. call IsWaitOver ; No, determine if we've timed out.
  814. jnc short @b ; Haven't timed out; keep looking.
  815. jmp rsm_notMZ
  816. @@:
  817. address RXB LSR ; Get address of Receive Buffer.
  818. DelayIn ; Get character that was sent to us.
  819. cmp al,bl ; Is it a MS wheel?
  820. jnz rsm_notMZ
  821. shr ebx, 8
  822. address LSR RXB
  823. pop cx
  824. sub cx, 1
  825. jnz rsm_get_byte
  826. ;
  827. ; Next read PnP string for the MS wheel mouse
  828. ; First skip 3 bytes: 08 + 2-byte Rev number
  829. ;
  830. mov cx, 3
  831. rsm_get_byte1:
  832. push cx
  833. mov cx,1 ; Wait between 55.5 and 111ms for
  834. call SetupForWait ; next character.
  835. @@:
  836. DelayIn ; Get current status.
  837. test al,LS_DR ; Is there a character in Receive Buff?
  838. jnz short @f ; Yes! Go and read it.
  839. call IsWaitOver ; No, determine if we've timed out.
  840. jnc short @b ; Haven't timed out; keep looking.
  841. jmp rsm_notMZ
  842. @@:
  843. address RXB LSR ; Get address of Receive Buffer.
  844. DelayIn ; Get character that was sent to us.
  845. address LSR RXB
  846. pop cx
  847. sub cx, 1
  848. jnz rsm_get_byte1
  849. ;
  850. ; Next read 7 bytes PnpDevice id
  851. mov si, offset MouseInfo
  852. lea si, [si].DeviceId
  853. mov cx, 7
  854. rsm_get_byte2:
  855. push cx
  856. mov cx,1 ; Wait between 55.5 and 111ms for
  857. call SetupForWait ; next character.
  858. @@:
  859. DelayIn ; Get current status.
  860. test al,LS_DR ; Is there a character in Receive Buff?
  861. jnz short @f ; Yes! Go and read it.
  862. call IsWaitOver ; No, determine if we've timed out.
  863. jnc short @b ; Haven't timed out; keep looking.
  864. jmp rsm_notMZ
  865. @@:
  866. address RXB LSR ; Get address of Receive Buffer.
  867. DelayIn ; Get character that was sent to us.
  868. mov [si], al
  869. inc si
  870. address LSR RXB
  871. pop cx
  872. sub cx, 1
  873. jnz rsm_get_byte2
  874. mov byte ptr [si], 0 ; add device id terminated null
  875. mov bx, MS_MOUSE + SERIAL_MOUSE_WITH_WHEEL
  876. jmp short rsm_leave ; We still have a standard serial mouse.
  877. rsm_notMZ:
  878. pop cx
  879. rsm_notLT:
  880. mov bx,MS_MOUSE + SERIAL_MOUSE ; We didn't get the '3' after the 'M'
  881. jmp short rsm_leave ; We still have a standard serial mouse.
  882. check_for_b:
  883. cmp al,bh ; Is it a B?
  884. jne rsm_next_char
  885. mov bx,MS_BALLPOINT + SERIAL_MOUSE ; We've found a BallPoint Mouse
  886. jmp short rsm_leave
  887. rsm_next_char:
  888. address LSR RXB ; Oh well. Get address of LSR again.
  889. dec si ; Have we read 5 chars yet?
  890. jnz rsm_getchar ; Nope, we'll give him another try.
  891. ;
  892. ; We've read many characters - No a single 'M' or 'B' in the lot.
  893. ;
  894. mov bx,NO_MOUSE
  895. rsm_leave:
  896. pop dx ; Get address of IER.
  897. pop ax ; Get old value of IER.
  898. DelayOut ; Restore IER.
  899. pop es ; Restore environment.
  900. assume es:nothing
  901. pop di
  902. pop si
  903. pop dx
  904. mov ax,bx ; Set return value.
  905. ret
  906. ResetSerialMouse ENDP
  907. ;++
  908. ;
  909. ; VOID
  910. ; SetupForWait (
  911. ; USHORT WaitTime
  912. ; )
  913. ;
  914. ; Routine Description:
  915. ;
  916. ; This procedure accepts the number of milliseconds that we will want
  917. ; to delay for and will set things up for the wait.
  918. ;
  919. ; Arguments:
  920. ;
  921. ; (CX) = Number of clock ticks to wait for.
  922. ;
  923. ; Return Value:
  924. ;
  925. ; None.
  926. ;
  927. ;--
  928. SetupForWait PROC NEAR
  929. push ax ; Do your saving !
  930. push es
  931. xor ax,ax
  932. mov es,ax ; Point to 40:6C = 0:46C
  933. cli
  934. mov ax,es:[LW_ClockTickCount+2]
  935. mov [DWFinalCount+2],ax ; Save ending time (HiWord)
  936. mov ax,es:[LW_ClockTickCount] ; Get tick count in AX.
  937. sti
  938. add ax,cx ; [Current + delay] = delay ends.
  939. mov [DWFinalCount],ax ; Save ending time (LoWord)
  940. jnc SFW_End
  941. inc [DWFinalCount+2]
  942. SFW_End:
  943. pop es ; Restore now !
  944. pop ax
  945. ret
  946. SetupForWait ENDP
  947. ;++
  948. ;
  949. ; BOOLEAN
  950. ; IsWaitOver (
  951. ; VOID
  952. ; )
  953. ;
  954. ; Routine Description:
  955. ;
  956. ; This procedure accepts the current time and the ending time and
  957. ; return and indication of whether the current time is past
  958. ; the ending time.
  959. ;
  960. ; Arguments:
  961. ;
  962. ; None.
  963. ;
  964. ; Return Value:
  965. ;
  966. ; carry clear Current time is not past ending time
  967. ; carry set Current time is past ending time
  968. ;
  969. ;--
  970. IsWaitOver PROC NEAR
  971. if 0
  972. push ax ; Preserve AX
  973. push es ; Preserve ES
  974. xor ax,ax
  975. mov es,ax ; Point to 40:6C = 0:46C
  976. cli
  977. mov ax,es:[LW_ClockTickCount]
  978. mov [DWCurrCount],ax ; Save current time (LoWord)
  979. mov ax,es:[LW_ClockTickCount+2] ; Get tick count in AX.
  980. sti
  981. cmp [DWFinalCount+2],ax ; Compare HiWords
  982. ja WaitNotOver ; Carry will be clear if wait
  983. ; is not over.
  984. mov ax,es:[LW_ClockTickCount] ; Compare Lowords
  985. cmp [DWFinalCount],ax ; This will set CY accordingly
  986. WaitNotOver:
  987. pop es ; Restore ES
  988. pop ax ; Restore AX
  989. ret
  990. else
  991. push ax ; Preserve AX
  992. push es ; Preserve ES
  993. xor ax,ax
  994. mov es,ax ; Point to 40:6C = 0:46C
  995. cli
  996. mov ax,es:[LW_ClockTickCount]
  997. mov [DWCurrCount],ax ; Save current time (LoWord)
  998. mov ax,es:[LW_ClockTickCount+2] ; Get tick count in AX.
  999. sti
  1000. cmp [DWFinalCount+2],ax ; Compare HiWords
  1001. jb WaitExit ; Time is up
  1002. jne WaitRollCheck ; If not equal check for
  1003. WaitLowCheck:
  1004. mov ax,[DWCurrCount] ; Compare Lowords
  1005. cmp [DWFinalCount],ax ; This will set CY accordingly
  1006. WaitExit:
  1007. pop es ; Restore ES
  1008. pop ax ; Restore AX
  1009. ret
  1010. WaitRollCheck:
  1011. ; If the current time is less than the wait time we must check for
  1012. ; roll over. There are 18.2 * 60 * 60 * 24 or 0x1800b0 clock ticks in
  1013. ; a day. At midnight the counter rolls over to zero.
  1014. cmp ax,0
  1015. jne WaitExit ; If current HiWord is not 0,
  1016. ; no roll over. Exit with
  1017. ; carry clear.
  1018. cmp [DWFinalCount+2],18h ; Is Final HiWord 0x18
  1019. je short @f ; Yes, check LoWord for wrap.
  1020. clc ; No, no roll over. Exit with
  1021. ; carry clear.
  1022. jmp WaitExit
  1023. @@:
  1024. mov ax,[DWFinalCount] ; Get final LoWord
  1025. sub ax, 0b0h ; Check for wrap
  1026. jb WaitExit ; No, no roll over. Exit with
  1027. ; cary set
  1028. ; At this point we have determined that we have wrapped and that the
  1029. ; ending time is into the next day. Update the ending time
  1030. mov [DWFinalCount],ax ; Set final LoWord
  1031. xor ax,ax
  1032. mov [DWFinalCount+2],ax ; Zero final HiWord
  1033. jmp WaitLowCheck ; Check LoWord
  1034. endif
  1035. IsWaitOver ENDP
  1036. ;++
  1037. ;
  1038. ; USHORT
  1039. ; TestForLogitechSerial (
  1040. ; VOID
  1041. ; )
  1042. ;
  1043. ; Routine Description:
  1044. ;
  1045. ; This procedure will detect the presence of a Logitech Series C
  1046. ; serial mouse is present
  1047. ;
  1048. ; Arguments:
  1049. ;
  1050. ; (edx) = Port Address
  1051. ;
  1052. ; Return Value:
  1053. ;
  1054. ; (ax) = Mouse ID.
  1055. ;
  1056. ;--
  1057. TestForLogitechSerial PROC NEAR
  1058. push di
  1059. push bx
  1060. sub sp, 10
  1061. mov bx, sp
  1062. mov word ptr [bx], 60h ; baud = 1200
  1063. mov word ptr [bx + 2], 30h ; baud = 2400
  1064. mov word ptr [bx + 4], 18h ; baud = 4800
  1065. mov word ptr [bx + 6], 0ch ; baud = 9600
  1066. mov word ptr [bx + 8], 0
  1067. ;
  1068. ; Power up the C series mouse.
  1069. ;
  1070. ; Set both DTR and RTS to an active state
  1071. ; If DTR and RTS are already on, the power is on for at least 500ms
  1072. ; due to the MM serial mouse detection.
  1073. ;
  1074. address MCR RXB ; Get address of Modem Control Reg.
  1075. DelayIn ; Get modem control byte
  1076. and al, MC_DTR + MC_RTS ; Check DTR and RTS
  1077. cmp al, MC_DTR + MC_RTS
  1078. je short @f ; the lines are high already
  1079. mov al, MC_DTR + MC_RTS ; Set DTR and RTS to an active state
  1080. DelayOut ; and ...
  1081. mov cx,9 ; wait for 1/2 second to pwrup mouse
  1082. call SetupForWait ; Set up BX:CX and ES:DI properly for
  1083. assume es:nothing ; upcoming delay loop.
  1084. ; ask for current baud rate
  1085. lt_waitloop1:
  1086. call IsWaitOver ; Determine if we've delayed enough.
  1087. jnc short lt_waitloop1
  1088. @@:
  1089. ;
  1090. ; Set the line control register to a format that the mouse can
  1091. ; understand (see below: the line is set after the report rate).
  1092. ;
  1093. address LCR MCR ; Get address of Line Control Reg.
  1094. mov al,LC_BITS8 + LC_STOP1 + LC_PODD
  1095. DelayOut
  1096. ;
  1097. ; Cycle through the different baud rates to detect the mouse.
  1098. ;
  1099. mov di, 0
  1100. address RXB LCR
  1101. Tfs_Next_Baud:
  1102. mov cx, [bx + di]
  1103. cmp cx, 0
  1104. je Tfs110 ; Reach the end of table
  1105. call SetBaudRate ; Set baud rate
  1106. ;
  1107. ; Put the mouse in prompt mode.
  1108. ;
  1109. mov cl, 'D'
  1110. call CSerWriteChar
  1111. ;
  1112. ; Set the MM protocol. This way we get the mouse to talk to us in a
  1113. ; specific format. This avoids receiving errors from the line
  1114. ; register.
  1115. ;
  1116. mov cl, 'S'
  1117. call CSerWriteChar
  1118. address LCR RXB ; Get address of Line Control Reg.
  1119. mov al,LC_BITS8 + LC_STOP1 + LC_PODD
  1120. DelayOut
  1121. ;
  1122. ; Try to get the status byte.
  1123. ;
  1124. address RXB LCR
  1125. mov cl, 's'
  1126. call CSerWriteChar
  1127. ;
  1128. ; Read back the status character.
  1129. ;
  1130. mov cx,2 ; Wait at least 55.5 ms for response.
  1131. call SetupForWait
  1132. assume es:nothing
  1133. address LSR RXB
  1134. lt_waitloop2: ; (dx) = LSR reg
  1135. DelayIn
  1136. test al, LS_DR ; Is receiving buffer full?
  1137. jnz short @f ; Yes, go read it.
  1138. lt_waitloop21: ; (dx) = LSR reg
  1139. call IsWaitOver
  1140. jnc short lt_waitloop2
  1141. address RXB LSR
  1142. jmp short Tfs50
  1143. @@:
  1144. address RXB LSR
  1145. DelayIn
  1146. cmp al, 04fh ; al = 4Fh means command understood
  1147. je short Tfs100
  1148. address LSR RXB
  1149. jmp short lt_waitloop21
  1150. Tfs50:
  1151. add di, 2
  1152. jmp Tfs_Next_Baud
  1153. Tfs100:
  1154. ;
  1155. ; Found the C series mouse. Put the mouse back in a default mode.
  1156. ; The protocol is already set.
  1157. ;
  1158. ;
  1159. ; Set to default baud rate 1200
  1160. ;
  1161. mov cl, '*'
  1162. call CSerWriteChar
  1163. mov cl, 'n'
  1164. call CSerWriteChar
  1165. ;
  1166. ; Wait for TX buffer empty
  1167. ;
  1168. mov cx, 1
  1169. call SetupForWait
  1170. address LSR RXB
  1171. @@:
  1172. DelayIn
  1173. and al, LS_THRE + LS_TSRE
  1174. cmp al, LS_THRE + LS_TSRE
  1175. je short @f ; Wait for TX buffer empty
  1176. call IsWaitOver
  1177. jnc short @b
  1178. @@:
  1179. address RXB LSR
  1180. mov cx, 60h ; Set baud rate to 1200
  1181. call SetBaudRate
  1182. ;
  1183. ; Set mouse to default report rate
  1184. ;
  1185. mov cl, 'N'
  1186. call CSerWriteChar
  1187. mov ax,LT_MOUSE + SERIAL_MOUSE
  1188. jmp short lt_leave
  1189. Tfs110:
  1190. mov ax,NO_MOUSE
  1191. lt_leave:
  1192. add sp, 10 ; clear stack
  1193. pop bx
  1194. pop di
  1195. ret
  1196. TestForLogitechSerial ENDP
  1197. ;++
  1198. ;
  1199. ; VOID
  1200. ; SetBaudRate (
  1201. ; USHORT Port,
  1202. ; USHORT BaudRate
  1203. ; )
  1204. ;
  1205. ; Routine Description:
  1206. ;
  1207. ; This procedure will set up the given COM port so that it can talk to
  1208. ; a Logitech C series serial mouse.
  1209. ;
  1210. ; Arguments:
  1211. ;
  1212. ; (DX) = COM Base address of COM port to set up.
  1213. ; (CX) = Baud Rate
  1214. ;
  1215. ; Return Value:
  1216. ;
  1217. ; None.
  1218. ;
  1219. ;--
  1220. SetBaudRate PROC NEAR
  1221. push dx
  1222. address LCR RXB ; Get address of Line Control Reg.
  1223. DelayIn
  1224. or al,LC_DLAB ; Set up to access divisor latches.
  1225. DelayOut
  1226. address LATMSB LCR ; Get address of high word of divisor
  1227. mov al, ch ; latch and set it with value for
  1228. DelayOut ; specified baud.
  1229. address LATLSB LATMSB ; Get address of low word of divisor
  1230. mov al, cl ; latch and set it with value for
  1231. DelayOut ; specified baud.
  1232. address LCR LATLSB ; Get address of Line Control Reg.
  1233. DelayIn
  1234. and al, NOT LC_DLAB ; Disable access divisor latches.
  1235. DelayOut
  1236. mov cx, 1
  1237. call SetupForWait
  1238. @@:
  1239. call IsWaitOver
  1240. jnc short @b
  1241. pop dx
  1242. ret
  1243. SetBaudRate ENDP
  1244. ;++
  1245. ;
  1246. ; VOID
  1247. ; CSerWriteChar (
  1248. ; USHORT Port,
  1249. ; UCHAR Command
  1250. ; )
  1251. ;
  1252. ; Routine Description:
  1253. ;
  1254. ; This procedure will write a char/command to logitech C series mouse.
  1255. ;
  1256. ; Arguments:
  1257. ;
  1258. ; (DX) = COM Base address of COM port to set up.
  1259. ; (CL) = Command
  1260. ;
  1261. ; Return Value:
  1262. ;
  1263. ; None.
  1264. ;
  1265. ;--
  1266. CserWriteChar proc near
  1267. push cx
  1268. mov cx, 1
  1269. call SetupForWait
  1270. address LSR RXB
  1271. @@:
  1272. DelayIn
  1273. and al, LS_THRE + LS_TSRE
  1274. cmp al, LS_THRE + LS_TSRE
  1275. je short @f ; Wait for TX buffer empty
  1276. call IsWaitOver
  1277. jnc short @b
  1278. @@:
  1279. address TXB LSR
  1280. pop ax ; Send command
  1281. DelayOut
  1282. ret
  1283. CserWriteChar endp
  1284. if 0
  1285. ;++
  1286. ;
  1287. ; VOID
  1288. ; FlushReceiveBuffer (
  1289. ; USHORT Port
  1290. ; )
  1291. ;
  1292. ; Routine Description:
  1293. ;
  1294. ; This procedure will flush receive buffer or until time out.
  1295. ;
  1296. ; Arguments:
  1297. ;
  1298. ; (DX) = COM Base address of COM port to set up.
  1299. ;
  1300. ; Return Value:
  1301. ;
  1302. ; None.
  1303. ;
  1304. ;--
  1305. FlushReceiveBuffer proc near
  1306. mov cx, 5
  1307. call SetupForWait
  1308. @@:
  1309. address LSR RXB
  1310. DelayIn
  1311. test al, LS_DR
  1312. jz short @f
  1313. address RXB LSR
  1314. DelayIn
  1315. call IsWaitOver
  1316. jnc short @b
  1317. ret
  1318. @@:
  1319. address RXB LSR
  1320. ret
  1321. FlushReceiveBuffer endp
  1322. endif
  1323. _TEXT ends
  1324. end