/*
 * ps2.h
 *
 * Copyright (C) 2016 Aleksandar Andrejevic <theflash@sdf.lonestar.org>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef _PS2_H_
#define _PS2_H_

#include <common.h>
#include <device.h>

#define PS2_STATUS_PORT  0x64
#define PS2_CONTROL_PORT 0x64
#define PS2_DATA_PORT    0x60

#define PS2_TIMEOUT 500
#define PS2_MAX_RETRIES  3

#define PS2_OUTPUT_BUFFER_FULL (1 << 0)
#define PS2_INPUT_BUFFER_FULL  (1 << 1)

#define PS2_CMD_READ_CONFIG         0x20
#define PS2_CMD_WRITE_CONFIG        0x60
#define PS2_CMD_DISABLE_SECOND_PORT 0xA7
#define PS2_CMD_ENABLE_SECOND_PORT  0xA8
#define PS2_CMD_TEST_SECOND_PORT    0xA9
#define PS2_CMD_TEST_CONTROLLER     0xAA
#define PS2_CMD_TEST_FIRST_PORT     0xAB
#define PS2_CMD_DISABLE_FIRST_PORT  0xAD
#define PS2_CMD_ENABLE_FIRST_PORT   0xAE
#define PS2_CMD_SEND_TO_SECONDARY   0xD4

#define PS2_DEVICE_CMD_SCANCODE_SET 0xF0
#define PS2_DEVICE_CMD_IDENTIFY     0xF2
#define PS2_DEVICE_CMD_ENABLE_SCAN  0xF4
#define PS2_DEVICE_CMD_DISABLE_SCAN 0xF5
#define PS2_DEVICE_CMD_RESET        0xFF

#define PS2_DEVICE_BAT_SUCCESS      0xAA
#define PS2_DEVICE_RESPONSE_ACK     0xFA
#define PS2_DEVICE_RESPONSE_FAILURE 0xFC
#define PS2_DEVICE_RESPONSE_RESEND  0xFE

#define PS2_FIRST_IRQ  1
#define PS2_SECOND_IRQ 12

#define PS2_BUFFER_CAPACITY 4096

typedef enum
{
    PS2_DEVICE_KEYBOARD,
    PS2_DEVICE_MOUSE
} ps2_device_type_t;

typedef struct
{
    device_t header;
    byte_t port;
    ps2_device_type_t type;
    lock_t buffer_lock;
    dword_t buffer_start, buffer_end;
} ps2_device_t;

typedef struct
{
    ps2_device_t header;
    word_t buffer[PS2_BUFFER_CAPACITY];
} ps2_keyboard_t;

typedef struct
{
    int32_t delta_x;
    int32_t delta_y;
    dword_t flags;
} ps2_mouse_packet_t;

typedef struct
{
    ps2_device_t header;
    int phase;
    byte_t unfinished_packet[5];
    ps2_mouse_packet_t buffer[PS2_BUFFER_CAPACITY];
} ps2_mouse_t;

#endif
