0,0 → 1,278 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; 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 |
|
DEBUGF 1, "K : Attach Interrupt %d Handler %x\n", [irq], [handler] |
|
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 |
|
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. |
push ebp |
xor ebp, ebp |
.try_other_irqs: |
cmp ebp, [esp] |
jz .try_next_irq |
cmp ebp, 1 |
jz .try_next_irq |
cmp ebp, 6 |
jz .try_next_irq |
cmp ebp, 12 |
jz .try_next_irq |
cmp ebp, 14 |
jz .try_next_irq |
cmp ebp, 15 |
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 |
|