home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / c / c220 / 7.ddi / EXAMPLES / DOSEXT / PTAIL2.ASM < prev    next >
Encoding:
Assembly Source File  |  1991-01-24  |  14.5 KB  |  561 lines

  1. ;************************************************************************/
  2. ;*    Copyright (C) 1986-1988 Phar Lap Software, Inc.            */
  3. ;*    Unpublished - rights reserved under the Copyright Laws of the    */
  4. ;*    United States.  Use, duplication, or disclosure by the         */
  5. ;*    Government is subject to restrictions as set forth in         */
  6. ;*    subparagraph (c)(1)(ii) of the Rights in Technical Data and     */
  7. ;*    Computer Software clause at 252.227-7013.            */
  8. ;*    Phar Lap Software, Inc., 60 Aberdeen Ave., Cambridge, MA 02138    */
  9. ;************************************************************************/
  10. ;
  11. ; PTAIL2.ASM - This is the protected mode portion
  12. ; of an example program that uses
  13. ; the Microsoft mouse driver, and also demonstrates
  14. ; several techniques for mixing real and protected
  15. ; mode code in the same program.
  16. ;
  17. ; FUNCTIONALITY - The program is used to draw rough
  18. ; pictures on the screen using the mouse.  The 
  19. ; program is always in one of two modes - character
  20. ; output mode, or toggle mode.  When in character
  21. ; output mode pressing the right mouse button will
  22. ; output a character at the current cursor position.
  23. ; Pressing the left mouse button causes the program
  24. ; to enter toggle mode.  When in toggle mode, 
  25. ; pressing the right mouse button will cause the
  26. ; character that gets output to be toggled between 
  27. ; a '*' and a ' ' (space).  Pressing the left mouse 
  28. ; button in toggle mode causes the program to exit. 
  29. ; The program starts up in character output mode, 
  30. ; with the output character set to '*'.  The program 
  31. ; is used to draw rudimentary pictures with '*'s,
  32. ; toggling the output character to a space to 
  33. ; erase mistakes.
  34. ;
  35. ; IMPLEMENTATION - The program demonstrates having
  36. ; the protected mode code in a protected mode EXP
  37. ; file, and the real mode code in a separate EXE
  38. ; file.  The protected mode program is linked (or
  39. ; run) with the -CALLBUFS switch to allocate
  40. ; a data buffer in conventional memory for
  41. ; passing data on intermode procedure calls, and
  42. ; the -MINREAL switch to make sure enough 
  43. ; conventional memory is left free to load the
  44. ; real mode program.  The protected mode program
  45. ; is run first, and it makes a Phar Lap EXEC
  46. ; system call to load the real mode program into
  47. ; memory without remapping the hardware interrupts
  48. ; back to their standard real mode settings.  
  49. ; Once the real mode program is running,
  50. ; the two programs transfer control to each other
  51. ; with software interrupts.
  52. ;
  53.  
  54. ;
  55. ; Segment ordering and attributes.  
  56. ;
  57. pmdata    segment dword public use32
  58. pmdata    ends
  59. pmcode    segment byte public use32
  60. pmcode    ends
  61. stack    segment dword stack use32
  62. stack    ends
  63.  
  64. ;
  65. ; Constants
  66. ;
  67. TRUE    equ    1
  68. FALSE    equ    0
  69.  
  70. ;
  71. ; Make entry points and data global so they
  72. ; can be accessed by the debugger
  73. ;
  74. public    main,init,cleanup,print_ch,pmi_hndlr
  75. public    vid_mode,pm_cbuf,rm_cseg
  76.  
  77. ;
  78. ; Give program a 4K stack
  79. ;
  80. stack    segment
  81.     db    4096 dup(?)
  82. stack    ends
  83.  
  84. ;
  85. ; Data structure for global data that is
  86. ; stored in the intermode call buffer, where
  87. ; both the real mode and the protected mode
  88. ; program can access it.  This data
  89. ; is initialized by the protected mode program,
  90. ; and modified by the real mode program.
  91. ;
  92. SHARE    struc
  93.     DONEF    dd ?    ; flags when pgm done
  94.     OUTP_CH    db ?    ; current output char
  95. SHARE    ends
  96.  
  97. ;
  98. ; Global data.
  99. ;
  100. pmdata    segment
  101.  
  102. vid_mode db    ?    ; saved video mode
  103.  
  104. pm_cbuf    label    pword    ; prot mode addr of 
  105. pm_coffs dd    ?        ; intermode call
  106. pm_cseg    dw    ?        ; buffer
  107. rm_cbuf    dd    ?    ; real mode addr of buf
  108. rm_cseg    dw    ?    ; segment addr of real 
  109.                 ; mode pgm's code
  110.                 ; segment
  111.  
  112. PROTINT    equ    0F0h    ; interrupt used to call
  113.                 ; from real to 
  114.                 ; prot mode
  115. pmi_sel    dw    ?    ; original prot mode
  116. pmi_offs dd    ?        ; interrupt vec
  117. rmi_adr    dd    ?    ; orig real mode vector
  118.  
  119. ;
  120. ; Data used to perform EXEC call.
  121. ;
  122. EXE_PBLK struc
  123.     ENVOFFS    dd    ?
  124.     ENVSEG    dw    ?
  125.     CMDOFFS    dd    ?
  126.     CMDSEG    dw    ?
  127. EXE_PBLK ends
  128. epblk    EXE_PBLK <>    ; exec param block
  129. rmpname    db    'RTAIL2.EXE',0 ; real mode pgm name
  130. cmdtail    db    1,PROTINT,0Dh ; cmd tail gives 
  131.                 ; interrupt vec
  132. ;
  133. ; Error messages
  134. ;
  135. drivmsg    db    'Mouse driver not present'
  136.     db    0Dh,0Ah,'$'
  137. b2msg    db    'Mouse must have 2 buttons'
  138.     db    0Dh,0Ah,'$'
  139. bufmsg    db    'Intermode call buffer too small'
  140.     db    0Dh,0Ah,'$'
  141. loadmsg    db    'Error loading real mode pgm'
  142.     db    0Dh,0Ah,'$'
  143.  
  144. pmdata    ends
  145.  
  146. page
  147.     assume    cs:pmcode,ds:pmdata
  148. pmcode    segment    
  149.  
  150. ;***************************************************
  151. ; main - loads the real mode program and sets up the 
  152. ;    mouse handler, then execs to the real mode
  153. ;    program, which will not terminate until the
  154. ;    left mouse button is pressed twice.
  155. ;***************************************************
  156. main    proc    near        ; program entry point
  157.  
  158.     call    init        ; init mouse
  159.     cmp    eax,TRUE    ; branch if error
  160.     je    short #initerr        ;
  161.  
  162.     les    ebx,pm_cbuf    ; set ES:EBX to point
  163.                     ; to call buf
  164.     mov    es:[ebx].DONEF,FALSE ; init done flag
  165.     mov    es:[ebx].OUTP_CH,'*' ; init output char
  166.  
  167. ;
  168. ; Start the real mode program running.  The first thing
  169. ; the real mode program will do is call the prot mode
  170. ; program (with the software interrupt identified in 
  171. ; the command line from the exec) to get the address of
  172. ; the intermode call buffer.  Then it will set up its
  173. ; own handler to get control when a mouse button is
  174. ; pressed, and just loop until the left button is pressed
  175. ; twice.  At that point it terminates and the prot mode
  176. ; program will get control again at the instruction 
  177. ; following the exec system call.
  178. ;
  179.     mov    epblk.ENVSEG,0    ; param blk = inherit
  180.     mov    ax,ds            ; environment,
  181.     mov    epblk.CMDSEG,ax        ; hardwired cmd 
  182.     mov    epblk.CMDOFFS,offset cmdtail ; tail
  183.     mov    ax,ds        ; load program
  184.     mov    es,ax            ;
  185.     lea    ebx,epblk        ;
  186.     lea    edx,rmpname        ;
  187.     mov    ax,25C3h        ;
  188.     int    21h            ;
  189.     jc    short #lderr    ; branch if error
  190.  
  191. ;
  192. ; OK, real mode pgm terminated so we are all done.
  193. ;
  194.     call    cleanup        ; clean up mouse
  195.     mov    al,0        ; return success
  196.  
  197. #exit:
  198.     mov    ah,4Ch        ; exit to DOS
  199.     int    21h            ;
  200.  
  201. #initerr:
  202.     mov    al,1        ; return error
  203.     jmp    #exit            ;
  204. #lderr:
  205.     lea    edx,loadmsg
  206. #err:
  207.     mov    ah,9        ; output error msg
  208.     int    21h            ;
  209.     call    cleanup        ; clean up mouse
  210.     mov    al,1        ; return error
  211.     jmp    #exit            ;
  212.  
  213. main    endp
  214.  
  215. ;***************************************************
  216. ; init - This routine checks for the presence
  217. ;    of the mouse driver, and if it is present,
  218. ;    initializes it.  It also gets the address
  219. ;    of the intermode call buffer which is used
  220. ;    for passing data between the real and
  221. ;    protected mode programs, and takes over
  222. ;    the software interrupt which is used by
  223. ;    the real mode program to call the prot
  224. ;    mode program.
  225. ;
  226. ; Returns:    TRUE if error
  227. ;        FALSE if success
  228. ;***************************************************
  229. init proc near
  230.  
  231.     push    es        ; save regs
  232.  
  233. ;
  234. ; Save the current video mode, and set the video mode 
  235. ; to 80x25 B&W (8x8 cell size).
  236. ;
  237.     mov    ah,0Fh        ; get video state
  238.     int    10h            ;
  239.     mov    vid_mode,al        ;
  240.     mov    ax,0002h    ; set video state
  241.     int    10h            ;
  242.  
  243. ;
  244. ; Get real and prot mode addresses of intermode call 
  245. ; buffer, and check to make sure the call buffer
  246. ; is sufficiently large.
  247. ;
  248.     mov    ax,250Dh    ; get real mode link
  249.     int    21h            ; info
  250.     cmp    ecx,size SHARE    ; branch if call buf
  251.     jb    #buferr            ; too small
  252.     mov    rm_cbuf,ebx    ; save RM buf addr
  253.     mov    pm_coffs,edx    ; save PM buf addr
  254.     mov    ax,es            ;
  255.     mov    pm_cseg,ax        ;
  256.  
  257. ;
  258. ; Check for presence of mouse driver, take error
  259. ; exit if not present, initialize it if present
  260. ;
  261.     mov    cl,33h        ; get mouse real mode
  262.     mov    ax,2503h        ; int vector
  263.     int    21h            ;
  264.     cmp    ebx,0        ; branch if null
  265.     je    #no_driver        ;
  266.     xor    eax,eax        ; branch if vector
  267.     mov    ax,bx            ; just points
  268.     and    ebx,0FFFF0000h        ; to an IRET
  269.     shr    ebx,12            ;
  270.     add    ebx,eax            ;
  271.     mov    ax,0034h        ;
  272.     mov    es,ax            ;
  273.     cmp    byte ptr es:[ebx],0CFh    ;
  274.     je    short #no_driver    ;
  275.     mov    ax,0        ; Initialize mouse
  276.     int    33h            ; driver
  277.     cmp    ax,0        ; branch if not
  278.     je    short #no_driver    ; installed
  279.     cmp    bx,2        ; pgm requires 2 
  280.     jne    short #buttons        ; buttons
  281.  
  282. ;
  283. ; Save the current protected AND real mode interrupt
  284. ; vectors for the interrupt used to call from real
  285. ; mode to protected mode, and then take over the
  286. ; interrupt so that we always gain control in our
  287. ; protected mode handler (taking over the interrupt
  288. ; in this fashion changes both the real and prot
  289. ; mode interrupt vectors).
  290. ;
  291.     mov    ax,2502h    ; save original 
  292.     mov    cl,PROTINT        ; prot mode
  293.     int    21h            ; vector
  294.     mov    pmi_sel,es        ;
  295.     mov    pmi_offs,ebx        ;
  296.     mov    ax,2503h    ; save original
  297.     mov    cl,PROTINT        ; real mode
  298.     int    21h            ; vector
  299.     mov    rmi_adr,ebx        ;
  300.     push    ds        ; take over int
  301.     mov    ax,cs            ; to always
  302.     mov    ds,ax            ; get control
  303.     lea    edx,pmi_hndlr        ; in prot 
  304.     mov    cl,PROTINT        ; mode
  305.     mov    ax,2506h        ;
  306.     int    21h            ;
  307.     pop    ds            ;
  308.  
  309. ;
  310. ; OK, all initialized - display mouse cursor and exit
  311. ;
  312.     mov    ax,1        ; display mouse cursor
  313.     int    33h            ;
  314.     mov    eax,FALSE    ; return success
  315.  
  316. #exit:
  317.     pop    es        ; restore regs 
  318.     ret                ; & exit
  319.  
  320. #buttons:
  321.     lea    edx,b2msg
  322.     jmp    short #err
  323. #no_driver:
  324.     lea    edx,drivmsg
  325.     jmp    short #err
  326. #buferr:
  327.     lea    edx,bufmsg
  328. #err:
  329.     mov    ah,0        ; restore video mode
  330.     mov    al,vid_mode        ;
  331.     int    10h            ;
  332.     mov    ah,9        ; output error msg
  333.     int    21h            ;
  334.     mov    eax,TRUE    ; return error
  335.     jmp    #exit            ;
  336.  
  337. init endp
  338.  
  339. ;***************************************************
  340. ; cleanup - This routine resets the mouse driver to 
  341. ;    set the interrupt call mask to 0 and hide 
  342. ;    the cursor, and restores the original video
  343. ;    mode, and restores the original interrupt
  344. ;    vectors for the interrupt we took over.
  345. ;***************************************************
  346. cleanup proc near
  347.     push    es        ; save regs we modify
  348.  
  349.     mov    ax,0        ; reset mouse 
  350.     int    33h            ;
  351.     mov    ah,0        ; restore video mode
  352.     mov    al,vid_mode        ;
  353.     int    10h            ;
  354.  
  355.     push    ds        ; restore original
  356.     mov    edx,pmi_offs        ; prot mode
  357.     mov    ax,pmi_sel        ; vector
  358.     mov    ds,ax            ;
  359.     mov    cl,PROTINT        ;
  360.     mov    ax,2504h        ;
  361.     int    21h            ;
  362.     pop    ds            ;
  363.     mov    ebx,rmi_adr    ; restore original
  364.     mov    cl,PROTINT        ; real mode
  365.     mov    ax,2505h        ; vector
  366.     int    21h            ;
  367.  
  368. #exit:
  369.     pop    es        ; restore regs &
  370.     ret                ; exit
  371. cleanup endp
  372.  
  373. ;***************************************************
  374. ; pmi_hndlr - This is the interrupt handler that gets
  375. ;    control when the real mode program issues
  376. ;    the software interrupt we have taken over.
  377. ;    Since we know we always get control from
  378. ;    real mode, we know 386|DOS-Extender will
  379. ;    always have set up the segment registers 
  380. ;    as they were at startup time, so we don't
  381. ;    have to set them up here.
  382. ;    
  383. ;    This routine takes a code specifying the
  384. ;    desired function in EAX.  The following
  385. ;    functions are supported:
  386. ;
  387. ;    EAX=1    Initialize interface
  388. ;    IN:    BL = interrupt number to call thru
  389. ;            to real mode pgm
  390. ;        CX = segment addr of code segment
  391. ;            in real mode program (used
  392. ;            only for debugging)
  393. ;    OUT:    EAX = FALSE
  394. ;        EBX = real mode addr of call buffer
  395. ;
  396. ;    EAX=2    Process mouse button hit when in 
  397. ;            character output mode
  398. ;    IN:    CX = horizontal cursor coordinate
  399. ;        DX = vertical cursor coordinate
  400. ;        WORD on top of original stack = condition mask
  401. ;    OUT:    EAX = TRUE if error, FALSE if success
  402. ;        EBX-EDX = destroyed
  403. ;
  404. ;    EAX = anything else
  405. ;    OUT:    EAX = TRUE (error)
  406. ;***************************************************
  407. pmi_hndlr proc    near
  408. ;
  409. ; Stack frame 
  410. ;
  411. #ORIG_SS equ    (dword ptr 32[ebp])
  412. #ORIG_ESP equ    (dword ptr 28[ebp])
  413.  
  414.     push    ebp        ; set up stack frame
  415.     mov    ebp,esp            ;
  416.  
  417.     cmp    eax,1        ; branch if init func
  418.     je    short #init        ;
  419.     cmp    eax,2        ; branch if mouse
  420.     je    short #button        ; button
  421.     jmp    short #err    ; bad function number
  422.  
  423. #init:
  424. ;
  425. ; We modify the code for the INT instruction that calls 
  426. ; thru to real mode in the print_ch routine, now that we
  427. ; know which interrupt the real mode program took over.
  428. ; Since we know that CS and DS map the same program 
  429. ; segment, there is no need to set up an alias for the
  430. ; code segment to do this.
  431. ;
  432.     assume    ds:pmcode    ; Modify INT instruction
  433.     mov    byte ptr int_inst+1,bl    ;
  434.     assume    ds:pmdata        ;
  435.     mov    rm_cseg,cx    ; save code segment addr
  436.                     ; for real mode pgm
  437.     mov    ebx,rm_cbuf    ; return real mode addr
  438.                     ; of call buffer
  439.     mov    eax,FALSE    ; return success
  440.     jmp    short #exit        ;
  441.  
  442. #button:
  443.     push    es        ; get condition mask off orig stack
  444.     mov    ax,34h            ;
  445.     mov    es,ax            ;
  446.     movzx    eax,word ptr #ORIG_SS    ;
  447.     shl    eax,4            ;
  448.     add    eax,#ORIG_ESP        ;
  449.     mov    ax,es:[eax]        ;
  450.     pop    es            ;
  451.     push    ax        ; process button hit
  452.     call    print_ch        ; (ret's status
  453.     add    esp,2            ; in EAX)
  454.  
  455. #exit:
  456.     pop    ebp        ; restore registers
  457.     iretd            ; return to caller
  458.  
  459. #err:
  460.     mov    eax,TRUE    ; return error
  461.     jmp    #exit            ;
  462.  
  463. pmi_hndlr endp
  464.  
  465. ;***************************************************
  466. ; print_ch(cond_msk)
  467. ; WORD cond_msk;
  468. ;
  469. ;    This routine is called from real mode
  470. ;    when either mouse button is pressed and we
  471. ;    are in character input mode.
  472. ;
  473. ;    If the left button was pressed, this proc
  474. ;    puts us in toggle mode by calling (via a 
  475. ;    software interrupt) the real mode routine
  476. ;    that sets up the mouse handler to the 
  477. ;    toggle mode handler in the real mode pgm.
  478. ;
  479. ;    If the right button was pressed, this proc
  480. ;    outputs the current output character at 
  481. ;    the specified cursor position.
  482. ;
  483. ; Inputs:
  484. ;    1st stack param = mouse condition mask
  485. ;    CX = horizontal cursor coord
  486. ;    DX = vertical cursor coord
  487. ;
  488. ; Outputs:
  489. ;    AX = TRUE if error, FALSE if success
  490. ;    EBX-EDX = destroyed
  491. ;***************************************************
  492. print_ch proc    near
  493. ;
  494. ; Stack frame
  495. ;
  496. #COND_MSK equ    (word ptr 8[ebp])
  497.  
  498.     push    ebp        ; Set up stack frame
  499.     mov    ebp,esp            ;
  500.     push    es        ; save regs
  501.     push    fs            ;
  502.  
  503.     test    #COND_MSK,2    ; branch if left button
  504.     jz    short #right        ; not pressed
  505.  
  506. ;
  507. ; Left mouse button was pressed.  All we do is 
  508. ; call a routine in the real mode program (with a
  509. ; software interrupt), which changes to toggle mode
  510. ; by setting up the toggle mode handler in the real
  511. ; mode program to get control when a mouse button
  512. ; is pressed.  The interrupt to call is set up
  513. ; by modifying the code during initialization.
  514. ;
  515. int_inst:
  516.     int    0        ; toggle modes
  517.     jmp    short #exit    ; all done
  518.  
  519. #right:
  520. ;
  521. ; Right mouse button was pressed.  Set up ES to point 
  522. ; to screen segment.
  523. ;
  524.     mov    ax,001Ch    
  525.     mov    es,ax    
  526.  
  527. ;
  528. ; Get offset in screen segment of 1st character on
  529. ; the line the cursor is on
  530. ;
  531.     shr    dx,3        ; convert pixel to line
  532.     imul    dx,160        ; 160 bytes/line
  533.  
  534. ;
  535. ; Add in the column number * 2 (2 bytes/char)
  536. ;
  537.     shr    cx,2
  538.     add    cx,dx
  539.     mov    bx,cx
  540.  
  541. ;
  542. ; Output the character at the cursor.
  543. ;
  544.     mov    ah,7        ; normal attribute
  545.     lfs    edx,pm_cbuf    ; get character
  546.     mov    al,fs:[edx].OUTP_CH    ;
  547.     mov    word ptr es:[bx],ax ; output it
  548.  
  549.     mov    ax,FALSE    ; return success
  550.  
  551. #exit:
  552.     pop    fs        ; restore regs &
  553.     pop    es            ; exit
  554.     pop    ebp            ;
  555.     ret                ; 
  556. print_ch endp
  557.  
  558. pmcode    ends
  559.  
  560.     end main        ; program entry point
  561.