;
;       TCtask - Timer interrupt handler (IBM specific)
;
;       V1.1    T.Wagner
;       V1.2    TECON Ltd.
;
        name    tctim
;        .model  large
;
        public  tsk_install_timer_
        public  tsk_remove_timer_
;        public  _tsk_chain_timer
;
        include tsk.mac
;
timer   equ     40h                     ; 8253 timer base I/O address
inta00  equ     20h                     ; 8259 int controller base
eoi     equ     20h                     ; unspecific EOI

tint=8h

        .data
;
        extrn   _tsk_timer_counter:word
;        extrn   _tsk_int9_counter:word
;
divisor         dw      ?
timcnt          dw      ?
sys_ticks       dw      ?
timflag         dw      ?
stat_int        db      ?

;        .code
;
        extrn   _sched_int:near
        extrn   inc_counter_:near
;
timer_save      label   fword           ; in CSEG to allow addressing
tsofs           dd      ?
tsseg           dw      ?
;
        .code
;----------------------------------------------------------------------
;
;       timer interrupt handler
;
timer_int       proc
        push    ds
        push    eax
        mov     ax,seg timflag
        mov     ds,ax

        mov     al,eoi                  ; issue EOI
        out     inta00,al
        mov     al,0bh                     ; access int control reg
        out     inta00,al
        in      al,inta00                  ; ints pending?
        mov     ds:stat_int,al

        dec     ds:timcnt                ; decrement tick count
        jne     no_pass                 ; pass on this int if zero
        mov     ax,ds:sys_ticks
        mov     ds:timcnt,ax               ; re-init tick counter
        pop     eax
        pop     ds

        pushfd
        call fword ptr cs:timer_save

        push    ds
        push    eax
no_pass:

        cli
;        push    ds
;        push    eax
        mov     ax,seg timflag
        mov     ds,ax
;
        cmp     timflag,1               ; initialisation ?
        jne     no_init
;
;       Install timer
;

        mov     timcnt,1
        mov     timflag,0               ; signal init ready

        mov     al,36h
        out     timer+3,al              ; setup to load divisor
        mov     al,byte ptr divisor
        out     timer,al                ; lsb
        mov     al,byte ptr divisor+1
        out     timer,al                ; msb
        jmp     short no_uninit
;
no_init:
        cmp     timflag,2               ; un-install flag set?
        jne     no_uninit               ; no un-install if not
        jmp     uninit
;
;--------------------------------------------------------------------
;
;       Normal timer tick. The tick counter is incremented, and
;       the interrupt controller is checked for other pending interrupts.
;       If the timer tick occurred during processing of another interrupt,
;       we may not call the scheduler, since this would delay the
;       interrupt handler.
;
;       Note that an EOI is issued here to allow interrupts to occur
;       during further processing. The original INT 9 handler will be
;       chained to from a special task. The reason behind this is that
;       some TSR's link into the timer interrupt and may do some lengthy
;       processing there. To allow the TSR to be preempted, we must use
;       a task for the INT 9 processing.
;
no_uninit:
        sti
        mov     eax,offset _tsk_timer_counter
        call    inc_counter_            ; increase timer tick counter

        mov     al,stat_int
        or      al,al
        pop     eax
        jnz     no_sch                  ; don't schedule if other ints active
        sti
        jmp     _sched_int              ; else schedule
;
no_sch:
        pop     ds
        iretd
;
;------------------------------------------------------------------------
;
;       Uninstall timer int handler
;
uninit:
        mov     timflag,0               ; mark un-install complete

        mov     al,36h                  ; setup to load divisor
        out     timer+3,al
        mov     al,0                    ; divisor 0 means 65536
        out     timer,al                ; lsb
        out     timer,al                ; msb

        mov     bl,tint
        mov     ax,205h                  ;“áâ ­®¢ª  ¢¥ªâ®à  8 ­  DS:EDX
        mov     edx, tsofs
        mov     cx, tsseg
        int     31h
        pop     eax
        pop     ds
        jmp     fword ptr [timer_save]       ; pass on interrupt
;
timer_int       endp
;
;----------------------------------------------------------------------
;
;       void far tsk_chain_timer (void)
;
;       Pass timer tick on to interrupt 9 chain.
;
;_tsk_chain_timer        proc
;
;        pushfd
;        cli
;        call    fword ptr [timer_save]
;        ret
;
;_tsk_chain_timer        endp
;
;
;       void far tsk_install_timer (word divisor, word sys_ticks)
;
;       This routine installs the timer tick int handler.
;       The timer chip is reprogrammed on the next tick.
;
tsk_install_timer_      proc
;
        push    eax
        push    ebx
        push    edx
        push    ecx

        mov     divisor,ax
        mov     sys_ticks,dx

        mov     timflag,1               ; set init-flag
        mov     bl,tint
        mov     ax,204h                 ;—⥭¨¥ ¢¥ªâ®à  ¯à¥à뢠­¨ï 8 = es:ebx
        int     31h
        mov     tsofs,edx
        mov     tsseg,cx

        cli
        mov     bl,tint
        mov     ax,205h                  ;“áâ ­®¢ª  ¢¥ªâ®à  8 ­  DS:EDX
        mov     edx,offset timer_int
        mov     cx,cs
        int     31h
        sti
wait_set:
        cmp     timflag,0               ; wait until timer started
        jne     wait_set
        pop     ecx
        pop     edx
        pop     ebx
        pop     eax
        ret
;
tsk_install_timer_      endp
;
;
;       void far tsk_remove_timer (void)
;
;       This routine un-installs the timer tick int handler.
;       The timer chip is reprogrammed & the interrupt vector
;       restored when the system tick count reaches zero.
;
tsk_remove_timer_       proc
;
        mov     timflag,2               ; set un-init flag for timer
wait_tim:
        sti                             ; just to be safe
        cmp     timflag,0               ; wait until int un-installed
        jne     wait_tim
        ret
;
tsk_remove_timer_       endp
;
        end