        xor     ax,ax
	int	33h
	cmp	ax,0ffffh
        jmp     not_loaded

	mov	ah,9
	mov	dx,offset already_loaded
	int	21h

	mov	ax,4c01h
	int	21h

not_loaded:

        mov	ah,9
        mov	dx,offset intro_string
        int	21h

        mov	ax,2574h
        mov	dx,offset new_isr
        int	21h

        mov	ax,2533h
        mov	dx,offset new_33
        int	21h

        cli

        mov	bl,0a8h
        call	keyboard_cmd

        mov	bl,20h
        call    keyboard_cmd
        call    keyboard_read
        or      al,2
        mov     bl,60h
        push    ax
        call    keyboard_cmd
        pop     ax
        call    keyboard_write

        mov     bl,0d4h
        call    keyboard_cmd
        mov     al,0f4h
        call    keyboard_write

        sti

        mov     dx,offset end_of_tsr
        int     27h

intro_string    db 0dh,0ah,'DPSMouseDRV (c) 1998',0dh,0ah,'$'
already_loaded  db 0dh,0ah,'Mouse driver already loaded!',0dh,0ah,'$'

call_user_isr:
        db      60h
        mov     cx,cs:[pos_x]
        mov     dx,cs:[pos_y]
        mov     di,0 ;cs:[x_move]
        mov     si,0 ;cs:[y_move]
        mov     w[cs:x_move],0
        mov     w[cs:y_move],0
        mov     bl,cs:[buttons]
        xor     bh,bh
        call    dword ptr cs:[user_subroutine]
        db      61h
        ret

new_isr:
        pushf
        cli
        push    ax
        push    bx
        push    cx
        push    dx
        push    di
        push    si
        push    es
        push    ds

        push    cs
        pop     ds

        mov     bl,0adh
        call    keyboard_cmd

        cmp     b[first_time],0
        je      not_first_time

        mov     b[first_time],0
        call    keyboard_read
        call    keyboard_read
        call    keyboard_read
        jmp     no_show

not_first_time:
        mov     w[temp_mask],0

        mov     cx,word ptr [offset pos_x]
        mov     dx,word ptr [offset pos_y]

        call    keyboard_read
        and     al,7 ;3
        mov     ah,[buttons]
        mov     [buttons],al
        cmp     al,ah
        je      no_button_change
        and     al,3
        and     ah,3
        xor     al,ah
        xor     bx,bx

        push    ax
        test    al,2
        jz      no_right_button_change
        and     ah,2
        jz      right_button_pressed
        or      bx,16
        jmp     no_right_button_change
right_button_pressed:
        or      bx,8
no_right_button_change:

        pop     ax

        test    al,1
        jz      no_left_button_change
        and     ah,1
        jz      left_button_pressed
        or      bx,4
        jmp     no_left_button_change
left_button_pressed:
        or      bx,2
no_left_button_change:

        mov     [temp_mask],bx

no_button_change:
        call    keyboard_read
        cbw
        add     word ptr [pos_x],ax
        add     word ptr [x_move],ax
        mov     ax,[x_min]
        cmp     word ptr [pos_x],ax
        jg      good_hor1
        mov     word ptr [pos_x],ax
good_hor1:
        mov     ax,[x_max]
        cmp     word ptr [pos_x],ax
        jle     good_hor2
        mov     word ptr [pos_x],ax
good_hor2:

        call    keyboard_read
        neg     al
        cbw
        add     word ptr [pos_y],ax
        add     word ptr [y_move],ax
        mov     ax,[y_min]
        cmp     word ptr [pos_y],ax
        jg      good_ver1
        mov     word ptr [pos_y],ax
good_ver1:
        mov     ax,[y_max]
        cmp     word ptr [pos_y],ax
        jle     good_ver2
        mov     word ptr [pos_y],ax
good_ver2:

        mov     ax,[x_move]
        or      ax,[y_move]
        or      ax,ax
        jz      no_change_position
        or      w[temp_mask],1
no_change_position:

        mov     ax,[temp_mask]
        and     ax,[user_mask]
        jz      no_call_user
        call    call_user_isr
no_call_user:

        cmp     byte ptr [sm_flag],1
        jne     no_show

        shr     cx,3
        shr     dx,3
        mov     ax,80
        mul     dl
        add     ax,cx
        shl     ax,1
        mov     di,ax
        mov     ax,0b800h
        mov     es,ax
        mov     ax,word ptr [offset save_char]
        stosw

        mov     cx,word ptr [offset pos_x]
        mov     dx,word ptr [offset pos_y]
        shr     cx,3
        shr     dx,3
        mov     ax,80
        mul     dl
        add     ax,cx
        shl     ax,1
        mov     di,ax
        mov     ax,0b800h
        mov     es,ax
        mov     ax,word ptr es:[di]
        mov     word ptr [offset save_char],ax
        not     ah
        and     ah,7fh
        stosw
