1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3
4# Copyright (c) 2022 Huawei Device Co., Ltd.
5#
6# HDF is dual licensed: you can use it either under the terms of
7# the GPL, or the BSD license, at your option.
8# See the LICENSE file in the root of this repository for complete details.
9
10
11import configparser
12import os
13import re
14from string import Template
15
16import hdf_utils
17from hdf_tool_exception import HdfToolException
18from .linux.kconfig_file_add_config import kconfig_file_operation
19from .linux.mk_file_add_config import audio_linux_makefile_operation, linux_makefile_operation
20
21from .liteos.gn_file_add_config import audio_build_file_operation, build_file_operation, input_build_file_operation
22from .liteos.mk_file_add_config import audio_makefile_file_operation, makefile_file_operation
23from ..hdf_command_error_code import CommandErrorCode
24from ..hdf_defconfig_patch import HdfDefconfigAndPatch
25from ..hdf_device_info_hcs import HdfDeviceInfoHcsFile
26
27
28class HdfAddDriver(object):
29    def __init__(self, args):
30        super(HdfAddDriver, self).__init__()
31        self.root, self.vendor, self.module, self.driver, \
32        self.board, self.kernel, self.device = args
33        self.template_file_path = hdf_utils.get_template_file_path(self.root)
34        if not os.path.exists(self.template_file_path):
35            raise HdfToolException(
36                'template file: %s not exist' %
37                self.template_file_path, CommandErrorCode.TARGET_NOT_EXIST)
38
39    def add_linux(self, driver_file_path, driver_head_path):
40        config_path_result = self.get_kernel_linux_config_path(
41            driver_file_path, driver_head_path)
42        config_path, file_path, defconfig_patch = config_path_result
43        pat_files = []
44        patch_list = defconfig_patch.add_module(
45            config_path, files=pat_files, codetype=None)
46        config_path = defconfig_patch.get_config_patch()
47        def_files = []
48        defconfig_list = defconfig_patch.add_module(
49            config_path, files=def_files, codetype=None)
50        file_path[self.module + "_dot_configs"] = \
51            list(set(patch_list + defconfig_list))
52        return file_path
53
54    def add_liteos(self, driver_file_path, driver_head_path):
55        adapter_hdf = hdf_utils.get_vendor_hdf_dir_adapter(
56            self.root, self.kernel)
57        hdf_utils.judge_file_path_exists(adapter_hdf)
58
59        adapter_model_path = os.path.join(adapter_hdf, 'model', self.module)
60        hdf_utils.judge_file_path_exists(adapter_model_path)
61
62        liteos_file_name = ['BUILD.gn', 'Makefile', 'Kconfig']
63        file_path = {}
64        for file_name in liteos_file_name:
65            file_path = self._liteos_config_file_configure(
66                file_path, file_name, adapter_model_path,
67                driver_file_path, driver_head_path)
68        # Modify hcs file
69        device_info = HdfDeviceInfoHcsFile(
70            self.root, self.vendor, self.module,
71            self.board, self.driver, path="")
72        hcs_file_path = device_info.add_hcs_config_to_exists_model(self.device)
73        file_path["devices_info.hcs"] = hcs_file_path
74
75        dot_file_list = hdf_utils.get_dot_configs_path(
76            self.root, self.vendor, self.board)
77        template_string = "LOSCFG_DRIVERS_HDF_${module_upper}_${driver_upper}=y\n"
78        new_demo_config = Template(template_string).substitute(
79            {"module_upper": self.module.upper(),
80             "driver_upper": self.driver.upper()})
81
82        device_enable = self.__get_enable_config()
83        for dot_file in dot_file_list:
84            file_lines_old = hdf_utils.read_file_lines(dot_file)
85            if device_enable:
86                file_lines = list(
87                    filter(
88                        lambda x: hdf_utils.judge_enable_line(
89                            enable_line=x,
90                            device_base=device_enable.split("=")[0]),
91                        file_lines_old))
92                if device_enable not in file_lines:
93                    file_lines.append(device_enable)
94            else:
95                file_lines = file_lines_old
96            file_lines[-1] = "{}\n".format(file_lines[-1].strip())
97            if new_demo_config not in file_lines:
98                file_lines.append(new_demo_config)
99            hdf_utils.write_file_lines(dot_file, file_lines)
100        file_path[self.module + "_dot_configs"] = dot_file_list
101        return file_path
102
103    def _liteos_config_file_configure(self, file_path, file_name, adapter_model_path,
104                                      driver_file_path, driver_head_path):
105        if file_name == "BUILD.gn":
106            build_file_path = os.path.join(adapter_model_path, file_name)
107            if self.module == "audio":
108                args_tuple = (driver_file_path, driver_head_path, self.module,
109                              self.driver, self.root, self.device, self.kernel)
110                audio_build_file_operation(build_file_path, args_tuple)
111            elif self.module == "input":
112                input_build_file_operation(
113                    build_file_path, driver_file_path[0], driver_head_path[0],
114                    self.module, self.driver)
115            else:
116                build_file_operation(
117                    build_file_path, driver_file_path[0], driver_head_path[0],
118                    self.module, self.driver)
119            file_path['BUILD.gn'] = build_file_path
120
121        elif file_name == "Makefile":
122            makefile_path = os.path.join(adapter_model_path, file_name)
123            if self.module == "audio":
124                args_tuple = (driver_file_path, driver_head_path, self.module,
125                              self.driver, self.root, self.device, self.kernel)
126                audio_makefile_file_operation(makefile_path, args_tuple)
127            else:
128                makefile_file_operation(
129                    makefile_path, driver_file_path[0], driver_head_path[0],
130                    self.module, self.driver, self.root)
131            file_path['Makefile'] = makefile_path
132
133        elif file_name == "Kconfig":
134            kconfig_path = os.path.join(adapter_model_path, file_name)
135            kconfig_file_operation(kconfig_path, self.module,
136                                   self.driver, self.template_file_path)
137            file_path['Kconfig'] = kconfig_path
138        return file_path
139
140    def add_kernel(self, driver_file_path, driver_head_path):
141        config_path_result = self.get_kernel_linux_config_path(
142            driver_file_path, driver_head_path)
143        config_path, file_path, defconfig_patch = config_path_result
144        files = []
145        patch_list = defconfig_patch.add_module(
146            config_path, files=files, codetype=None)
147        config_path = defconfig_patch.get_config_patch()
148        files1 = []
149        defconfig_list = defconfig_patch.add_module(
150            config_path, files=files1, codetype=None)
151        file_path[self.module + "_dot_configs"] = \
152            list(set(patch_list + defconfig_list))
153        return file_path
154
155    def get_kernel_linux_config_path(self, driver_file_path, driver_head_path):
156        file_path = {}
157        file_path.update(self.linux_operation_config(driver_file_path, driver_head_path))
158
159        device_info = HdfDeviceInfoHcsFile(self.root, self.vendor,
160                                           self.module, self.board,
161                                           self.driver, path="")
162        hcs_file_path = device_info.add_hcs_config_to_exists_model(self.device)
163        file_path["devices_info.hcs"] = hcs_file_path
164        device_enable_config_line = self.__get_enable_config()
165        template_string = "CONFIG_DRIVERS_HDF_${module_upper}_${driver_upper}=y\n"
166        data_model = {
167            "module_upper": self.module.upper(),
168            "driver_upper": self.driver.upper()
169        }
170
171        new_demo_config = Template(template_string).substitute(data_model)
172        if device_enable_config_line:
173            new_demo_config_list = [device_enable_config_line, new_demo_config]
174        else:
175            new_demo_config_list = [new_demo_config]
176        defconfig_patch = HdfDefconfigAndPatch(
177            self.root, self.vendor, self.kernel, self.board,
178            data_model, new_demo_config_list)
179
180        config_path = defconfig_patch.get_config_config()
181        return config_path, file_path, defconfig_patch
182
183    def driver_create_info_format(self, config_file_json,
184                                  config_item, file_path):
185        board_type = config_file_json.get(self.board)
186        if board_type is None:
187            config_file_json[self.board] = {
188                config_item.get("module_name"): {
189                    'module_level_config': {},
190                    "driver_file_list": {
191                        config_item.get("driver_name"):
192                            config_item.get("driver_file_path") +
193                            config_item.get("head_file_path")
194                    }
195                }
196            }
197            config_file_json[self.board][self.module]["module_level_config"]\
198                .update(file_path)
199        else:
200            model_type = board_type.get(config_item.get("module_name"))
201            if model_type is None:
202                temp = config_file_json.get(self.board)
203                temp_module = config_item.get("module_name")
204                temp[temp_module] = {
205                    'module_level_config': {},
206                    "driver_file_list": {
207                        config_item.get("driver_name"):
208                            config_item.get("driver_file_path") +
209                            config_item.get("head_file_path")
210                    }
211                }
212                config_file_json.get(self.board).get(self.module).\
213                    get("module_level_config").update(file_path)
214            else:
215                temp = config_file_json.get(self.board).\
216                    get(config_item.get("module_name")).get("driver_file_list")
217                temp[config_item.get("driver_name")] = \
218                    config_item.get("driver_file_path") + \
219                    config_item.get("head_file_path")
220        return config_file_json
221
222    def add_driver(self, *args_tuple):
223        root, vendor, module, driver, board, kernel, device = args_tuple
224        drv_converter = hdf_utils.WordsConverter(driver)
225        dev_converter = hdf_utils.WordsConverter(device)
226        # create driver file path
227        source_file, head_path = self.create_model_file_name(
228            root, vendor, module, driver, board, kernel, device)
229        data_model = {
230            'driver_lower_case': drv_converter.lower_case(),
231            'driver_upper_camel_case': drv_converter.upper_camel_case(),
232            'driver_lower_camel_case': drv_converter.lower_camel_case(),
233            'driver_upper_case': drv_converter.upper_case(),
234            'device_lower_case': dev_converter.lower_case(),
235            'device_upper_camel_case': dev_converter.upper_camel_case(),
236            'device_lower_camel_case': dev_converter.lower_camel_case(),
237            'device_upper_case': dev_converter.upper_case()
238        }
239        templates_list, target_path = self.get_model_template_list(module, board)
240        source_file_list, source_statu_exist = self.get_template_source_file(
241            source_file, data_model, templates_list, target_path, args_tuple)
242        head_path_list, head_statu_exist = self.get_template_head_file(
243            head_path, data_model, templates_list, target_path, args_tuple)
244        if head_statu_exist and source_statu_exist:
245            return True, source_file_list, head_path_list
246        child_dir_list, operation_object = hdf_utils.ini_file_read_operation(
247            section_name=module, node_name='file_dir')
248        if device not in child_dir_list:
249            child_dir_list.append(device)
250            hdf_utils.ini_file_write_operation(
251                module, operation_object, child_dir_list)
252        return True, source_file_list, head_path_list
253
254    def get_template_source_file(self, source_file, data_model,
255                                 templates_list, target_path, *args_tuple):
256        # find model template .c
257        source_statu_exist = False
258        root, vendor, module, driver, board, kernel, device = args_tuple[0]
259        if module == "audio" or module == "display":
260            if board.startswith("rk3568"):
261                source_file_template_list = \
262                    list(filter(
263                        lambda file_name: "source" in file_name and
264                                          file_name.startswith("rk"),
265                        templates_list))
266            else:
267                source_file_template_list = \
268                    list(filter(
269                        lambda file_name: "source" in file_name and
270                                          file_name.startswith("hi"),
271                        templates_list))
272        elif module == "sensor":
273            source_file_template_list = self._sensor_source_head("source", templates_list)
274        else:
275            source_file_template_list = \
276                list(filter(
277                    lambda file_name: "source" in file_name,
278                    templates_list))
279        source_file_template = \
280            list(map(
281                lambda template_name: os.path.join(target_path, template_name),
282                source_file_template_list))
283        path_list = list(os.path.split(source_file))
284        temp_path = os.path.sep.join(path_list[:-1])
285        if not os.path.exists(temp_path):
286            os.makedirs(temp_path)
287
288        source_file_list = []
289        for source_file_temp in source_file_template:
290            if not os.path.exists(source_file):
291                os.makedirs(source_file)
292            create_name = re.search(r'[a-z]+_source', source_file_temp).group()
293            create_source_name = "%s_%s_%s.c" % (device, driver, create_name.split("_")[0])
294            data_model.update({'include_file': "%s_%s_%s.h" % (device, driver, create_name.split("_")[0])})
295            source_file_name = os.path.join(source_file, create_source_name)
296            if os.path.exists(source_file_name):
297                source_statu_exist = True
298                source_file_list.append(source_file_name)
299            else:
300                self._template_fill(source_file_temp, source_file_name, data_model)
301                source_file_list.append(source_file_name)
302        return source_file_list, source_statu_exist
303
304    def get_template_head_file(
305            self, head_path, data_model, templates_list, target_path, *args_tuple):
306        # find model template .h
307        head_statu_exist = False
308        root, vendor, module, driver, board, kernel, device = args_tuple[0]
309        if module == "audio":
310            if board.startswith("rk3568"):
311                head_file_template_list = list(filter(
312                    lambda file_name:
313                    ("head" in file_name and file_name.startswith("rk")),
314                    templates_list))
315            else:
316                head_file_template_list = list(filter(
317                    lambda file_name:
318                    ("head" in file_name and file_name.startswith("hi")),
319                    templates_list))
320        elif module == "sensor":
321            head_file_template_list = self._sensor_source_head("head", templates_list)
322        else:
323            head_file_template_list = list(filter(
324                lambda file_name: "head" in file_name, templates_list))
325        head_file_template = list(map(
326            lambda template_name: os.path.join(target_path, template_name),
327            head_file_template_list))
328        path_list = list(os.path.split(head_path))
329        temp_path = os.path.sep.join(path_list[:-1])
330        if not os.path.exists(temp_path):
331            os.makedirs(temp_path)
332        head_path_list = []
333        for head_file_temp in head_file_template:
334            if not os.path.exists(head_path):
335                os.makedirs(head_path)
336            create_name = re.search(r'[a-z]+_head', head_file_temp).group()
337            create_head_name = "%s_%s_%s.h" % (device, driver,
338                                               create_name.split("_")[0])
339            head_file_name = os.path.join(head_path, create_head_name)
340            if os.path.exists(head_file_name):
341                head_statu_exist = True
342                head_path_list.append(head_file_name)
343            else:
344                self._template_fill(head_file_temp, head_file_name, data_model)
345                head_path_list.append(head_file_name)
346        return head_path_list, head_statu_exist
347
348    def _sensor_source_head(self, file_type, templates_list):
349        kernel_base_device = f"{self.kernel}_base_device"
350        base_device_list, _ = hdf_utils.ini_file_read_operation(
351            section_name=self.module, node_name=kernel_base_device)
352        if file_type == "head":
353            if self.device == "als" or self.device == "hall" or self.device == "ppg":
354                head_file_template_list = \
355                    list(filter(
356                        lambda file_name: "head" in file_name and
357                                          file_name.startswith(self.device),
358                        templates_list))
359            elif self.device in base_device_list:
360                head_file_template_list = \
361                    list(filter(
362                        lambda file_name: "head" in file_name and
363                                          file_name.startswith("accel"),
364                        templates_list))
365            else:
366                head_file_template_list = \
367                    list(filter(
368                        lambda file_name: "head" in file_name and
369                                          file_name.startswith("com"),
370                        templates_list))
371            return head_file_template_list
372        else:
373            if self.device == "als" or self.device == "hall" or self.device == "ppg":
374                source_file_template_list = \
375                    list(filter(
376                        lambda file_name: "source" in file_name and
377                                          file_name.startswith(self.device),
378                        templates_list))
379            elif self.device in base_device_list:
380                source_file_template_list = \
381                    list(filter(
382                        lambda file_name: "source" in file_name and
383                                          file_name.startswith("accel"),
384                        templates_list))
385            else:
386                source_file_template_list = \
387                    list(filter(
388                        lambda file_name: "source" in file_name and
389                                          file_name.startswith("com"),
390                        templates_list))
391            return source_file_template_list
392
393    def _file_gen_lite(self, template, source_file_path, model):
394        templates_dir = hdf_utils.get_templates_lite_dir()
395        template_path = os.path.join(templates_dir, template)
396        self._template_fill(template_path, source_file_path, model)
397
398    def _template_fill(self, template_path, output_path, data_model):
399        if not os.path.exists(template_path):
400            return
401        raw_content = hdf_utils.read_file(template_path)
402        contents = Template(raw_content).safe_substitute(data_model)
403        hdf_utils.write_file(output_path, contents)
404
405    def create_model_file_name(self, *args_tuple):
406        root, vendor, module, driver, board, kernel, device = args_tuple
407        drv_src_dir = hdf_utils.get_drv_src_dir(root, module)
408        if device.strip():
409            if module == "sensor":
410                relatively_path, _ = hdf_utils.ini_file_read_operation(
411                    section_name=module, node_name='driver_path')
412                new_mkdir_path = os.path.join(root, relatively_path, device)
413            elif module == "audio":
414                relatively_path_dict, _ = hdf_utils.ini_file_read_operation(
415                    section_name=module, node_name='driver_path')
416                if board.startswith("rk3568"):
417                    relatively_path = relatively_path_dict["rk3568"]
418                else:
419                    relatively_path = relatively_path_dict["hi3516"]
420                new_mkdir_path = os.path.join(
421                    root, relatively_path, device)
422            else:
423                new_mkdir_path = os.path.join(drv_src_dir, device)
424
425            if not os.path.exists(new_mkdir_path):
426                os.mkdir(new_mkdir_path)
427            if module == "sensor":
428                result_path_source = new_mkdir_path
429                result_path_head = new_mkdir_path
430            else:
431                result_path_source = os.path.join(new_mkdir_path, 'src')
432                result_path_head = os.path.join(new_mkdir_path, 'include')
433        else:
434            if module == "sensor":
435                new_mkdir_path = os.path.join(drv_src_dir, 'chipset', driver)
436            else:
437                new_mkdir_path = os.path.join(drv_src_dir, driver)
438            if not os.path.exists(new_mkdir_path):
439                os.mkdir(new_mkdir_path)
440            result_path_source = os.path.join(
441                new_mkdir_path, '%s_driver.c' % driver)
442            result_path_head = os.path.join(
443                new_mkdir_path, '%s_driver.h' % driver)
444        return result_path_source, result_path_head
445
446    def __get_enable_config(self):
447        device_enable_config = None
448        templates_dir = hdf_utils.get_templates_lite_dir()
449        templates_model_dir = []
450        for path, dir_name, _ in os.walk(templates_dir):
451            if dir_name:
452                templates_model_dir.extend(dir_name)
453        templates_model_dir = list(
454            filter(
455                lambda model_dir: self.module in model_dir,
456                templates_model_dir))
457        config_file = [
458            name for name in os.listdir(
459                os.path.join(
460                    templates_dir,
461                    templates_model_dir[0])) if name.endswith("ini")]
462        if config_file:
463            config_path = os.path.join(
464                templates_dir,
465                templates_model_dir[0],
466                config_file[0])
467            config = configparser.ConfigParser()
468            config.read(config_path)
469            section_list = config.options(section=self.kernel)
470            if self.device in section_list:
471                device_enable_config, _ = hdf_utils.ini_file_read_operation(
472                    section_name=self.kernel,
473                    node_name=self.device, path=config_path)
474            else:
475                if self.kernel == "linux":
476                    device_enable_config = [
477                        "CONFIG_DRIVERS_HDF_SENSOR_ACCEL=y\n"]
478                else:
479                    device_enable_config = [
480                        "LOSCFG_DRIVERS_HDF_SENSOR_ACCEL=y\n"]
481
482        if device_enable_config:
483            return device_enable_config[0]
484        else:
485            return ""
486
487    def get_model_template_list(self, module, board):
488        templates_dir = hdf_utils.get_templates_lite_dir()
489        templates_model_dir = []
490        for path, dir_name, _ in os.walk(templates_dir):
491            if dir_name:
492                templates_model_dir.extend(dir_name)
493        templates_model_dir = list(filter(
494            lambda model_dir: self.module in model_dir,
495            templates_model_dir))
496        target_template_path = list(map(
497            lambda dir_name: os.path.join(templates_dir, dir_name),
498            templates_model_dir))[0]
499        templates_file_list = os.listdir(target_template_path)
500        if module == "audio" and board.startswith("hispark_taurus"):
501            templates_file_list = list(filter(
502                lambda x: x.startswith("hi35xx"), templates_file_list))
503        return templates_file_list, target_template_path
504
505    def linux_operation_config(self, driver_file_path, driver_head_path):
506        adapter_hdf = hdf_utils.get_vendor_hdf_dir_adapter(
507            self.root, self.kernel)
508        hdf_utils.judge_file_path_exists(adapter_hdf)
509
510        adapter_model_path = os.path.join(adapter_hdf, 'model', self.module)
511        hdf_utils.judge_file_path_exists(adapter_model_path)
512
513        liteos_file_name = ['Makefile', 'Kconfig']
514        file_path_temp = {}
515        for file_name in liteos_file_name:
516            if file_name == "Makefile":
517                linux_makefile_file_path = os.path.join(adapter_model_path, file_name)
518                if self.module == "audio":
519                    args_tuple = (driver_file_path, driver_head_path, self.module,
520                                  self.driver, self.root, self.device, self.board)
521                    linux_makefile_file_path = audio_linux_makefile_operation(
522                        linux_makefile_file_path, args_tuple)
523                else:
524                    linux_makefile_operation(
525                        linux_makefile_file_path, driver_file_path[0], driver_head_path[0],
526                        self.module, self.driver)
527                file_path_temp['Makefile'] = linux_makefile_file_path
528
529            elif file_name == "Kconfig":
530                kconfig_path = os.path.join(adapter_model_path, file_name)
531                kconfig_file_operation(kconfig_path, self.module,
532                                       self.driver, self.template_file_path)
533                file_path_temp['Kconfig'] = kconfig_path
534        return file_path_temp
535
536