kolibrios/kernel/trunk/core/irq.inc
CleverMouse 30b17fb697 allow high-priority threads to wakeup after any IRQ, not just timer
git-svn-id: svn://kolibrios.org@3615 a494cfbc-eb01-0410-851d-a64ba20cac60
2013-06-07 16:46:52 +00:00

298 lines
6.6 KiB
PHP

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2012. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
IRQ_RESERVED equ 24
IRQ_POOL_SIZE equ 48
uglobal
align 16
irqh_tab rd sizeof.LHEAD * IRQ_RESERVED / 4
irqh_pool rd sizeof.IRQH * IRQ_POOL_SIZE /4
next_irqh rd 1
irq_active_set rd 1
irq_failed rd IRQ_RESERVED
endg
align 4
init_irqs:
mov ecx, IRQ_RESERVED
mov edi, irqh_tab
@@:
mov eax, edi
stosd
stosd
loop @B
mov ecx, IRQ_POOL_SIZE-1
mov eax, irqh_pool+sizeof.IRQH
mov [next_irqh], irqh_pool
@@:
mov [eax-sizeof.IRQH], eax
add eax, sizeof.IRQH
loop @B
mov [eax-sizeof.IRQH], dword 0
ret
align 4
proc attach_int_handler stdcall, irq:dword, handler:dword, user_data:dword
locals
.irqh dd ?
endl
and [.irqh], 0
push ebx
mov ebx, [irq] ;irq num
test ebx, ebx
jz .err
cmp ebx, IRQ_RESERVED
jae .err
mov edx, [handler]
test edx, edx
jz .err
spin_lock_irqsave IrqsList
;allocate handler
mov ecx, [next_irqh]
test ecx, ecx
jz .fail
mov eax, [ecx]
mov [next_irqh], eax
mov [.irqh], ecx
mov [irq_failed+ebx*4], 0;clear counter
mov eax, [user_data]
mov [ecx+IRQH.handler], edx
mov [ecx+IRQH.data], eax
and [ecx+IRQH.num_ints], 0
lea edx, [irqh_tab+ebx*8]
list_add_tail ecx, edx ;clobber eax
stdcall enable_irq, ebx
.fail:
spin_unlock_irqrestore IrqsList
.err:
pop ebx
mov eax, [.irqh]
ret
endp
if 0
align 4
proc get_int_handler stdcall, irq:dword
mov eax, [irq]
cmp eax, 15
ja .fail
mov eax, [irq_tab + 4 * eax]
ret
.fail:
xor eax, eax
ret
endp
end if
align 4
proc detach_int_handler
ret
endp
macro irq_serv_h [num] {
forward
align 4
.irq_#num :
push num
jmp .main
}
align 16
irq_serv:
; .irq_1:
; push 1
; jmp .main
; etc...
irq_serv_h 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 15
irq_serv_h 16, 17, 18, 19, 20, 21, 22, 23
purge irq_serv_h
align 16
.main:
save_ring3_context
mov ebp, [esp + 32]
mov bx, app_data;os_data
mov ds, bx
mov es, bx
cmp [v86_irqhooks+ebp*8], 0
jnz v86_irq
cmp bp, 6
jnz @f
push ebp
call [fdc_irq_func]
pop ebp
@@:
cmp bp, 14
jnz @f
push ebp
call [irq14_func]
pop ebp
@@:
cmp bp, 15
jnz @f
push ebp
call [irq15_func]
pop ebp
@@:
bts [irq_active_set], ebp
lea esi, [irqh_tab+ebp*8] ; esi= list head
mov ebx, esi
.next:
mov ebx, [ebx+IRQH.list.next]; ebx= irqh pointer
cmp ebx, esi
je .done
push ebx ; FIX THIS
push edi
push esi
push [ebx+IRQH.data]
call [ebx+IRQH.handler]
pop ecx
pop esi
pop edi
pop ebx
test eax, eax
jz .next
inc [ebx+IRQH.num_ints]
btr [irq_active_set], ebp
jmp .next
.done:
btr [irq_active_set], ebp
jnc .exit
; There is at least one configuration with one device which generates IRQ
; that is not the same as it should be according to PCI config space.
; For that device, the handler is registered at wrong IRQ.
; As a workaround, when nobody acknowledges the generated IRQ,
; try to ask all other registered handlers; if some handler acknowledges
; the IRQ this time, relink it to the current IRQ list.
; To make this more reliable, for every handler keep number of times
; that it has acknowledged an IRQ, and assume that handlers with at least one
; acknowledged IRQ are registered properly.
; Note: this still isn't 100% correct, because two IRQs can fire simultaneously,
; the better way would be to find the correct IRQ, but I don't know how to do
; this in that case.
; Also, [fdc_irq_func], [irq14_func], [irq15_func] could process interrupt
; but do not return whether they did it, so just ignore IRQs 6, 14, 15.
cmp ebp, 6
jz .fail
cmp ebp, 14
jz .fail
cmp ebp, 15
jz .fail
push ebp
xor ebp, ebp
.try_other_irqs:
cmp ebp, [esp]
jz .try_next_irq
cmp ebp, 1
jz .try_next_irq
cmp ebp, 12
jz .try_next_irq
lea esi, [irqh_tab+ebp*8]
mov ebx, esi
.try_next_handler:
mov ebx, [ebx+IRQH.list.next]
cmp ebx, esi
je .try_next_irq
cmp [ebx+IRQH.num_ints], 0
jne .try_next_handler
; keyboard handler acknowledges everything
push [ebx+IRQH.data]
call [ebx+IRQH.handler]
pop ecx
test eax, eax
jz .try_next_handler
.found_in_wrong_list:
DEBUGF 1,'K : warning: relinking handler from IRQ%d to IRQ%d\n',\
ebp, [esp]
pop ebp
spin_lock_irqsave IrqsList
list_del ebx
lea edx, [irqh_tab+ebp*8]
list_add_tail ebx, edx
spin_unlock_irqrestore IrqsList
jmp .exit
.try_next_irq:
inc ebp
cmp ebp, 16
jb .try_other_irqs
pop ebp
.fail:
inc [irq_failed+ebp*4]
.exit:
mov ecx, ebp
call irq_eoi
; IRQ handler could make some kernel thread ready; reschedule
mov bl, SCHEDULE_HIGHER_PRIORITY
call find_next_task
jz .return ; if there is only one running process
call do_change_task
.return:
restore_ring3_context
add esp, 4
iret
align 4
irqD:
push eax
push ecx
xor eax, eax
out 0xf0, al
mov cl, 13
call irq_eoi
pop ecx
pop eax
iret