#ifndef KATA_H
#define KATA_H

#ifndef __ASSEMBLER__
#include <stdint.h>
#include <stddef.h>
#endif

#define IDE_PRIMARY_IO_BASE 0x01F0
#define IDE_PRIMARY_CRTL_BASE 0x03F6

#define IDE_SECONDARY_IO_BASE 0x0170
#define IDE_SECONDARY_CRTL_BASE 0x0376

#define IDE_DRIVE_MASTER 0xA0
#define IDE_DRIVE_SLAVE 0xB0

#define IO_DATA_REG 0x0000
#define IO_ERROR_REG 0x0001
#define IO_FEATURE_REG 0x0001
#define IO_SECTOR_COUNT_REG 0x0002
#define IO_SECTOR_NUM_REG 0x0003 
#define IO_LBA_LO_REG 0x0003
#define IO_CYL_LO_REG 0x0004
#define IO_LBA_MID_REG 0x0004
#define IO_LBA_HI_REG 0x0005
#define IO_CYL_HI_REG 0x0005
#define IO_DRIVE_SELECT_REG 0x0006
#define IO_STATUS_REG 0x0007
#define IO_CMD_REG 0x0007

#define CTRL_ALT_STATUS_REG 0x00
#define CTRL_DEV_CTRL_REG 0x00
#define CTRL_DRIVE_ADDR_REG 0x01

#define ERROR_REG_AMNF  0b00000001  // Address mark not found
#define ERROR_REG_TKZNF 0b00000010  // Track zero not found
#define ERROR_REG_ABRT  0b00000100  // Aborted command
#define ERROR_REG_MCR   0b00001000  // Media change request
#define ERROR_REG_IDNF  0b00010000  // ID not found
#define ERROR_REG_MC    0b00100000  // Media changed
#define ERROR_REG_UNC   0b01000000  // Uncorrectable data error
#define ERROR_REG_BBK   0b10000000  // Bad Block detected

#define DRIVE_SELECT_REG_BN     0b00000111
#define DRIVE_SELECT_REG_DRV    0b00010000
#define DRIVE_SELECT_REG_LBA   0b01000000

#define STATUS_REG_ERR  0b00000001
#define STATUS_REG_IDX  0b00000010
#define STATUS_REG_CORR 0b00000100
#define STATUS_REG_DRQ  0b00001000
#define STATUS_REG_SRV  0b00010000
#define STATUS_REG_DF   0b00100000
#define STATUS_REG_RDY  0b01000000
#define STATUS_REG_BSY  0b10000000

#define DEV_CTRL_REG_nIEN   0b00000010
#define DEV_CTRL_REG_SRST   0b00000100
#define DEV_CTRL_REG_HOB    0b10000000

#define DRIVE_ADDR_REG_DS0      0b00000001
#define DRIVE_ADDR_REG_DS1      0b00000010
#define DRIVE_ADDR_REG_HEAD     0b00111100
#define DRIVE_ADDR_REG_WTG      0b01000000

#define ATA_CMD_READ_PIO          0x20
#define ATA_CMD_READ_PIO_EXT      0x24
#define ATA_CMD_READ_DMA          0xC8
#define ATA_CMD_READ_DMA_EXT      0x25
#define ATA_CMD_WRITE_PIO         0x30
#define ATA_CMD_WRITE_PIO_EXT     0x34
#define ATA_CMD_WRITE_DMA         0xCA
#define ATA_CMD_WRITE_DMA_EXT     0x35
#define ATA_CMD_CACHE_FLUSH       0xE7
#define ATA_CMD_CACHE_FLUSH_EXT   0xEA
#define ATA_CMD_PACKET            0xA0
#define ATA_CMD_IDENTIFY_PACKET   0xA1
#define ATA_CMD_IDENTIFY          0xEC

#define ATAPI_CMD_READ       0xA8
#define ATAPI_CMD_EJECT      0x1B

#define ATA_IDENT_DEVICETYPE   0
#define ATA_IDENT_CYLINDERS    2
#define ATA_IDENT_HEADS        6
#define ATA_IDENT_SECTORS      12
#define ATA_IDENT_SERIAL       20
#define ATA_IDENT_MODEL        54
#define ATA_IDENT_MODEL_SZ     40
#define ATA_IDENT_CAPABILITIES 98
#define ATA_IDENT_FIELDVALID   106
#define ATA_IDENT_MAX_LBA      120
#define ATA_IDENT_COMMANDSETS  164
#define ATA_IDENT_MAX_LBA_EXT  200

#ifndef __ASSEMBLER__
typedef enum {
    NO_DEVICE = 0,
    ATA,
    ATAPI,
} ide_dev_type;


typedef struct __attribute__((packed)) {
    uint16_t bus;
    uint8_t device;
    ide_dev_type type;
    uint16_t sig;
    uint16_t capabilities;
    uint32_t command_set;
    char* serial;
    char* model;
    uint32_t size;
} ide_device_t;

void scan_drives();
ide_device_t* get_ide_device(uint8_t slot);
int ide_read_blks(ide_device_t* dev, uint32_t lba, uint32_t sectors, void* buf);

#endif

#endif