$Revision: 434 $
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;                                                              ;;
;; Copyright (C) KolibriOS team 2004-2007. All rights reserved. ;;
;; Copyright (C) MenuetOS 2000-2004 Ville Mikael Turjanmaa      ;;
;; Distributed under terms of the GNU General Public License    ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; IRQ0 HANDLER (TIMER INTERRUPT) ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

align 32
irq0:
        save_ring3_context
	mov   ax, os_data
	mov   ds, ax
	mov   es, ax

        inc   dword [timer_ticks]

        mov   eax, [timer_ticks]
        call  playNote           ; <<<--- Speaker driver

        cmp   eax,[next_usage_update]
        jb    .nocounter
        add   eax,100
        mov   [next_usage_update],eax
        call  updatecputimes
     .nocounter:

        cmp   [DONT_SWITCH], byte 1
        jne   .change_task

        mov   al,0x20   ; send End Of Interrupt signal
        mov   dx,0x20
        out   dx,al

        mov   [DONT_SWITCH], byte 0

        restore_ring3_context
        iret

     .change_task:
        call  update_counters

        call  find_next_task
        mov   ecx, eax

        mov   al,0x20   ; send End Of Interrupt signal
        mov   dx,0x20
        out   dx,al

	test  ecx, ecx  ; if there is only one running process
        jnz   .return

        call  do_change_task

     .return:
        restore_ring3_context
        iret


align 4
change_task:

        pushfd
        cli
        pushad

        call  update_counters
; \begin{Mario79}
        cmp     [dma_task_switched], 1
        jne     .find_next_task
        mov     [dma_task_switched], 0
        mov     ebx, [dma_process]
        cmp     [CURRENT_TASK], ebx
        je      .return
        mov     edi, [dma_slot_ptr]
        mov     [CURRENT_TASK], ebx
        mov     [TASK_BASE], edi
        jmp     @f
.find_next_task:
; \end{Mario79}
        call  find_next_task
        test  eax, eax    ; the same task -> skip switch
        jnz    .return
@@:
        mov   [DONT_SWITCH],byte 1
        call  do_change_task

     .return:
        popad
        popfd

        ret


uglobal
   align 4
   far_jump:
    .offs dd ?
    .sel  dw ?
   context_counter     dd ? ;noname & halyavin
   next_usage_update   dd ?
   timer_ticks         dd ?
   prev_slot           dd ?
   event_sched         dd ?
endg


update_counters:
        mov   edi, [TASK_BASE]
        mov   ebx, [edi+TASKDATA.counter_add] ; time stamp counter add
        call  _rdtsc
        sub   eax, ebx
        add   eax, [edi+TASKDATA.counter_sum] ; counter sum
        mov   [edi+TASKDATA.counter_sum], eax
ret


; Find next task to execute
; result: ebx = number of the selected task
;         eax = 1  if the task is the same
;         edi = address of the data for the task in ebx
;         [0x3000] = ebx and [0x3010] = edi
;         corrupts other regs
find_next_task:
        mov   ebx, [CURRENT_TASK]
        mov   edi, [TASK_BASE]
        mov   [prev_slot], ebx

      .waiting_for_termination:
      .waiting_for_reuse:
      .waiting_for_event:
      .suspended:
        cmp   ebx, [TASK_COUNT]
        jb    @f
        mov   edi, CURRENT_TASK
        xor   ebx, ebx
      @@:

        add   edi,0x20
        inc   ebx

        mov   al, byte [edi+TASKDATA.state]
        test  al, al
        jz    .found
	cmp   al, 1
	jz    .suspended
	cmp   al, 2
	jz    .suspended
        cmp   al, 3
        je    .waiting_for_termination
        cmp   al, 4
        je    .waiting_for_termination
        cmp   al, 9
        je    .waiting_for_reuse

        mov   [CURRENT_TASK],ebx
        mov   [TASK_BASE],edi
        push    ebx
        shl     ebx, 8
        mov     ebx, [SLOT_BASE + ebx + APPDATA.pl0_stack]
        add     ebx, RING0_STACK_SIZE
        mov     [CURRENT_RING0_ESP], ebx
        pop     ebx

        cmp   al, 5
        jne   .noevents
        call  get_event_for_app
        test  eax, eax
        jz    .waiting_for_event
        mov   [event_sched], eax
        mov   [edi+TASKDATA.state], byte 0
      .noevents:
      .found:
        mov   [CURRENT_TASK],ebx
        mov   [TASK_BASE],edi
        call  _rdtsc
        mov   [edi+TASKDATA.counter_add],eax

	xor   eax, eax
        cmp   ebx, [prev_slot]
        sete  al
ret

; in: ebx = TSS selector index
do_change_task:
        shl   ebx, 3
        xor   eax, eax
        add   ebx, tss0
        mov   [far_jump.sel],  bx   ; selector
        mov   [far_jump.offs], eax  ; offset
        jmp   pword [far_jump]
        inc   [context_counter] ;noname & halyavin
ret



align 4
updatecputimes:

        mov  eax,[idleuse]
        mov  [idleusesec],eax
        mov  [idleuse],dword 0
        mov  ecx, [TASK_COUNT]
        mov  edi, TASK_DATA
      .newupdate:
        mov  ebx,[edi+TASKDATA.counter_sum]
        mov  [edi+TASKDATA.cpu_usage],ebx
        mov  [edi+TASKDATA.counter_sum],dword 0
        add  edi,0x20
        dec  ecx
        jnz  .newupdate

        ret
