; kernel controlled device drivers
%pragma once
bits 16

; PIC
%define cmd1        0x20
%define cmd2        0xa0
%define data1       (cmd1+1)
%define data2       (cmd2+1)
%define casquade    2
%define icw4        0x01
%define single      0x02
%define interval    0x04
%define level       0x08
%define initpic     0x10
%define i8086       0x01
%define auto        0x02
%define slave       0x08
%define master      0x0c
%define sfnm        0x10
%define endofint    0x20

; PIT timer
%define pit0        0x40
%define pitcmd      0x43


; out8 :: int8 port -> int8 val -> void
%macro out8 2
    mov byte al,%2
    out byte %1,al
%endmacro

%macro iowait 0
    out8 0x80,0x00
%endmacro

; picinit :: void -> void
picinit:
    enter 0,0

    xor ax,ax
    out8 cmd1,(initpic|icw4)
    iowait
    out8 cmd2,(initpic|icw4)
    iowait

    ; out8 data1,14
    out8 data1,240
    iowait
    ; out8 data2,22
    out8 data2,230
    iowait

    out8 data1,(1<<casquade)
    iowait
    out8 data2,casquade
    iowait

    out8 data1,i8086
    iowait
    out8 data2,i8086
    iowait

    ; unmask
    out8 data1,0
    out8 data2,0

    xor ax,ax
    clc
    leave
    ret

; __eoi :: int8 irq -> void
__eoi:
    enter 0,0

    mov ax,[bp+4]       ; ax=irq
    and ax,0b1111

    cmp al,8
    jl .pic1
 .pic2:
    out8 cmd2,endofint
 .pic1:
    out8 cmd1,endofint

    xor ax,ax
    clc
    leave
    ret

; pitinit :: void -> void
pitinit:
    enter 0,0

    out8 pitcmd,0b00110100
    out8 pit0,0xff
    out8 pit0,0xff

    xor ax,ax
    clc
    leave
    ret

; pitisr :: int8 irq -> void
pitisr:
    enter 0,0
    push bx

    mov bx,[bp+4]       ; bx=irq
    pfln "Tick from IRQ %d",bx
    call tick
    ; call printticks
    eoi(bx)

    pop bx
    xor ax,ax
    clc
    leave
    ret

; tick :: void -> void
tick:
    enter 0,0
    push bx

    chseg(ds,csselector)
        mov bx,confseg.ticks

        ; ticks = 0xdddd'cccc'bbbb'aaaa

     .a:
        inc word ds:[bx+0]
        jnc .end
     .b:
        inc word ds:[bx+2]
        jnc .end
     .c:
        inc word ds:[bx+4]
        jnc .end
     .d:
        inc word ds:[bx+6]
     .end:
    sret(ds)

    pop bx
    xor ax,ax
    clc
    leave
    ret

; printticks :: void -> void
printticks:
    %assign stack 4
    enter stack,0
    %define Hi bp-2
    %define Lo bp-4
    push bx

    chseg(ds,csselector)
        mov bx,confseg.ticks
        mov word ax,ds:[bx+0]
        mov word ss:[Lo],ax
        
        mov word ax,ds:[bx+2]
        mov word ss:[Hi],ax
    sret(ds)

    pf "ticks = 0x%x",ss:[Hi]
    pfln "%x",ss:[Lo]
    
    ; ax =
    ;   callhandlers(EventTick)
    
    pop bx
    add sp,stack
    xor ax,ax
    clc
    leave
    ret

; mstick :: void -> void
mstick:
    enter 0,0
    
    %assign stack 4
    enter stack,0
    %define Hi bp-2
    %define Lo bp-4
    push bx

    chseg(ds,csselector)
        mov bx,confseg.msticks
        mov word ax,ds:[bx+0]
        mov word ss:[Lo],ax
        
        mov word ax,ds:[bx+2]
        mov word ss:[Hi],ax
    sret(ds)

    pf "ticks = 0x%x",ss:[Hi]
    pfln "%x",ss:[Lo]
    
    ; ax =
    ;   callhandlers(MsEventTick)
    
    pop bx
    add sp,stack
    xor ax,ax
    clc
    leave
    ret
