Send patches - preferably formatted by git format-patch - to patches at archlinux32 dot org.
summaryrefslogtreecommitdiff
path: root/archinstall/lib/hardware.py
diff options
context:
space:
mode:
Diffstat (limited to 'archinstall/lib/hardware.py')
-rw-r--r--archinstall/lib/hardware.py494
1 files changed, 311 insertions, 183 deletions
diff --git a/archinstall/lib/hardware.py b/archinstall/lib/hardware.py
index 9660ea95..c8001c19 100644
--- a/archinstall/lib/hardware.py
+++ b/archinstall/lib/hardware.py
@@ -1,190 +1,318 @@
import os
-import logging
-from functools import partial
+from enum import Enum
+from functools import cached_property
from pathlib import Path
-from typing import Iterator, Optional, Union
+from typing import Optional, Dict, List, TYPE_CHECKING, Any
+from .exceptions import SysCallError
from .general import SysCommand
from .networking import list_interfaces, enrich_iface_types
-from .exceptions import SysCallError
-from .output import log
-
-__packages__ = [
- "mesa",
- "xf86-video-amdgpu",
- "xf86-video-ati",
- "xf86-video-nouveau",
- "xf86-video-vmware",
- "libva-mesa-driver",
- "libva-intel-driver",
- "intel-media-driver",
- "vulkan-radeon",
- "vulkan-intel",
- "nvidia",
-]
-
-AVAILABLE_GFX_DRIVERS = {
- # Sub-dicts are layer-2 options to be selected
- # and lists are a list of packages to be installed
- "All open-source (default)": [
- "mesa",
- "xf86-video-amdgpu",
- "xf86-video-ati",
- "xf86-video-nouveau",
- "xf86-video-vmware",
- "libva-mesa-driver",
- "libva-intel-driver",
- "intel-media-driver",
- "vulkan-radeon",
- "vulkan-intel",
- ],
- "AMD / ATI (open-source)": [
- "mesa",
- "xf86-video-amdgpu",
- "xf86-video-ati",
- "libva-mesa-driver",
- "vulkan-radeon",
- ],
- "Intel (open-source)": [
- "mesa",
- "libva-intel-driver",
- "intel-media-driver",
- "vulkan-intel",
- ],
- "Nvidia (open kernel module for newer GPUs, Turing+)": ["nvidia-open"],
- "Nvidia (open-source nouveau driver)": [
- "mesa",
- "xf86-video-nouveau",
- "libva-mesa-driver"
- ],
- "Nvidia (proprietary)": ["nvidia"],
- "VMware / VirtualBox (open-source)": ["mesa", "xf86-video-vmware"],
-}
-
-CPUINFO = Path("/proc/cpuinfo")
-MEMINFO = Path("/proc/meminfo")
-
-
-def cpuinfo() -> Iterator[dict[str, str]]:
- """Yields information about the CPUs of the system."""
- cpu = {}
-
- with CPUINFO.open() as file:
- for line in file:
- if not (line := line.strip()):
- yield cpu
- cpu = {}
- continue
-
- key, value = line.split(":", maxsplit=1)
- cpu[key.strip()] = value.strip()
-
-
-def meminfo(key: Optional[str] = None) -> Union[dict[str, int], Optional[int]]:
- """Returns a dict with memory info if called with no args
- or the value of the given key of said dict.
- """
- with MEMINFO.open() as file:
- mem_info = {
- (columns := line.strip().split())[0].rstrip(':'): int(columns[1])
- for line in file
- }
-
- if key is None:
- return mem_info
-
- return mem_info.get(key)
-
-
-def has_wifi() -> bool:
- return 'WIRELESS' in enrich_iface_types(list_interfaces().values()).values()
-
-
-def has_cpu_vendor(vendor_id: str) -> bool:
- return any(cpu.get("vendor_id") == vendor_id for cpu in cpuinfo())
-
-
-has_amd_cpu = partial(has_cpu_vendor, "AuthenticAMD")
-
-
-has_intel_cpu = partial(has_cpu_vendor, "GenuineIntel")
-
-
-def has_uefi() -> bool:
- return os.path.isdir('/sys/firmware/efi')
-
-
-def graphics_devices() -> dict:
- cards = {}
- for line in SysCommand("lspci"):
- if b' VGA ' in line or b' 3D ' in line:
- _, identifier = line.split(b': ', 1)
- cards[identifier.strip().decode('UTF-8')] = line
- return cards
-
-
-def has_nvidia_graphics() -> bool:
- return any('nvidia' in x.lower() for x in graphics_devices())
-
-
-def has_amd_graphics() -> bool:
- return any('amd' in x.lower() for x in graphics_devices())
-
-
-def has_intel_graphics() -> bool:
- return any('intel' in x.lower() for x in graphics_devices())
+from .output import debug
+from .utils.util import format_cols
+
+if TYPE_CHECKING:
+ _: Any
+
+
+class CpuVendor(Enum):
+ AuthenticAMD = 'amd'
+ GenuineIntel = 'intel'
+ _Unknown = 'unknown'
+
+ @classmethod
+ def get_vendor(cls, name: str) -> 'CpuVendor':
+ if vendor := getattr(cls, name, None):
+ return vendor
+ else:
+ debug(f"Unknown CPU vendor '{name}' detected.")
+ return cls._Unknown
+
+ def _has_microcode(self) -> bool:
+ match self:
+ case CpuVendor.AuthenticAMD | CpuVendor.GenuineIntel:
+ return True
+ case _:
+ return False
+
+ def get_ucode(self) -> Optional[Path]:
+ if self._has_microcode():
+ return Path(self.value + '-ucode.img')
+ return None
+
+
+class GfxPackage(Enum):
+ Dkms = 'dkms'
+ IntelMediaDriver = 'intel-media-driver'
+ LibvaIntelDriver = 'libva-intel-driver'
+ LibvaMesaDriver = 'libva-mesa-driver'
+ Mesa = "mesa"
+ NvidiaDkms = 'nvidia-dkms'
+ NvidiaOpen = 'nvidia-open'
+ NvidiaOpenDkms = 'nvidia-open-dkms'
+ VulkanIntel = 'vulkan-intel'
+ VulkanRadeon = 'vulkan-radeon'
+ Xf86VideoAmdgpu = "xf86-video-amdgpu"
+ Xf86VideoAti = "xf86-video-ati"
+ Xf86VideoNouveau = 'xf86-video-nouveau'
+ Xf86VideoVmware = 'xf86-video-vmware'
+ XorgServer = 'xorg-server'
+ XorgXinit = 'xorg-xinit'
+
+
+class GfxDriver(Enum):
+ AllOpenSource = 'All open-source'
+ AmdOpenSource = 'AMD / ATI (open-source)'
+ IntelOpenSource = 'Intel (open-source)'
+ NvidiaOpenKernel = 'Nvidia (open kernel module for newer GPUs, Turing+)'
+ NvidiaOpenSource = 'Nvidia (open-source nouveau driver)'
+ NvidiaProprietary = 'Nvidia (proprietary)'
+ VMOpenSource = 'VMware / VirtualBox (open-source)'
+
+ def is_nvidia(self) -> bool:
+ match self:
+ case GfxDriver.NvidiaProprietary | \
+ GfxDriver.NvidiaOpenSource | \
+ GfxDriver.NvidiaOpenKernel:
+ return True
+ case _:
+ return False
+
+ def packages_text(self) -> str:
+ text = str(_('Installed packages')) + ':\n'
+ pkg_names = [p.value for p in self.gfx_packages()]
+ text += format_cols(sorted(pkg_names))
+ return text
+
+ def gfx_packages(self) -> List[GfxPackage]:
+ packages = [GfxPackage.XorgServer, GfxPackage.XorgXinit]
+
+ match self:
+ case GfxDriver.AllOpenSource:
+ packages += [
+ GfxPackage.Mesa,
+ GfxPackage.Xf86VideoAmdgpu,
+ GfxPackage.Xf86VideoAti,
+ GfxPackage.Xf86VideoNouveau,
+ GfxPackage.Xf86VideoVmware,
+ GfxPackage.LibvaMesaDriver,
+ GfxPackage.LibvaIntelDriver,
+ GfxPackage.IntelMediaDriver,
+ GfxPackage.VulkanRadeon,
+ GfxPackage.VulkanIntel
+ ]
+ case GfxDriver.AmdOpenSource:
+ packages += [
+ GfxPackage.Mesa,
+ GfxPackage.Xf86VideoAmdgpu,
+ GfxPackage.Xf86VideoAti,
+ GfxPackage.LibvaMesaDriver,
+ GfxPackage.VulkanRadeon
+ ]
+ case GfxDriver.IntelOpenSource:
+ packages += [
+ GfxPackage.Mesa,
+ GfxPackage.LibvaIntelDriver,
+ GfxPackage.IntelMediaDriver,
+ GfxPackage.VulkanIntel
+ ]
+ case GfxDriver.NvidiaOpenKernel:
+ packages += [
+ GfxPackage.NvidiaOpen,
+ GfxPackage.Dkms,
+ GfxPackage.NvidiaOpenDkms
+ ]
+ case GfxDriver.NvidiaOpenSource:
+ packages += [
+ GfxPackage.Mesa,
+ GfxPackage.Xf86VideoNouveau,
+ GfxPackage.LibvaMesaDriver
+ ]
+ case GfxDriver.NvidiaProprietary:
+ packages += [
+ GfxPackage.NvidiaDkms,
+ GfxPackage.Dkms,
+ ]
+ case GfxDriver.VMOpenSource:
+ packages += [
+ GfxPackage.Mesa,
+ GfxPackage.Xf86VideoVmware
+ ]
+
+ return packages
+
+class _SysInfo:
+ def __init__(self):
+ pass
+
+ @cached_property
+ def cpu_info(self) -> Dict[str, str]:
+ """
+ Returns system cpu information
+ """
+ cpu_info_path = Path("/proc/cpuinfo")
+ cpu: Dict[str, str] = {}
+
+ with cpu_info_path.open() as file:
+ for line in file:
+ if line := line.strip():
+ key, value = line.split(":", maxsplit=1)
+ cpu[key.strip()] = value.strip()
+
+ return cpu
+
+ @cached_property
+ def mem_info(self) -> Dict[str, int]:
+ """
+ Returns system memory information
+ """
+ mem_info_path = Path("/proc/meminfo")
+ mem_info: Dict[str, int] = {}
+
+ with mem_info_path.open() as file:
+ for line in file:
+ key, value = line.strip().split(':')
+ num = value.split()[0]
+ mem_info[key] = int(num)
+ return mem_info
-def cpu_vendor() -> Optional[str]:
- for cpu in cpuinfo():
- return cpu.get("vendor_id")
-
- return None
-
-
-def cpu_model() -> Optional[str]:
- for cpu in cpuinfo():
- return cpu.get("model name")
-
- return None
-
-
-def sys_vendor() -> Optional[str]:
- with open(f"/sys/devices/virtual/dmi/id/sys_vendor") as vendor:
- return vendor.read().strip()
-
-
-def product_name() -> Optional[str]:
- with open(f"/sys/devices/virtual/dmi/id/product_name") as product:
- return product.read().strip()
-
-
-def mem_available() -> Optional[int]:
- return meminfo('MemAvailable')
-
-
-def mem_free() -> Optional[int]:
- return meminfo('MemFree')
-
-
-def mem_total() -> Optional[int]:
- return meminfo('MemTotal')
-
-
-def virtualization() -> Optional[str]:
- try:
- return str(SysCommand("systemd-detect-virt")).strip('\r\n')
- except SysCallError as error:
- log(f"Could not detect virtual system: {error}", level=logging.DEBUG)
-
- return None
-
-
-def is_vm() -> bool:
- try:
- return b"none" not in b"".join(SysCommand("systemd-detect-virt")).lower()
- except SysCallError as error:
- log(f"System is not running in a VM: {error}", level=logging.DEBUG)
- return None
-
-# TODO: Add more identifiers
+ def mem_info_by_key(self, key: str) -> int:
+ return self.mem_info[key]
+
+ @cached_property
+ def loaded_modules(self) -> List[str]:
+ """
+ Returns loaded kernel modules
+ """
+ modules_path = Path('/proc/modules')
+ modules: List[str] = []
+
+ with modules_path.open() as file:
+ for line in file:
+ module = line.split(maxsplit=1)[0]
+ modules.append(module)
+
+ return modules
+
+
+_sys_info = _SysInfo()
+
+
+class SysInfo:
+ @staticmethod
+ def has_wifi() -> bool:
+ ifaces = list(list_interfaces().values())
+ return 'WIRELESS' in enrich_iface_types(ifaces).values()
+
+ @staticmethod
+ def has_uefi() -> bool:
+ return os.path.isdir('/sys/firmware/efi')
+
+ @staticmethod
+ def _graphics_devices() -> Dict[str, str]:
+ cards: Dict[str, str] = {}
+ for line in SysCommand("lspci"):
+ if b' VGA ' in line or b' 3D ' in line:
+ _, identifier = line.split(b': ', 1)
+ cards[identifier.strip().decode('UTF-8')] = str(line)
+ return cards
+
+ @staticmethod
+ def has_nvidia_graphics() -> bool:
+ return any('nvidia' in x.lower() for x in SysInfo._graphics_devices())
+
+ @staticmethod
+ def has_amd_graphics() -> bool:
+ return any('amd' in x.lower() for x in SysInfo._graphics_devices())
+
+ @staticmethod
+ def has_intel_graphics() -> bool:
+ return any('intel' in x.lower() for x in SysInfo._graphics_devices())
+
+ @staticmethod
+ def cpu_vendor() -> Optional[CpuVendor]:
+ if vendor := _sys_info.cpu_info.get('vendor_id'):
+ return CpuVendor.get_vendor(vendor)
+ return None
+
+ @staticmethod
+ def cpu_model() -> Optional[str]:
+ return _sys_info.cpu_info.get('model name', None)
+
+ @staticmethod
+ def sys_vendor() -> str:
+ with open(f"/sys/devices/virtual/dmi/id/sys_vendor") as vendor:
+ return vendor.read().strip()
+
+ @staticmethod
+ def product_name() -> str:
+ with open(f"/sys/devices/virtual/dmi/id/product_name") as product:
+ return product.read().strip()
+
+ @staticmethod
+ def mem_available() -> int:
+ return _sys_info.mem_info_by_key('MemAvailable')
+
+ @staticmethod
+ def mem_free() -> int:
+ return _sys_info.mem_info_by_key('MemFree')
+
+ @staticmethod
+ def mem_total() -> int:
+ return _sys_info.mem_info_by_key('MemTotal')
+
+ @staticmethod
+ def virtualization() -> Optional[str]:
+ try:
+ return str(SysCommand("systemd-detect-virt")).strip('\r\n')
+ except SysCallError as err:
+ debug(f"Could not detect virtual system: {err}")
+
+ return None
+
+ @staticmethod
+ def is_vm() -> bool:
+ try:
+ result = SysCommand("systemd-detect-virt")
+ return b"none" not in b"".join(result).lower()
+ except SysCallError as err:
+ debug(f"System is not running in a VM: {err}")
+
+ return False
+
+ @staticmethod
+ def requires_sof_fw() -> bool:
+ return 'snd_sof' in _sys_info.loaded_modules
+
+ @staticmethod
+ def requires_alsa_fw() -> bool:
+ modules = (
+ 'snd_asihpi',
+ 'snd_cs46xx',
+ 'snd_darla20',
+ 'snd_darla24',
+ 'snd_echo3g',
+ 'snd_emu10k1',
+ 'snd_gina20',
+ 'snd_gina24',
+ 'snd_hda_codec_ca0132',
+ 'snd_hdsp',
+ 'snd_indigo',
+ 'snd_indigodj',
+ 'snd_indigodjx',
+ 'snd_indigoio',
+ 'snd_indigoiox',
+ 'snd_layla20',
+ 'snd_layla24',
+ 'snd_mia',
+ 'snd_mixart',
+ 'snd_mona',
+ 'snd_pcxhr',
+ 'snd_vx_lib'
+ )
+
+ for loaded_module in _sys_info.loaded_modules:
+ if loaded_module in modules:
+ return True
+
+ return False