#include <stdlib.h>
#include "ibm.h"
#include "mouse.h"
#include "pic.h"
#include "serial.h"
#include "timer.h"

typedef struct mouse_serial_t
{
        int mousepos;
	pc_timer_t mousedelay_timer;
        int oldb;
        SERIAL *serial;
} mouse_serial_t;

void mouse_serial_poll(int x, int y, int z, int b, void *p)
{
        mouse_serial_t *mouse = (mouse_serial_t *)p;
        SERIAL *serial = mouse->serial;        
        uint8_t mousedat[3];

        if (!(serial->ier & 1))
                return;
        if (!x && !y && b == mouse->oldb)
                return;

        mouse->oldb = b;
        if (x>127) x=127;
        if (y>127) y=127;
        if (x<-128) x=-128;
        if (y<-128) y=-128;

        /*Use Microsoft format*/
        mousedat[0]=0x40;
        mousedat[0]|=(((y>>6)&3)<<2);
        mousedat[0]|=((x>>6)&3);
        if (b&1) mousedat[0]|=0x20;
        if (b&2) mousedat[0]|=0x10;
        mousedat[1]=x&0x3F;
        mousedat[2]=y&0x3F;
        
        if (!(serial->mctrl & 0x10))
        {
//                pclog("Serial data %02X %02X %02X\n", mousedat[0], mousedat[1], mousedat[2]);
                serial_write_fifo(mouse->serial, mousedat[0]);
                serial_write_fifo(mouse->serial, mousedat[1]);
                serial_write_fifo(mouse->serial, mousedat[2]);
        }
}

void mouse_serial_rcr(struct SERIAL *serial, void *p)
{
        mouse_serial_t *mouse = (mouse_serial_t *)p;
        
        mouse->mousepos = -1;
        timer_set_delay_u64(&mouse->mousedelay_timer, TIMER_USEC * 5000);
}
        
void mousecallback(void *p)
{
        mouse_serial_t *mouse = (mouse_serial_t *)p;

        if (mouse->mousepos == -1)
        {
                mouse->mousepos = 0;
                serial_write_fifo(mouse->serial, 'M');
        }
}

void *mouse_serial_init()
{
        mouse_serial_t *mouse = (mouse_serial_t *)malloc(sizeof(mouse_serial_t));
        memset(mouse, 0, sizeof(mouse_serial_t));

        mouse->serial = &serial1;
        serial1.rcr_callback = mouse_serial_rcr;
        serial1.rcr_callback_p = mouse;
        timer_add(&mouse->mousedelay_timer, mousecallback, mouse, 0);
        
        return mouse;
}

void mouse_serial_close(void *p)
{
        mouse_serial_t *mouse = (mouse_serial_t *)p;
        
        free(mouse);
        
        serial1.rcr_callback = NULL;
}

mouse_t mouse_serial_microsoft =
{
        "Microsoft 2-button mouse (serial)",
        mouse_serial_init,
        mouse_serial_close,
        mouse_serial_poll,
        MOUSE_TYPE_SERIAL
};
