-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathalsa-firmware.py
More file actions
156 lines (114 loc) · 4.2 KB
/
alsa-firmware.py
File metadata and controls
156 lines (114 loc) · 4.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
import sys
from errno import ENOENT
from pathlib import Path
from dataclasses import dataclass, field
from subprocess import run, CalledProcessError
from typing import List
@dataclass
class ModInfo:
name: str
description: str
firmware: List[Path] = field(default_factory=list)
def __str__(self):
s = f' name: {self.name}\n'
s += f'description: {self.description}\n'
for fw_file in self.firmware:
s += f' firmware: {fw_file}\n'
return s.removesuffix('\n')
def sound_modules() -> List[Path]:
"""
Get a list of all sound loadable kernel modules
"""
modules = Path('/usr/lib/modules')
subdirs = [p for p in modules.iterdir() if p.is_dir()]
if not len(subdirs):
raise FileNotFoundError(
ENOENT, f"No subdirectory found in directory: '{modules}'")
if len(subdirs) == 1:
kernel_ver_dir = subdirs[0]
else:
proc_version = Path('/proc/version')
with proc_version.open() as f:
version = f.read()
kernel_ver = version.split(maxsplit=3)[2]
kernel_ver_dir = modules / kernel_ver
sound = kernel_ver_dir / 'kernel' / 'sound'
pathlist = Path(sound).rglob('*')
return [p for p in pathlist if p.is_file()]
def firmware_files(package: str) -> List[Path]:
"""
Get a list of all firmware files provided by a package
"""
pkg_contents = run(['pacman', '-Flq', package],
capture_output=True, check=True,
encoding='UTF-8').stdout
fw_files = []
firmware = 'usr/lib/firmware'
for path in pkg_contents.splitlines():
# Skip a path if it is to a directory
if (not path.endswith('/')
and (p := Path(path)).is_relative_to(firmware)):
fw_files.append(p.relative_to(firmware))
return fw_files
def modules_requiring_firmware(modules: List[Path],
firmware_files: List[Path]) -> List[ModInfo]:
"""
Get data on the modules that list any of the firmware files
"""
data = []
for module in modules:
try:
info = run(['modinfo', module],
capture_output=True, check=True,
encoding='UTF-8').stdout
# Skip a module if it is not found
except CalledProcessError:
continue
firmware_list = []
for line in info.splitlines():
if line.startswith('description:'):
description = line.split(maxsplit=1)[1]
elif (line.startswith('firmware:')
and (firmware := Path(line.split()[1])) in firmware_files):
firmware_list.append(firmware)
elif line.startswith('name:'):
name = line.split()[1]
if len(firmware_list):
modinfo = ModInfo(name, description, firmware_list)
data.append(modinfo)
return sorted(data, key=lambda module: module.name)
def main() -> None:
"""
Determine which sound loadable kernel modules require firmware
provided by the alsa-firmware package
"""
package = 'alsa-firmware'
try:
modules = sound_modules()
# Modules directory or a kernel directory does not exist
except FileNotFoundError as error:
print(error, file=sys.stderr)
sys.exit(1)
try:
firmware = firmware_files(package)
# Database files do not exist or package was not found
except CalledProcessError as error:
print(error.stderr, end='', file=sys.stderr)
sys.exit(1)
data = modules_requiring_firmware(modules, firmware)
print(f'Sound LKMs with firmware provided by the `{package}` package: ',
end='\n\n')
tuple_str = 'modules = (\n'
for module_data in data:
tuple_str += f"\t'{module_data.name}',\n"
print(module_data, end='\n\n')
for fw_file in module_data.firmware:
if fw_file in firmware:
firmware.remove(fw_file)
tuple_str = tuple_str.removesuffix(',\n') + '\n)'
print('Firmware files without a match to a sound LKM:')
for entry in firmware:
print(entry)
print('\nModules tuple:\n' + tuple_str)
if __name__ == '__main__':
main()