no_show:
        mov     bl,0aeh
        call    keyboard_cmd

        mov     al,20h
        out     0a0h,al
        out     20h,al

        pop     ds
        pop     es
        pop     si
        pop     di
        pop     dx
        pop     cx
        pop     bx
        pop     ax
        popf
        iret

first_time      db      1
buttons         db      0
pos_x           dw      0
pos_y           dw      0
sm_flag         dw      0
save_char       dw      0
x_move          dw      0
y_move          dw      0
x_max           dw      639
x_min           dw      0
y_max           dw      199
y_min           dw      0
user_subroutine dw      0,0
user_mask       dw      0
temp_mask       dw      0

keyboard_read:
        push    cx
        push    dx
        xor     cx,cx
key_read_loop:
        in      al,64h
        jmp     $+2
        jmp     $+2
        test    al,1
        jnz     key_read_ready
        loop    key_read_loop
        mov     ah,1
        jmp     key_read_exit
key_read_ready:
        push    cx
        mov     cx,32
key_read_delay:
        jmp     $+2
        jmp     $+2
        loop    key_read_delay

        pop     cx

        in      al,60h
        jmp     $+2
        jmp     $+2
        xor     ah,ah
key_read_exit:
        pop     dx
        pop     cx
        ret

keyboard_write:
        push    cx
        push    dx
        mov     dl,al
        xor     cx,cx
kbd_wrt_loop1:
        in      al,64h
        jmp     $+2
        jmp     $+2
        test    al,20h
        jz      kbd_wrt_ok1

        loop    kbd_wrt_loop1

        mov     ah,1
        jmp     kbd_wrt_exit

kbd_wrt_ok1:
        in      al,60h

        xor     cx,cx
kbd_wrt_loop:
        in      al,64h
        jmp     $+2
        jmp     $+2
        test    al,2
        jz      kbd_wrt_ok

        loop    kbd_wrt_loop

        mov     ah,1
        jmp     kbd_wrt_exit

kbd_wrt_ok:
        mov     al,dl
        out     60h,al
        jmp     $+2
        jmp     $+2

        xor     cx,cx
kbd_wrt_loop3:
        in      al,64h
        jmp     $+2
        jmp     $+2
        test    al,2
        jz      kbd_wrt_ok3

        loop    kbd_wrt_loop3

        mov     ah,1
        jmp     kbd_wrt_exit

kbd_wrt_ok3:
        mov     ah,8
kbd_wrt_loop4:
        xor     cx,cx
kbd_wrt_loop5:
        in      al,64h
        jmp     $+2
        jmp     $+2
        test    al,1
        jnz     kbd_wrt_ok4

        loop    kbd_wrt_loop5

        dec     ah
        jnz     kbd_wrt_loop4

kbd_wrt_ok4:
        xor     ah,ah
kbd_wrt_exit:
        pop     dx
        pop     cx
        ret
        
keyboard_cmd:
        xor     cx,cx
cmd_wait:
        in      al,64h
        jmp     $+2
        jmp     $+2
        test    al,2
        jz      cmd_send
        loop    cmd_wait

        jmp     cmd_error

cmd_send:
        mov     al,bl
        out     64h,al
        jmp     $+2
        jmp     $+2

        xor     cx,cx
cmd_accept:
        in      al,64h
        jmp     $+2
        jmp     $+2
        test    al,2
        jz      cmd_ok
        loop    cmd_accept

cmd_error:
        mov     ah,1
        jmp     cmd_exit
cmd_ok:
        xor     ah,ah
cmd_exit:
        ret

new_33:
        cli
        cmp     al,0
        je      reset_mouse
        cmp     al,1
        je      show_mouse
        cmp     al,2
        je      hide_mouse
        cmp     al,3
        je      get_pos
        cmp     al,4
        je      set_pos
        cmp     al,7
        je      set_hor_pos
        cmp     al,8
        je      set_ver_pos
        cmp     al,0bh
        je      get_mouse_movement
        cmp     al,0ch
        je      set_subroutines
        cmp     al,14h
        je      swap_subroutines
        iret

reset_mouse:
        jmp     _reset_mouse
