home *** CD-ROM | disk | FTP | other *** search
/ CD Actual 15 / CDACTUAL15.iso / cdactual / program / asm / KBSTUF.ZIP / KBSTUFF.ASM next >
Encoding:
Assembly Source File  |  1992-06-01  |  19.2 KB  |  784 lines

  1. page 60,132
  2. ;+
  3. ;********************************************************************
  4. ;    (c) Copyright 1989-1992 Magic Box Designs, David J. Crone
  5. ;    all rights reserved
  6. ;
  7. ; Filename: kbstuff.asm
  8. ;
  9. ; Function: Assembly language routines for accessing PC keyboard
  10. ;
  11. ; Author: David J. Crone
  12. ; Version: 2.0
  13. ; Last Edit:    04-Jun-91 [014]    DJC  fix to newfudge
  14. ;               10-Aug-89       DJC  Creation
  15. ;
  16. ;********************************************************************
  17. ;-
  18.  
  19. INCLUDE kb.inc
  20.  
  21. NEWFUDGE    EQU    1    ;0=use code tromping version
  22.                 ;1=use controller overwrite version
  23.  
  24.  
  25. ;    .CODE
  26. _TEXT    SEGMENT  WORD PUBLIC 'CODE'
  27.         ASSUME cs:_TEXT, ds:_TEXT, es:_TEXT
  28.  
  29.  
  30. ; --- data ---
  31. if NEWFUDGE EQ 0
  32.   _fudge_count:WORD
  33.   _fudge_factor:WORD
  34.   _fudge_addr:WORD
  35.   _fudge_isr_addr:DWORD
  36. endif
  37.  
  38.  
  39.  
  40. ;+
  41. ;**********************************************************
  42. ; name: set_vector(interrupt_number, far *routine);
  43. ; return type: void
  44. ; entry type:   int interrupt_number;
  45. ;               far *routine;
  46. ; function:
  47. ;    set an interrupt vector to use a specific routine
  48. ;
  49. ;**********************************************************
  50. ;-
  51.  
  52. int_num    =      4        ;interrupt number
  53. r_off    =      6        ;routine offset
  54. r_seg    =      8        ;routine segment
  55.  
  56.     PUBLIC    _set_vector
  57. _set_vector    PROC NEAR
  58.     push    bp
  59.     mov    bp,sp            ;establish stack frame
  60.         push    es
  61.         push    ds
  62.         push    si
  63.  
  64.     mov    ax,[bp].r_seg        ;get segment of routine
  65.         mov     ds,ax
  66.     mov    dx,[bp].r_off        ;get offset of routine
  67.  
  68.         mov    ax,WORD PTR [bp].int_num ;get interrupt number
  69.         mov     ah,25h                  ;"set int vector" DOS function
  70.         int     21h                     ;passed as DS:DX
  71.  
  72.         pop     si
  73.         pop     ds
  74.         pop     es
  75.     pop    bp
  76.     ret
  77.  
  78. _set_vector    ENDP
  79.  
  80.  
  81. ;+
  82. ;**********************************************************
  83. ; name: get_vector(interrupt_number);
  84. ; return type:  void far *
  85. ; entry type:   int interrupt_number;
  86. ;
  87. ; function:
  88. ;    returns the contents of an interrupt vector 
  89. ; exit:
  90. ;    dx    segment
  91. ;    ax    offset
  92. ;**********************************************************
  93. ;-
  94.  
  95. int_num    =      4        ;interrupt number
  96.  
  97.     PUBLIC    _get_vector
  98. _get_vector    PROC NEAR
  99.     push    bp
  100.     mov    bp,sp            ;establish stack frame
  101.         push    es
  102.         push    ds
  103.         push    si
  104.  
  105.     mov    ax,WORD PTR [bp].int_num ;get interrupt number
  106.         mov     ah,35h                  ;"get int vector" DOS function
  107.         int     21h                     ;returns ES:BX
  108.  
  109.         mov     dx,es                   ;we want to return in DX:AX
  110.         mov     ax,bx
  111.  
  112.         pop     si
  113.         pop     ds
  114.         pop     es
  115.     pop    bp
  116.     ret
  117.  
  118. _get_vector    ENDP
  119.  
  120.  
  121. ;+
  122. ;**********************************************************
  123. ; name: read_vector(interrupt_number);
  124. ; return type:  void far *
  125. ; entry type:   int interrupt_number;
  126. ;
  127. ; function: This routine manually reads the interrupt 
  128. ;    vector address.  It should not normally be used, but
  129. ;    is the only way to get a vector from within an 
  130. ;    interrupt service routine.  DOS is not nice about
  131. ;    executing function 35h from within an interrupt
  132. ;    routine
  133. ; exit:
  134. ;    dx    segment
  135. ;    ax    offset
  136. ;**********************************************************
  137. ;-
  138.  
  139. int_num    =      4        ;interrupt number
  140.  
  141.     PUBLIC    _read_vector
  142. _read_vector    PROC NEAR
  143.     push    bp
  144.     mov    bp,sp            ;establish stack frame
  145.         push    ds
  146.         push    si
  147.  
  148.     mov    si,WORD PTR [bp].int_num ;get interrupt number
  149.     shl    si,2            ; * 4 for offset
  150.     mov    ax,0
  151.     mov    ds,ax            ;segment 0
  152.  
  153.     mov    ax,[si]            ;read offset of vector
  154.     mov    dx,[si+2]        ;read segment of vector
  155.  
  156.         pop     si
  157.         pop     ds
  158.     pop    bp
  159.     ret
  160.  
  161. _read_vector    ENDP
  162.  
  163.  
  164.  
  165. ;+
  166. ;********************************************************
  167. ; name: signal_eoi()
  168. ; return type: void
  169. ; entry type: void
  170. ;
  171. ; function: Signal end of interrupt to 8259A
  172. ;********************************************************/
  173. ;-
  174.  
  175.         PUBLIC  _signal_eoi
  176. _signal_eoi     PROC    NEAR
  177.         mov     al,EOI          ;signal end-of-interrupt
  178.         out     EOI_MASTER,al   ;first signal master
  179.     cmp    _delta_int,070h    ;is IRQ on slave ?
  180.     jb    sig_10        ;no, skip
  181.  
  182.         out     EOI_SLAVE,al    ;then signal slave 8259
  183. sig_10:
  184.         ret
  185. _signal_eoi     ENDP
  186.  
  187.  
  188.  
  189. ;+
  190. ;**********************************************************
  191. ;* name: get_bios_buffer()
  192. ;* return type:  int
  193. ;* entry type:   void
  194. ;*
  195. ;* function: returns next char from BIOS buffer if one available
  196. ;**********************************************************
  197. ;-
  198.  
  199.         PUBLIC  _get_bios_buffer
  200. _get_bios_buffer        PROC    NEAR
  201.  
  202.         push    bx
  203.         push    es
  204.  
  205.         mov     ax,BIOS_SEG             ;set up BIOS data seg
  206.         mov     es,ax
  207.         mov     bx,es:bios_head         ;get head ptr
  208.         cmp     bx,es:bios_tail         ;if anything in buffer
  209.         je      get_bios_20
  210.  
  211.         mov     ax,es:[bx]              ;get char
  212.         call    inc_bios                ;then inc ptr
  213.         mov     es:bios_head,bx         ;store it
  214. get_bios_20:
  215.         pop     es
  216.         pop     bx
  217.         ret
  218.  
  219. _get_bios_buffer        ENDP
  220.  
  221.  
  222.  
  223.  
  224. ;+
  225. ;**********************************************************
  226. ;* name: put_bios_buffer(scancode)
  227. ;* return type:  int
  228. ;* entry type:   unsigned scancode
  229. ;*
  230. ;* function: generate interrupt 0x15 
  231. ;**********************************************************
  232. ;-
  233.  
  234. scancode        =       4
  235.  
  236.         PUBLIC  _put_bios_buffer
  237. _put_bios_buffer        PROC    NEAR
  238.         push    bp
  239.         mov     bp,sp           ;establish stack frame
  240.         push    es
  241.         push    bx
  242.         push    dx
  243.  
  244.         mov     ax,BIOS_SEG             ;set up BIOS data seg
  245.         mov     es,ax
  246.         mov     bx,es:bios_tail         ;get tail ptr
  247.         mov     si,bx
  248.         call    inc_bios                ;increment it
  249.         cmp     bx,es:bios_head         ;wrapped around ?
  250.         je      put_bios_20             ;yes, skip the put
  251.  
  252.         mov     ax,[bp].scancode        ;get scan code
  253.         mov     es:[si],ax              ;put it in BIOS buffer
  254.         mov     es:bios_tail,bx         ;update tail pointer
  255.  
  256. put_bios_20:
  257.         pop     dx
  258.         pop     bx
  259.         pop     es
  260.         pop     bp
  261.         ret
  262.  
  263. _put_bios_buffer        ENDP
  264.  
  265.  
  266. ;+
  267. ;**********************************************************
  268. ;* name: clear_bios_buffer()
  269. ;* return type:  void
  270. ;* entry type:   void
  271. ;*
  272. ;* function: reset BIOS head & tail ptrs 
  273. ;**********************************************************
  274. ;-
  275.  
  276.         PUBLIC  _clear_bios_buffer
  277. _clear_bios_buffer        PROC    NEAR
  278.  
  279.         push    es
  280.  
  281.         mov     ax,BIOS_SEG     ;set up BIOS data seg
  282.         mov     es,ax
  283.         mov     ax,es:bios_start        ;reset buffer ptrs
  284.         mov     es:bios_head,ax
  285.         mov     es:bios_tail,ax
  286.  
  287.         pop     es
  288.         ret
  289.  
  290. _clear_bios_buffer        ENDP
  291.  
  292.  
  293. ;*****
  294. ; Increment bios buffer pointer -- strictly local routine
  295. ;*****
  296. inc_bios:
  297.         inc     bx
  298.         inc     bx
  299.         cmp     bx,es:bios_end
  300.         jb      inc_bios_20
  301.  
  302.         mov     bx,es:bios_start
  303. inc_bios_20:
  304.         ret
  305.  
  306.  
  307. ;+
  308. ;**********************************************************
  309. ;* name: update_bios_flags(bf, bf1, bf2)
  310. ;* return type:  void
  311. ;* entry type:   int bf         flag
  312. ;*               int bf1        flag_1
  313. ;*               int bf2        flag_2
  314. ;*
  315. ;* function: copy flags to BIOS data area
  316. ;**********************************************************
  317. ;-
  318.  
  319.         PUBLIC  _update_bios_flags
  320. _update_bios_flags      PROC    NEAR
  321.  
  322. bf      =       4
  323. bf1     =       6
  324. bf2     =       8
  325.  
  326.         push    bp
  327.         mov     bp,sp           ;establish stack frame
  328.         push    es
  329.  
  330.         mov     ax,BIOS_SEG     ;set up BIOS data seg
  331.         mov     es,ax
  332.         mov     ax,[bp].bf      ;copy LSByte of flags
  333.         mov     es:bios_flag,al
  334.         mov     ax,[bp].bf1
  335.         mov     es:bios_flag_1,al
  336.         mov     ax,[bp].bf2
  337.         mov     es:bios_flag_2,al
  338.         
  339.         pop     es
  340.         pop     bp
  341.         ret
  342.  
  343. _update_bios_flags      ENDP
  344.  
  345.  
  346. IF NEWFUDGE
  347. ;+
  348. ;***************************************************************
  349. ; Name: newfudge(scan_code)
  350. ; Entry: unsigned char scan_code    last scan code from delta kb
  351. ; Exit:  void
  352. ;
  353. ; Function: Send sequence to PC keyboard controller chip (8042) that
  354. ;        will cause it to place 'scan_code' in its data 
  355. ;        register at 060h.  This will allow us to vector to
  356. ;        the current Int 9 handler and let it handle the scan
  357. ;        code as it sees fit.  If this works, we can eliminate
  358. ;        the need to walk through the current Int 9 handler
  359. ;        and tromp on its code.
  360. ;    This will be accomplished by writing the scan code to the 
  361. ;    PC keyboard controller's command byte.  Then we will issue 
  362. ;    the command to read the controller's command byte.  This 
  363. ;    will cause the byte we just wrote (our scan code) to be 
  364. ;    presented as data on the keyboard controller.  Any subsequent
  365. ;    reads of the keyboard controller's data port will result
  366. ;    in reading the scan code we put there. 
  367. ; ***014    A problem was encountered when the data was EVEN
  368. ;    (i.e. bit 0 = 0)  This caused OutputBufferFull interrupts to
  369. ;    be disabled on the 8042, and thus no IRQ was registered on the
  370. ;    8259 int. controller.  Special handling was added within
  371. ;    "***014" markers to correct for this by doing a software
  372. ;    Int 9h instruction for EVEN data only.
  373. ;***************************************************************
  374. ;-
  375.  
  376. scan       =    4    ;index to scan code
  377.  
  378.     PUBLIC    _newfudge
  379. _newfudge    PROC    NEAR    ;                ***012 Begin
  380.     push    bp
  381.     mov    bp,sp        ;establish stack frame
  382.     pushf
  383.     cli            ;disable interrupts for this
  384.                 ;Don't want Int 9h handler to wake
  385.                 ; up until we get data set up first
  386.  
  387.     in    al,pc_k_data    ;clear any random data
  388.  
  389.     ;-- send Write Command Byte command to controller port (64h)
  390.     push    KC_WRITE
  391.     call    _send_pckb_controller
  392.     pop    ax
  393.  
  394.     ;-- send SCANCODE to data port (60h)
  395.     mov    ax,[bp].scan    ;get scan code
  396.     push    ax
  397.     call    _send_pckb_data
  398.     pop    ax
  399.  
  400.     ;-- send Read Command Byte command to controller port
  401.     push    KC_READ
  402.     call    _send_pckb_controller
  403.     pop    ax
  404.  
  405.     ;------------------------
  406.     ; keyboard controller now has our scancode in data port
  407.     ;------------------------
  408.  
  409.     ;-- send Write Command Byte command to controller port (64h)
  410.     push    KC_WRITE
  411.     call    _send_pckb_controller
  412.     pop    ax
  413.  
  414.     ;-- send standard enable to data port (60h)
  415.     push    049h        ;enable kb interrupts
  416.     call    _send_pckb_data
  417.     pop    ax
  418.  
  419.     ; The keyboard controller should generate an interrupt
  420.     ; as soon as the command byte is available.
  421.     ; (ODD scan codes only)
  422.  
  423.     call    _read_pckb_data    ;clear pending interrupt    ****
  424.  
  425.     popf            ;restore interrupt status
  426.                 ;                ***014 Begin
  427. ;    test    WORD PTR [bp].scan,01h    ;is scan code EVEN ?
  428. ;    jne    newf_50        ; no, exit
  429.  
  430.     int    9h        ; yes, must manually cause int 9h
  431. newf_50:            ;                ***014 End
  432.     pop    bp
  433.     ret
  434. _newfudge    ENDP        ;                ***012 End
  435.  
  436.  
  437. ;+
  438. ;**********************************************************
  439. ; name: send_pckb_controller(cmnd)
  440. ; return type:  void
  441. ; entry type:   unsigned char cmnd
  442. ;
  443. ; function: send a command code to the PC's 8042 keyboard
  444. ;           controller 
  445. ;**********************************************************
  446. ;-
  447.  
  448.         PUBLIC  _send_pckb_controller
  449. cmnd    =       4
  450.  
  451. _send_pckb_controller     PROC    NEAR
  452.         push    bp
  453.         mov     bp,sp           ;establish stack frame
  454.     pushf
  455.         cli                     ;;disable interrupts
  456.  
  457.         call    _wait_pckb_send   ;;wait till O.K. to send
  458.         mov     al,BYTE PTR [bp].cmnd
  459.  
  460.         mov     dx,pc_k_control
  461.         out     dx,al           ;;output command
  462.  
  463.     popf            ;restore interrupt status
  464.         pop     bp
  465.         ret
  466. _send_pckb_controller     ENDP
  467.  
  468.  
  469. ;+
  470. ;********************************************************
  471. ; name: send_pckb_data(cmnd)
  472. ; return type:  void
  473. ; entry type:    unsigned char cmnd
  474. ;
  475. ; function: send the keyboard command code through the PC's 8042
  476. ;           to the PC's keyboard
  477. ;********************************************************/
  478. ;-
  479.         PUBLIC  _send_pckb_data
  480. cmnd    =       4
  481.  
  482. _send_pckb_data     PROC    NEAR
  483.         push    bp
  484.         mov    bp,sp        ;establish stack frame
  485.     pushf
  486.         cli            ;;disable interrupts
  487.  
  488. spkbd_10:
  489.         call    _wait_pckb_send    ;;wait till O.K. to send
  490.  
  491.         mov    al,BYTE PTR [bp].cmnd
  492.         mov    dx,pc_k_data
  493.         out    dx,al        ;;output the command
  494.  
  495.     popf
  496.         pop    bp
  497.         ret
  498.  
  499. _send_pckb_data     ENDP
  500.  
  501.  
  502. ;+
  503. ;**********************************************************
  504. ; name: wait_pckb_send
  505. ; return type: int              0 = ready for data
  506. ; entry type: void
  507. ;
  508. ; funtion: Wait until PC's 8042 ready for new data
  509. ;**********************************************************
  510. ;-
  511.  
  512.         PUBLIC  _wait_pckb_send
  513. _wait_pckb_send    PROC    NEAR
  514.         sub     cx,cx           ;max. wait time
  515. wpkbs_10:
  516.         mov     dx,pc_k_status
  517.         in      al,dx           ;wait for input buffer empty
  518.         and     ax,KS_IBF       ;ibf=0 means buffer empty
  519.         loopnz  wpkbs_10
  520.  
  521.         ret
  522.  
  523. _wait_pckb_send   ENDP
  524.  
  525.  
  526. ;+
  527. ;**********************************************************
  528. ; name: wait_pckb_receive
  529. ; return type: int              non-zero = data available
  530. ; entry type: void
  531. ;
  532. ; funtion: Wait until new data ready from PC's 8042 
  533. ;**********************************************************
  534. ;-
  535.         PUBLIC  _wait_pckb_receive
  536. _wait_pckb_receive    PROC    NEAR
  537.         sub     cx,cx           ;max. wait time
  538. wpkbr_10:
  539.         mov     dx,pc_k_status
  540.         in      al,dx           ;wait for input buffer empty
  541.         and     ax,KS_OBF       ;obf=1 means buffer full
  542.         loopz   wpkbr_10
  543.  
  544.         ret
  545.  
  546. _wait_pckb_receive    ENDP
  547.  
  548.  
  549. ;+
  550. ;********************************************************
  551. ; name: read_pckb_data()
  552. ; return type: unsigned char 
  553. ; entry type: void
  554. ;
  555. ; function: return the PC's keyboard scan code
  556. ;********************************************************/
  557. ;-
  558.         PUBLIC  _read_pckb_data
  559. _read_pckb_data     PROC    NEAR
  560.  
  561.         mov     dx,pc_k_data
  562.         in      al,dx                   ;read data port of 8042
  563.  
  564.         ret
  565.  
  566. _read_pckb_data     ENDP
  567.  
  568.  
  569.  
  570. ;+
  571. ;********************************************************
  572. ; name: read_pckb_status()
  573. ; return type: unsigned char
  574. ; entry type: void
  575. ;
  576. ; function: return the status register of the PC's 8042 keyboard
  577. ;           controller
  578. ;********************************************************/
  579. ;-
  580.         PUBLIC  _read_pckb_status
  581. _read_pckb_status     PROC    NEAR
  582.  
  583.         mov     dx,pc_k_status
  584.         in      al,dx                   ;read 8042 status port
  585.  
  586.         ret
  587.  
  588. _read_pckb_status     ENDP
  589.  
  590.  
  591. ELSE                ;using old fudge method
  592.  
  593. ;+
  594. ;***************************************************************
  595. ; Name: fudge(scan_code)
  596. ; Entry: unsigned char scan_code    last scan code from delta kb
  597. ; Exit:  int            0 = no fudging, don't call int9
  598. ;                1 = current handler is fudged
  599. ;                    int9 needs to be called
  600. ;
  601. ; Function: Search through the currently installed Int 9 handler
  602. ;    (standard keyboard IRQ) and find the following instruction:
  603. ;        IN  AL,60h
  604. ;    Replace all occurrences of this statement within the first 
  605. ;    100h bytes with an 
  606. ;        INT 60h 
  607. ;    so that our special handler can substitute the scan code 
  608. ;    we want to use to fake out the Int 9 handler.
  609. ;***************************************************************
  610. ;-
  611.  
  612. scan       =    4    ;index to scan code
  613.  
  614.     PUBLIC    _fudge
  615. _fudge    PROC    NEAR
  616.  
  617.     push    bp
  618.     mov    bp,sp        ;establish stack frame
  619.     push    es
  620.     push    di
  621.     cld            ;make sure forward direction set
  622.  
  623.     mov    al,[bp].scan
  624.     mov    BYTE PTR CS:scode,al    ;save scan code
  625.  
  626.     mov    ax,9
  627.     push    ax
  628.     call    _read_vector        ;get int9 handler addr
  629.     add    sp,2            ; DX:AX = handler
  630.     mov    es,dx
  631.     mov    di,ax            ;now ES:DI = handler
  632.  
  633. ;* If int9 handler is our dummy handler, then no need
  634. ;* to fudge.
  635. ;;;;    cmp    dx,SEG _dummy_pckb_isr    ;is int9 = our dummy handler ?
  636.         cmp     dx,_codeseg
  637.     jne    fudge_5
  638.     cmp    di,OFFSET _dummy_pckb_isr
  639.     jne    fudge_5            ;no
  640.  
  641.     mov    _fudge_factor,0
  642.     mov    WORD PTR _fudge_isr_addr,di      ;yes, remove old app's 
  643.     mov    WORD PTR _fudge_isr_addr+2,dx    ; handler
  644.     jmp    fudge_50                ;go exit
  645.  
  646. ;* If int9 handler is same as last time, then no need 
  647. ;* to fudge.
  648.  
  649. fudge_5:
  650.     mov    _fudge_factor,1        ;set flag so int9 gets called
  651.     cmp    dx,WORD PTR _fudge_isr_addr+2    ;is int9 = same as last time?
  652.     jne    fudge_10
  653.     cmp    di,WORD PTR _fudge_isr_addr
  654.     je    fudge_50        ;yes, skip fudge
  655.                     ;no, fudge it
  656. fudge_10:
  657.     mov    WORD PTR _fudge_isr_addr,di      ;save fudge addr so we only
  658.     mov    WORD PTR _fudge_isr_addr+2,dx    ; do it once
  659.     call    _clear_bios_buffer
  660.  
  661.     mov    cx,100h            ;limit our search
  662. fudge_15:
  663.     mov    al,BYTE PTR cs:in60    ;IN AL  instruction
  664.  
  665.     REPNZ    scasb            ;find 'IN AL'
  666.     jnz    fudge_50        ;no good, just exit
  667.  
  668.     mov    al,BYTE PTR cs:in60+1    ;rest of IN AL,60 instruction
  669.     scasb
  670.     jnz    fudge_30        ;this wasn't it
  671.  
  672. fudge_20:            ;found it, now replace it
  673.     dec    di            ;backup pointer to instruction
  674.     dec    di
  675.  
  676.     mov    _fudge_addr,di        ;DIAGNOSTICS
  677.     inc    _fudge_count        ;DIAGNOSTICS
  678.  
  679.     mov    al,BYTE PTR cs:int60    ;Int 60h instruction
  680.     stosb                ;substitute it
  681.     mov    al,BYTE PTR cs:int60+1
  682.     stosb
  683. fudge_30:
  684.     or    cx,cx            ;hit our limit?
  685.     jnz    fudge_15        ;not yet, try again
  686.  
  687. fudge_50:                ;exit
  688.     mov    ax,_fudge_factor
  689.     pop    di
  690.     pop    es
  691.     pop    bp
  692.     ret
  693.  
  694.             ;These don't execute, they are data
  695. in60:    in    al,60h        ;the instruction we're looking for
  696. int60:    int    60h        ;the substitute instruction
  697. scode:    db    0        ;scan code gets stored here
  698.  
  699. _fudge    ENDP
  700.  
  701.  
  702.  
  703. ;+
  704. ;***************************************************************
  705. ; Name: int60_isr()
  706. ; Entry: void
  707. ; Exit:  unsigned
  708. ;
  709. ; Function: Int 60h handler
  710. ;    Returns the scan code stored in scode
  711. ;    in AL to fake the Int 9 handler into thinking it came 
  712. ;    from the PC keyboard.
  713. ;***************************************************************
  714. ;-
  715.     PUBLIC    _int60_isr
  716. _int60_isr    PROC    FAR
  717.  
  718.     in    al,pc_k_data    ;check for keystroke on real keyboard
  719.     test    al,KS_OBF
  720.     jz    i6_20        ;no key, skip read
  721.  
  722.                 ;Must have gotten here through hardware
  723.                 ; keyboard interrupt (IRQ1 = int9)
  724.     in    al,pc_k_data    ;clear standard keyboard
  725.  
  726. i6_20:
  727.     mov    al,BYTE PTR CS:scode    ;get scan code
  728.  
  729.     iret                ;return to int 9 handler
  730.  
  731. _int60_isr    ENDP
  732.  
  733.  
  734. ;+
  735. ;**********************************************************
  736. ; name: dummy_pckb_isr();
  737. ; return type: void
  738. ; entry type: void
  739. ;
  740. ; function: dummy interrupt service routine for the standard
  741. ;        PC keyboard
  742. ;**********************************************************
  743. ;-
  744.  
  745.     PUBLIC _dummy_pckb_isr 
  746. _dummy_pckb_isr    PROC    FAR
  747.  
  748.         push    ax
  749.         in      al,pc_k_data    ;clear key from keyboard
  750.         mov     al,EOI
  751.         out     EOI_MASTER,al    ;clear irq
  752.         pop     ax
  753.     iret            ;return from interrupt
  754.  
  755. _dummy_pckb_isr    ENDP
  756.  
  757.  
  758. ;+
  759. ;**********************************************************
  760. ;* name: int9()
  761. ;* return type:  int
  762. ;* entry type:   void
  763. ;*
  764. ;* function: generate interrupt 0x09 - Standard Keyboard
  765. ;*        hardware interupt service routine
  766. ;**********************************************************
  767. ;-
  768.  
  769.         PUBLIC  _int9
  770. _int9   PROC    NEAR
  771.         int     9h        ;do the interrupt
  772.         ret
  773.  
  774. _int9   ENDP
  775.  
  776.  
  777. ENDIF                ;end conditional fudge routines
  778.  
  779.  
  780. _TEXT   ENDS
  781.         END
  782.  
  783. ;--- end of kbstuff.asm ---
  784.