// SPDX-License-Identifier: MPL-2.0
#ifndef SH_LIB_GSI_H
#define SH_LIB_GSI_H
#include "std/stdlib.h"
#include "devs/apic/ioapic.h"
// GSI polarity enum
enum sh_gsi_POLARITY {
  SH_GSI_POLARITY_NOT_SET=0,
  SH_GSI_POLARITY_BUS_DEFAULT,
  SH_GSI_POLARITY_ACTIVE_HIGH,
  SH_GSI_POLARITY_ACTIVE_LOW
};
// GSI trigger mode enum
enum sh_gsi_TRIGGER_MODE {
  SH_GSI_TRIGGER_MODE_NOT_SET=0,
  SH_GSI_TRIGGER_MODE_BUS_DEFAULT,
  SH_GSI_TRIGGER_MODE_EDGE,
  SH_GSI_TRIGGER_MODE_LEVEL
};
// Interrupt source override (ISO) structure
typedef struct {
  sh_uint32 gsi;
  // must default to SH_FALSE
  sh_bool valid;
  // when ISOs array is initialized, this field must default to 0
  sh_uint8 source_irq;
  // these two fields are determined by the flags field in the MADT entry. Bus-default value are resolved when writing IOREDTBL
  enum sh_gsi_POLARITY polarity;
  enum sh_gsi_TRIGGER_MODE trigger_mode;
  // when ISOs array is initialized, this field must default to 0
  sh_uint8 bus;
} sh_gsi_ISO;
// Initialize a 256 elements array of sh_gsi_ISO structs
SH_STATUS sh_gsi_iso_array_init();
// Register an ISO, this function is supposed to be used during MADT parsing when encountering an ISO. It expect the field as they are provided into the MADT entry
SH_STATUS sh_gsi_iso_register(sh_uint8 bus,sh_uint8 source,sh_uint32 gsi,sh_uint16 flags);
// Return an ISO structure for the given interrupt
sh_gsi_ISO *sh_gsi_get_iso_by_irq(sh_uint8 irq);
// Return an ISO structure for the given GSI
sh_gsi_ISO *sh_gsi_get_iso_by_gsi(sh_uint32 gsi);
// These two functions provide a thread-safe and "interrupt-storm" safe way to get and set IOREDTBL entries
// Read the IOREDTBL entry associated with the provided GSI
SH_STATUS sh_gsi_get(sh_uint32 gsi,sh_ioapic_IOREDTBL_ENTRY *entry);
// Set the provided GSI to the corresponding IOREDTBL entry, mask the IOOREDTBL entry and doesn't unmask it
SH_STATUS sh_gsi_set(sh_uint32 gsi,sh_ioapic_IOREDTBL_ENTRY *entry);
// Set the provided IRQ to IOREDTBL entry, calculate the expected GSI using sh_gsi_get_iso_by_irq
SH_STATUS sh_gsi_irq_set(sh_uint8 irq,sh_ioapic_IOREDTBL_ENTRY *entry);
// Mask the IOREDTBL entry corresponding to the provided GSI
inline SH_STATUS sh_gsi_mask(sh_uint32 gsi) {
  return sh_ioapic_mask_gsi(sh_ioapic_get_dev_by_gsi(gsi),gsi);
}
// Unmask the IOREDTBL entry corresponding to the provided GSI
inline SH_STATUS sh_gsi_unmask(sh_uint32 gsi) {
  return sh_ioapic_unmask_gsi(sh_ioapic_get_dev_by_gsi(gsi),gsi);
}
// Mask the IOREDTBL entry corresponding to the provided IRQ
SH_STATUS sh_gsi_irq_mask(sh_uint8 irq);
// Unmask the IOREDTBL entry corresponding to the provided IRQ
SH_STATUS sh_gsi_irq_unmask(sh_uint8 irq);
// Load all legacy IRQ to IOREDTBL entries, intented to be called only one time
SH_STATUS sh_gsi_irq_switch();
#endif