show_mouse:
        jmp     _show_mouse
hide_mouse:
        jmp     _hide_mouse
get_pos:
        jmp     _get_pos
set_pos:
        jmp     _set_pos
set_hor_pos:
        jmp     _set_hor_pos
set_ver_pos:
        jmp     _set_ver_pos
get_mouse_movement:
        jmp     _get_mouse_movement
set_subroutines:
        jmp     _set_subroutines
swap_subroutines:
        jmp     _swap_subroutines

_reset_mouse:
        mov     b[cs:offset buttons],0
        mov     w[cs:offset pos_x],0
        mov     w[cs:offset pos_y],0
        mov     w[cs:offset x_move],0
        mov     w[cs:offset y_move],0
        mov     w[cs:offset x_max],639
        mov     w[cs:offset x_min],0
        mov     w[cs:offset y_max],199
        mov     w[cs:offset y_min],0
        mov     w[cs:offset user_mask],0
        mov     w[cs:offset user_subroutine],0
        mov     w[cs:offset user_subroutine+2],0
        mov     ax,0ffffh
        mov     bx,3
        iret

_get_pos:
        mov     cx,word ptr cs:[offset pos_x]
        mov     dx,word ptr cs:[offset pos_y]
        mov     bx,word ptr cs:[offset buttons]
        xor     bh,bh
        iret

_get_mouse_movement:
        mov     cx,word ptr cs:[offset x_move]
        mov     dx,word ptr cs:[offset y_move]
        mov     word ptr cs:[offset x_move],0
        mov     word ptr cs:[offset y_move],0
        iret

_show_mouse:
        push    ax
        push    bx
        push    di
        push    es
        mov     byte ptr cs:[offset sm_flag],1
        mov     ax,word ptr cs:[offset pos_y]
        shr     ax,3
        mov     bl,80
        mul     bl
        mov     bx,word ptr cs:[offset pos_x]
        shr     bx,3
        add     ax,bx
        shl     ax,1
        mov     di,ax
        mov     ax,0b800h
        mov     es,ax
        mov     ax,word ptr es:[di]
        mov     cs:[offset save_char],ax
        not     ah
        and     ah,7fh
        mov     es:[di],ax
        pop     es
        pop     di
        pop     bx
        pop     ax
        iret

_hide_mouse:
        push    ax
        push    bx
        push    di
        push    es
        mov     byte ptr cs:[offset sm_flag],0
        mov     ax,word ptr cs:[offset pos_y]
        shr     ax,3
        mov     bl,80
        mul     bl
        mov     bx,word ptr cs:[offset pos_x]
        shr     bx,3
        add     ax,bx
        shl     ax,1
        mov     di,ax
        mov     ax,0b800h
        mov     es,ax
        mov     ax,word ptr cs:[offset save_char]
        mov     word ptr es:[di],ax
        pop     es
        pop     di
        pop     bx
        pop     ax
        iret

_set_pos:
        mov     cx,cs:[pos_x]
        mov     dx,cs:[pos_y]
        mov     w[cs:x_move],0
        mov     w[cs:y_move],0
        iret

_set_hor_pos:
        call    max_min
        mov     cs:[x_min],cx
        mov     cs:[x_max],dx
        cmp     cs:[pos_x],cx
        jge     good_hor_min
        mov     cs:[pos_x],cx
good_hor_min:
        cmp     cs:[pos_x],dx
        jle     good_hor_max
        mov     cs:[pos_x],dx
good_hor_max:
        iret

_set_ver_pos:
        call    max_min
        mov     cs:[y_min],cx
        mov     cs:[y_max],dx
        cmp     cs:[pos_y],cx
        jge     good_ver_min
        mov     cs:[pos_y],cx
good_ver_min:
        cmp     cs:[pos_y],dx
        jle     good_ver_max
        mov     cs:[pos_y],dx
good_ver_max:
        iret

max_min:
        cmp     cx,dx
        jle     no_swap
        xchg    cx,dx
no_swap:
        ret

_set_subroutines:
        mov     cs:[user_subroutine],dx
        mov     cs:[user_subroutine+2],es
        mov     cs:[user_mask],cx
        iret

_swap_subroutines:
        push    w[cs:user_mask]
        push    w[cs:user_subroutine+2]
        push    w[cs:user_subroutine]
        mov     cs:[user_subroutine],dx
        mov     cs:[user_subroutine+2],es
        mov     cs:[user_mask],cx
        pop     dx
        pop     es
        pop     cx
        iret

end_of_tsr:
end