/*
BSD 3-Clause License
Copyright (c) 2024, k4m1
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __8042_KBDCTL_H__
#define __8042_KBDCTL_H__
#include <stdbool.h>
#include <drivers/device.h>
/* 8042 related definitions and declarations here. */
#define KBDCTL_DATA 0x60
#define KBDCTL_STAT 0x64
#define KBDCTL_CMD 0x64
/* Status byte bit definitions */
#define KBDCTL_STAT_OUT_BUF 0x01 // Output / input status
#define KBDCTL_STAT_IN_BUF 0x02
#define KBDCTL_STAT_SYSF 0x04 // System flag
#define KBDCTL_STAT_CD 0x08 // Command/Data, 0 = inbuf, 1 = ps2ctl
#define KBDCTL_STAT_TIMEOUT 0x40 // Timeout error (0 = good, 1 = timeout)
#define KBDCTL_STAT_PARITY 0x80 // Parity error (0 = good, 1 = timeout)
/* Configuration byte bit definitions */
#define KBDCTL_CTL_P1_IE 0x01 // PS2 Port 1 interrupts enabled
#define KBDCTL_CTL_P2_IE 0x02 // PS2 Port 2 interrupts enabled
#define KBDCTL_CTL_SF 0x04 // System Flag (Passed POST or not)
#define KBDCTL_CTL_PS1_CLKE 0x10 // First PS2 port clock enabled
#define KBDCTL_CTL_PS2_CLKE 0x20 // 2nd PS2 port clock enabled
#define KBDCTL_CTL_PS1_TE 0x40 // PS2 Port translation enabled
#define KBDCTL_DEFAULT_CONFIG_MASK 0xBC // Disable IRQs and translation
/* Controller output port bit definitions */
#define KBDCTL_CTL_OUT_SYSRST 0x01 // Pulse to reset
#define KBDCTL_CTL_OUT_A20 0x02 // A20 gate output
#define KBDCLT_CTL_OUT_P2_CLK 0x04 // Second ps2 port clock
#define KBDCTL_CTL_OUT_P2_DATA 0x08 // PS2 port data
#define KBDCTL_CTL_OUT_BUF_FULL_IRQ1 0x10 // Output buffer full @ port 1
#define KBDCTL_CTL_OUT_BUFF_FULL_IRQ2 0x20 // Output buffer full @ port 2
#define KBDCTL_CTL_OUT_P1_CLK 0x40 // First ps2 port clock
#define KBDCTL_CTL_OUT_P1_DATA 0x80 // First ps2 port data
// Command byte definitions:
// 1.) Read "Byte 0" from internal ram, returns controller config byte
// 2.) Read Nth byte of internal ram
// 3.) Write byte0/controller configuration byte
// 4.) Write Nth byte of internal ram
// 5.) Disable second ps/2 port (if supported)
// 6.) Enable second ps/2 port (if supported)
// 7.) Test second ps/2 port (if supported)
// 8.) Test ps/2 controller
// 9.) Test 1st ps/2 port
// 10.) Diagnostic dump (Read all ram)
// 11.) Disable 1st ps/2 port
// 12.) Enable 1st ps/2 port
// 13.) Read controller input port
// 14.) Copy bits 0-3 of input to status 4-7
// 15.) Copy bits 4-7 of input to status 4-7
// 16.) Read controller output port
// 17.) Write next byte to Controller Output Port
// Note: first check that output buffer is empty
// 18.) Write next byte to ps/2 port 1 output buffer
// Note: Makes it look like byte was from 1st ps/2 port
// 19.) Write next byte to ps/2 port 2 output buffer
// Note: Makes it look like the byte was from 2nd ps/2 port
// 20.) Write next byte to ps/2 port input buffer
// Note: Sends next byte to second ps/2 port)
//
#define KBDCTL_CMD_READ_CONFIG 0x20
#define KBDCTL_CMD_READBN(x) (0x20 + x)
#define KBDCTL_CMD_WRITE_CONFIG 0x60
#define KBDCTL_CMD_WRITEBN(x) (0x60 + x)
#define KBDCTL_CMD_DISABLE_P2 0xA7
#define KBDCTL_CMD_ENABLE_P2 0xA8
#define KBDCTL_CMD_TEST_P2 0xA9
#define KBDCTL_CMD_TEST_CTL 0xAA
#define KBDCTL_CMD_TEST_P1 0xAB
#define KBDCTL_CMD_DUMP_RAM 0xAC
#define KBDCTL_CMD_DISABLE_P1 0xAD
#define KBDCTL_CMD_ENABLE_P1 0xAE
#define KBDCTL_CMD_READ_CTL_IN 0xC0
#define KBDCTL_CMD_CP_INLO_STATHI 0xC1
#define KBDCTL_CMD_CP_INHI_STATHI 0xC2
#define KBDCTL_CMD_READ_CTL_OUT 0xC3
#define KBDCTL_CMD_WRITENEXT_CTL_OUT 0xD1
#define KBDCTL_CMD_WRITENEXT_P1OUTBUF 0xD2
#define KBDCTL_CMD_WRITENEXT_P2OUTBUF 0xD3
#define KBDCTL_CMD_WRITENEXT_P2INBUF 0xD4
#define KBDCTL_CMD_ENABLE_A20 0xDF
#define KBDCTL_CMD_PULSE_OUT_LOW(x) (0xF0 | x)
#define KBDCTL_CMD_CPU_HARD_RESET 0xFE
#define KBDCTL_CMD_RST_DEVICE 0xFF
// Device commands
#define KBDCTL_DEV_CMD_RESET 0xFF
// Command responses
#define KBDCTL_SELFTEST_SUCCESS 0x55
#define KBDCTL_STAT_ACK 0xFA
#define KBDCTL_STAT_FAIL 0xFC
// 8042/ps2 controoler status related information
typedef struct {
// Is this a dual channel controller
bool dual_channel;
// current configuration
unsigned char current_configuration;
// devices initialised
int devices_initialised;
// A20 line status for memory access :3
bool a20line_enabled;
} ps2_8042_status;
// Send command to kbd controller, read response
//
// @param unsigned char v -- Command byte to send
// @return bool true on success or fals eon error
//
bool kbdctl_send_cmd(unsigned char v);
// Read a byte from data port once data becomes readable
//
// @return unsigned char data we received or -1 on error
//
unsigned char kbdctl_recv_data_poll(void);
// Write 1 byte of data to kbdctl port once it becomes writable
//
// @param unsigned char v -- byte to write
// @return true on success or false on timeout
//
bool kbdctl_send_data_poll(unsigned char v);
// Disable both ps/2 ports
//
// @return int 0 on success or which port failed to disable on error (1, 2, or both)
//
int kbdctl_disable_ports(void);
// Set keyboard controller byte with default config mask with
// interrupts and translation layer disabled
//
// @return enum DEVICE_STATUS status of device
//
enum DEVICE_STATUS kbdctl_set_default_init(device *dev);
// Perform keyboard controller self test.
//
// @return true on success or false on error
//
bool kbdctl_do_self_test(void);
// Test a single device
//
// @param unsigned char dev_cmd -- device specific test cmd (KBDCTL_CMD_TEST_P{1,2}
// @return unsigned char status of device test on success or -1 on error
//
unsigned char kbdctl_test_device(unsigned char dev_cmd);
// Enable all ps/2 devices
//
// @return unsigned char devices initialised
//
unsigned char kbdctl_enable_devices(device *dev);
// Reset a specific device
//
// @param int device_number -- 0 or 1 for 1st or 2nd device
// @return bool true on success or false on error
//
bool kbdctl_reset_device(int which);
#endif // __8042_KBDCTL_H__