#include <stdint.h>

#include <cpuinfo.h>
#include <x86/api.h>

/* Intel vendor string: "GenuineIntel" */
#define Genu UINT32_C(0x756E6547)
#define ineI UINT32_C(0x49656E69)
#define ntel UINT32_C(0x6C65746E)

/* AMD vendor strings: "AuthenticAMD", "AMDisbetter!", "AMD ISBETTER" */
#define Auth UINT32_C(0x68747541)
#define enti UINT32_C(0x69746E65)
#define cAMD UINT32_C(0x444D4163)
#define AMDi UINT32_C(0x69444D41)
#define sbet UINT32_C(0x74656273)
#define ter UINT32_C(0x21726574)
#define AMD UINT32_C(0x20444D41)
#define ISBE UINT32_C(0x45425349)
#define TTER UINT32_C(0x52455454)

/* VIA (Centaur) vendor strings: "CentaurHauls", "VIA VIA VIA " */
#define Cent UINT32_C(0x746E6543)
#define aurH UINT32_C(0x48727561)
#define auls UINT32_C(0x736C7561)
#define VIA UINT32_C(0x20414956)

/* Hygon vendor string: "HygonGenuine" */
#define Hygo UINT32_C(0x6F677948)
#define nGen UINT32_C(0x6E65476E)
#define uine UINT32_C(0x656E6975)

/* Transmeta vendor strings: "GenuineTMx86", "TransmetaCPU" */
#define ineT UINT32_C(0x54656E69)
#define Mx86 UINT32_C(0x3638784D)
#define Tran UINT32_C(0x6E617254)
#define smet UINT32_C(0x74656D73)
#define aCPU UINT32_C(0x55504361)

/* Cyrix vendor string: "CyrixInstead" */
#define Cyri UINT32_C(0x69727943)
#define xIns UINT32_C(0x736E4978)
#define tead UINT32_C(0x64616574)

/* Rise vendor string: "RiseRiseRise" */
#define Rise UINT32_C(0x65736952)

/* NSC vendor string: "Geode by NSC" */
#define Geod UINT32_C(0x646F6547)
#define e_by UINT32_C(0x79622065)
#define NSC UINT32_C(0x43534E20)

/* SiS vendor string: "SiS SiS SiS " */
#define SiS UINT32_C(0x20536953)

/* NexGen vendor string: "NexGenDriven" */
#define NexG UINT32_C(0x4778654E)
#define enDr UINT32_C(0x72446E65)
#define iven UINT32_C(0x6E657669)

/* UMC vendor string: "UMC UMC UMC " */
#define UMC UINT32_C(0x20434D55)

/* RDC vendor string: "Genuine  RDC" */
#define ine UINT32_C(0x20656E69)
#define RDC UINT32_C(0x43445220)

/* D&MP vendor string: "Vortex86 SoC" */
#define Vort UINT32_C(0x74726F56)
#define ex86 UINT32_C(0x36387865)
#define SoC UINT32_C(0x436F5320)

enum cpuinfo_vendor cpuinfo_x86_decode_vendor(uint32_t ebx, uint32_t ecx, uint32_t edx) {
	switch (ebx) {
		case Genu:
			switch (edx) {
				case ineI:
					if (ecx == ntel) {
						/* "GenuineIntel" */
						return cpuinfo_vendor_intel;
					}
					break;
#if CPUINFO_ARCH_X86
				case ineT:
					if (ecx == Mx86) {
						/* "GenuineTMx86" */
						return cpuinfo_vendor_transmeta;
					}
					break;
				case ine:
					if (ecx == RDC) {
						/* "Genuine  RDC" */
						return cpuinfo_vendor_rdc;
					}
					break;
#endif
			}
			break;
		case Auth:
			if (edx == enti && ecx == cAMD) {
				/* "AuthenticAMD" */
				return cpuinfo_vendor_amd;
			}
			break;
		case Cent:
			if (edx == aurH && ecx == auls) {
				/* "CentaurHauls" */
				return cpuinfo_vendor_via;
			}
			break;
		case Hygo:
			if (edx == nGen && ecx == uine) {
				/* "HygonGenuine" */
				return cpuinfo_vendor_hygon;
			}
			break;
#if CPUINFO_ARCH_X86
		case AMDi:
			if (edx == sbet && ecx == ter) {
				/* "AMDisbetter!" */
				return cpuinfo_vendor_amd;
			}
			break;
		case AMD:
			if (edx == ISBE && ecx == TTER) {
				/* "AMD ISBETTER" */
				return cpuinfo_vendor_amd;
			}
			break;
		case VIA:
			if (edx == VIA && ecx == VIA) {
				/* "VIA VIA VIA " */
				return cpuinfo_vendor_via;
			}
			break;
		case Tran:
			if (edx == smet && ecx == aCPU) {
				/* "TransmetaCPU" */
				return cpuinfo_vendor_transmeta;
			}
			break;
		case Cyri:
			if (edx == xIns && ecx == tead) {
				/* "CyrixInstead" */
				return cpuinfo_vendor_cyrix;
			}
			break;
		case Rise:
			if (edx == Rise && ecx == Rise) {
				/* "RiseRiseRise" */
				return cpuinfo_vendor_rise;
			}
			break;
		case Geod:
			if (edx == e_by && ecx == NSC) {
				/* "Geode by NSC" */
				return cpuinfo_vendor_nsc;
			}
			break;
		case SiS:
			if (edx == SiS && ecx == SiS) {
				/* "SiS SiS SiS " */
				return cpuinfo_vendor_sis;
			}
			break;
		case NexG:
			if (edx == enDr && ecx == iven) {
				/* "NexGenDriven" */
				return cpuinfo_vendor_nexgen;
			}
			break;
		case UMC:
			if (edx == UMC && ecx == UMC) {
				/* "UMC UMC UMC " */
				return cpuinfo_vendor_umc;
			}
			break;
		case Vort:
			if (edx == ex86 && ecx == SoC) {
				/* "Vortex86 SoC" */
				return cpuinfo_vendor_dmp;
			}
			break;
#endif
	}
	return cpuinfo_vendor_unknown;
}
