struct cpuinfo_arm_chipset cpuinfo_arm_linux_decode_chipset_from_proc_cpuinfo_hardware()

in src/arm/linux/chipset.c [2226:2438]


struct cpuinfo_arm_chipset cpuinfo_arm_linux_decode_chipset_from_proc_cpuinfo_hardware(
	const char hardware[restrict static CPUINFO_HARDWARE_VALUE_MAX],
	uint32_t cores, uint32_t max_cpu_freq_max, bool is_tegra)
{
	struct cpuinfo_arm_chipset chipset;
	const size_t hardware_length = strnlen(hardware, CPUINFO_HARDWARE_VALUE_MAX);
	const char* hardware_end = hardware + hardware_length;

	if (is_tegra) {
		/*
		 * Nvidia Tegra-specific path: compare /proc/cpuinfo Hardware string to
		 * tabulated Hardware values for popular chipsets/devices with Tegra chipsets.
		 * This path is only used when ro.board.platform indicates a Tegra chipset
		 * (albeit does not indicate which exactly Tegra chipset).
		 */
		for (size_t i = 0; i < CPUINFO_COUNT_OF(tegra_hardware_map_entries); i++) {
			if (strncmp(tegra_hardware_map_entries[i].platform, hardware, hardware_length) == 0 &&
					tegra_hardware_map_entries[i].platform[hardware_length] == 0)
			{
				cpuinfo_log_debug(
					"found /proc/cpuinfo Hardware string \"%.*s\" in Nvidia Tegra chipset table",
					(int) hardware_length, hardware);
				/* Create chipset name from entry */
				return (struct cpuinfo_arm_chipset) {
					.vendor = chipset_series_vendor[tegra_hardware_map_entries[i].series],
					.series = (enum cpuinfo_arm_chipset_series) tegra_hardware_map_entries[i].series,
					.model = tegra_hardware_map_entries[i].model,
					.suffix = {
						[0] = tegra_hardware_map_entries[i].suffix,
					},
				};
			}
		}
	} else {
		/* Generic path: consider all other vendors */

		bool word_start = true;
		for (const char* pos = hardware; pos != hardware_end; pos++) {
			const char c = *pos;
			switch (c) {
				case ' ':
				case '\t':
				case ',':
					word_start = true;
					break;
				default:
					if (word_start && is_ascii_alphabetic(c)) {
						/* Check Qualcomm MSM/APQ signature */
						if (match_msm_apq(pos, hardware_end, &chipset)) {
							cpuinfo_log_debug(
								"matched Qualcomm MSM/APQ signature in /proc/cpuinfo Hardware string \"%.*s\"",
								(int) hardware_length, hardware);
							return chipset;
						}

						/* Check SDMxxx (Qualcomm Snapdragon) signature */
						if (match_sdm(pos, hardware_end, &chipset)) {
							cpuinfo_log_debug(
								"matched Qualcomm SDM signature in /proc/cpuinfo Hardware string \"%.*s\"",
								(int) hardware_length, hardware);
							return chipset;
						}

						/* Check SMxxxx (Qualcomm Snapdragon) signature */
						if (match_sm(pos, hardware_end, &chipset)) {
							cpuinfo_log_debug(
								"matched Qualcomm SM signature in /proc/cpuinfo Hardware string \"%.*s\"",
								(int) hardware_length, hardware);
							return chipset;
						}

						/* Check MediaTek MT signature */
						if (match_mt(pos, hardware_end, true, &chipset)) {
							cpuinfo_log_debug(
								"matched MediaTek MT signature in /proc/cpuinfo Hardware string \"%.*s\"",
								(int) hardware_length, hardware);
							return chipset;
						}

						/* Check HiSilicon Kirin signature */
						if (match_kirin(pos, hardware_end, &chipset)) {
							cpuinfo_log_debug(
								"matched HiSilicon Kirin signature in /proc/cpuinfo Hardware string \"%.*s\"",
								(int) hardware_length, hardware);
							return chipset;
						}

						/* Check Rockchip RK signature */
						if (match_rk(pos, hardware_end, &chipset)) {
							cpuinfo_log_debug(
								"matched Rockchip RK signature in /proc/cpuinfo Hardware string \"%.*s\"",
								(int) hardware_length, hardware);
							return chipset;
						}
					}
					word_start = false;
					break;
			}
		}

		/* Check Samsung Exynos signature */
		if (match_samsung_exynos(hardware, hardware_end, &chipset)) {
			cpuinfo_log_debug(
				"matched Samsung Exynos signature in /proc/cpuinfo Hardware string \"%.*s\"",
				(int) hardware_length, hardware);
			return chipset;
		}

		/* Check universalXXXX (Samsung Exynos) signature */
		if (match_universal(hardware, hardware_end, &chipset)) {
			cpuinfo_log_debug(
				"matched UNIVERSAL (Samsung Exynos) signature in /proc/cpuinfo Hardware string \"%.*s\"",
				(int) hardware_length, hardware);
			return chipset;
		}

		#if CPUINFO_ARCH_ARM
			/* Match /SMDK(4410|4x12)$/ */
			if (match_and_parse_smdk(hardware, hardware_end, cores, &chipset)) {
				cpuinfo_log_debug(
					"matched SMDK (Samsung Exynos) signature in /proc/cpuinfo Hardware string \"%.*s\"",
					(int) hardware_length, hardware);
				return chipset;
			}
		#endif

		/* Check Spreadtrum SC signature */
		if (match_sc(hardware, hardware_end, &chipset)) {
			cpuinfo_log_debug(
				"matched Spreadtrum SC signature in /proc/cpuinfo Hardware string \"%.*s\"",
				(int) hardware_length, hardware);
			return chipset;
		}

		#if CPUINFO_ARCH_ARM
			/* Check Marvell PXA signature */
			if (match_pxa(hardware, hardware_end, &chipset)) {
				cpuinfo_log_debug(
					"matched Marvell PXA signature in /proc/cpuinfo Hardware string \"%.*s\"",
					(int) hardware_length, hardware);
				return chipset;
			}
		#endif

		/* Match /sun\d+i/ signature and map to Allwinner chipset name */
		if (match_and_parse_sunxi(hardware, hardware_end, cores, &chipset)) {
			cpuinfo_log_debug(
				"matched sunxi (Allwinner Ax) signature in /proc/cpuinfo Hardware string \"%.*s\"",
				(int) hardware_length, hardware);
			return chipset;
		}

		/* Check Broadcom BCM signature */
		if (match_bcm(hardware, hardware_end, &chipset)) {
			cpuinfo_log_debug(
				"matched Broadcom BCM signature in /proc/cpuinfo Hardware string \"%.*s\"",
				(int) hardware_length, hardware);
			return chipset;
		}

		#if CPUINFO_ARCH_ARM
			/* Check Texas Instruments OMAP signature */
			if (match_omap(hardware, hardware_end, &chipset)) {
				cpuinfo_log_debug(
					"matched Texas Instruments OMAP signature in /proc/cpuinfo Hardware string \"%.*s\"",
					(int) hardware_length, hardware);
				return chipset;
			}

			/* Check WonderMedia WMT signature and decode chipset from frequency and number of cores  */
			if (match_and_parse_wmt(hardware, hardware_end, cores, max_cpu_freq_max, &chipset)) {
				cpuinfo_log_debug(
					"matched WonderMedia WMT signature in /proc/cpuinfo Hardware string \"%.*s\"",
					(int) hardware_length, hardware);
				return chipset;
			}

		#endif

		/* Check Telechips TCC signature */
		if (match_tcc(hardware, hardware_end, &chipset)) {
			cpuinfo_log_debug(
				"matched Telechips TCC signature in /proc/cpuinfo Hardware string \"%.*s\"",
				(int) hardware_length, hardware);
			return chipset;
		}

		/* Compare to tabulated Hardware values for popular chipsets/devices which can't be otherwise detected */
		for (size_t i = 0; i < CPUINFO_COUNT_OF(special_hardware_map_entries); i++) {
			if (strncmp(special_hardware_map_entries[i].platform, hardware, hardware_length) == 0 &&
					special_hardware_map_entries[i].platform[hardware_length] == 0)
			{
				cpuinfo_log_debug(
					"found /proc/cpuinfo Hardware string \"%.*s\" in special chipset table",
					(int) hardware_length, hardware);
				/* Create chipset name from entry */
				return (struct cpuinfo_arm_chipset) {
					.vendor = chipset_series_vendor[special_hardware_map_entries[i].series],
					.series = (enum cpuinfo_arm_chipset_series) special_hardware_map_entries[i].series,
					.model = special_hardware_map_entries[i].model,
					.suffix = {
						[0] = special_hardware_map_entries[i].suffix,
					},
				};
			}
		}
	}

	return (struct cpuinfo_arm_chipset) {
		.vendor = cpuinfo_arm_chipset_vendor_unknown,
		.series = cpuinfo_arm_chipset_series_unknown,
	};
}