summaryrefslogtreecommitdiff
path: root/utils/gen-controls.py
blob: 3f99b5e2ba7d24b0dca6ddf54ae5554c6b1e4bff (plain)
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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0-or-later
# Copyright (C) 2019, Google Inc.
#
# Author: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
#
# gen-controls.py - Generate control definitions from YAML

import argparse
import string
import sys
import yaml


def snake_case(s):
    return ''.join([c.isupper() and ('_' + c) or c for c in s]).strip('_')


def format_description(description):
    description = description.strip('\n').split('\n')
    description[0] = '\\brief ' + description[0]
    return '\n'.join([(line and ' * ' or ' *') + line for line in description])


def generate_cpp(controls):
    enum_doc_start_template = string.Template('''/**
 * \\enum ${name}Enum
 * \\brief Supported ${name} values''')
    enum_doc_value_template = string.Template(''' * \\var ${value}
${description}''')
    doc_template = string.Template('''/**
 * \\var ${name}
${description}
 */''')
    def_template = string.Template('extern const Control<${type}> ${name}(${id_name}, "${name}");')
    enum_values_doc = string.Template('''/**
 * \\var ${name}Values
 * \\brief List of all $name supported values
 */''')
    enum_values_start = string.Template('''extern const std::array<const ControlValue, ${size}> ${name}Values = {''')
    enum_values_values = string.Template('''\tstatic_cast<int32_t>(${name}),''')

    ctrls_doc = []
    ctrls_def = []
    draft_ctrls_doc = []
    draft_ctrls_def = []
    ctrls_map = []

    for ctrl in controls:
        name, ctrl = ctrl.popitem()
        id_name = snake_case(name).upper()

        ctrl_type = ctrl['type']
        if ctrl_type == 'string':
            ctrl_type = 'std::string'
        elif ctrl.get('size'):
            ctrl_type = 'Span<const %s>' % ctrl_type

        info = {
            'name': name,
            'type': ctrl_type,
            'description': format_description(ctrl['description']),
            'id_name': id_name,
        }

        target_doc = ctrls_doc
        target_def = ctrls_def
        if ctrl.get('draft'):
            target_doc = draft_ctrls_doc
            target_def = draft_ctrls_def

        enum = ctrl.get('enum')
        if enum:
            enum_doc = []
            enum_doc.append(enum_doc_start_template.substitute(info))

            num_entries = 0
            for entry in enum:
                value_info = {
                    'name': name,
                    'value': entry['name'],
                    'description': format_description(entry['description']),
                }
                enum_doc.append(enum_doc_value_template.substitute(value_info))
                num_entries += 1

            enum_doc = '\n *\n'.join(enum_doc)
            enum_doc += '\n */'
            target_doc.append(enum_doc)

            values_info = {
                'name': info['name'],
                'size': num_entries,
            }
            target_doc.append(enum_values_doc.substitute(values_info))
            target_def.append(enum_values_start.substitute(values_info))
            for entry in enum:
                value_info = {
                    'name': entry['name']
                }
                target_def.append(enum_values_values.substitute(value_info))
            target_def.append("};")

        target_doc.append(doc_template.substitute(info))
        target_def.append(def_template.substitute(info))

        if ctrl.get('draft'):
            name = 'draft::' + name

        ctrls_map.append('\t{ ' + id_name + ', &' + name + ' },')

    return {
        'controls_doc': '\n\n'.join(ctrls_doc),
        'controls_def': '\n'.join(ctrls_def),
        'draft_controls_doc': '\n\n'.join(draft_ctrls_doc),
        'draft_controls_def': '\n\n'.join(draft_ctrls_def),
        'controls_map': '\n'.join(ctrls_map),
    }


def generate_h(controls):
    enum_template_start = string.Template('''enum ${name}Enum {''')
    enum_value_template = string.Template('''\t${name} = ${value},''')
    enum_values_template = string.Template('''extern const std::array<const ControlValue, ${size}> ${name}Values;''')
    template = string.Template('''extern const Control<${type}> ${name};''')

    ctrls = []
    draft_ctrls = []
    ids = []
    id_value = 1

    for ctrl in controls:
        name, ctrl = ctrl.popitem()
        id_name = snake_case(name).upper()

        ids.append('\t' + id_name + ' = ' + str(id_value) + ',')

        ctrl_type = ctrl['type']
        if ctrl_type == 'string':
            ctrl_type = 'std::string'
        elif ctrl.get('size'):
            ctrl_type = 'Span<const %s>' % ctrl_type

        info = {
            'name': name,
            'type': ctrl_type,
        }

        target_ctrls = ctrls
        if ctrl.get('draft'):
            target_ctrls = draft_ctrls

        enum = ctrl.get('enum')
        if enum:
            target_ctrls.append(enum_template_start.substitute(info))

            num_entries = 0
            for entry in enum:
                value_info = {
                    'name': entry['name'],
                    'value': entry['value'],
                }
                target_ctrls.append(enum_value_template.substitute(value_info))
                num_entries += 1
            target_ctrls.append("};")

            values_info = {
                'name': info['name'],
                'size': num_entries,
            }
            target_ctrls.append(enum_values_template.substitute(values_info))

        target_ctrls.append(template.substitute(info))
        id_value += 1

    return {
        'ids': '\n'.join(ids),
        'controls': '\n'.join(ctrls),
        'draft_controls': '\n'.join(draft_ctrls)
    }


def fill_template(template, data):

    template = open(template, 'rb').read()
    template = template.decode('utf-8')
    template = string.Template(template)
    return template.substitute(data)


def main(argv):

    # Parse command line arguments
    parser = argparse.ArgumentParser()
    parser.add_argument('-o', dest='output', metavar='file', type=str,
                        help='Output file name. Defaults to standard output if not specified.')
    parser.add_argument('input', type=str,
                        
} __attribute__ ((packed));

/* ioctls */

#define MEDIA_IOC_DEVICE_INFO	_IOWR('|', 0x00, struct media_device_info)
#define MEDIA_IOC_ENUM_ENTITIES	_IOWR('|', 0x01, struct media_entity_desc)
#define MEDIA_IOC_ENUM_LINKS	_IOWR('|', 0x02, struct media_links_enum)
#define MEDIA_IOC_SETUP_LINK	_IOWR('|', 0x03, struct media_link_desc)
#define MEDIA_IOC_G_TOPOLOGY	_IOWR('|', 0x04, struct media_v2_topology)
#define MEDIA_IOC_REQUEST_ALLOC	_IOR ('|', 0x05, int)

/*
 * These ioctls are called on the request file descriptor as returned
 * by MEDIA_IOC_REQUEST_ALLOC.
 */
#define MEDIA_REQUEST_IOC_QUEUE		_IO('|',  0x80)
#define MEDIA_REQUEST_IOC_REINIT	_IO('|',  0x81)


/*
 * Legacy symbols used to avoid userspace compilation breakages.
 * Do not use
    
 *
 * Those symbols map the entity function into types and should be
 * used only on legacy programs for legacy hardware. Don't rely
 * on those for MEDIA_IOC_G_TOPOLOGY.
 */
#define MEDIA_ENT_TYPE_SHIFT			16
#define MEDIA_ENT_TYPE_MASK			0x00ff0000
#define MEDIA_ENT_SUBTYPE_MASK			0x0000ffff

#define MEDIA_ENT_T_DEVNODE_UNKNOWN		(MEDIA_ENT_F_OLD_BASE | \
						 MEDIA_ENT_SUBTYPE_MASK)

#define MEDIA_ENT_T_DEVNODE			MEDIA_ENT_F_OLD_BASE
#define MEDIA_ENT_T_DEVNODE_V4L			MEDIA_ENT_F_IO_V4L
#define MEDIA_ENT_T_DEVNODE_FB			(MEDIA_ENT_F_OLD_BASE + 2)
#define MEDIA_ENT_T_DEVNODE_ALSA		(MEDIA_ENT_F_OLD_BASE + 3)
#define MEDIA_ENT_T_DEVNODE_DVB			(MEDIA_ENT_F_OLD_BASE + 4)

#define MEDIA_ENT_T_UNKNOWN			MEDIA_ENT_F_UNKNOWN
#define MEDIA_ENT_T_V4L2_VIDEO			MEDIA_ENT_F_IO_V4L
#define MEDIA_ENT_T_V4L2_SUBDEV			MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN
#define MEDIA_ENT_T_V4L2_SUBDEV_SENSOR		MEDIA_ENT_F_CAM_SENSOR
#define MEDIA_ENT_T_V4L2_SUBDEV_FLASH		MEDIA_ENT_F_FLASH
#define MEDIA_ENT_T_V4L2_SUBDEV_LENS		MEDIA_ENT_F_LENS
#define MEDIA_ENT_T_V4L2_SUBDEV_DECODER		MEDIA_ENT_F_ATV_DECODER
#define MEDIA_ENT_T_V4L2_SUBDEV_TUNER		MEDIA_ENT_F_TUNER

#define MEDIA_ENT_F_DTV_DECODER			MEDIA_ENT_F_DV_DECODER

/*
 * There is still no full ALSA support in the media controller. These
 * defines should not have been added and we leave them here only
 * in case some application tries to use these defines.
 *
 * The ALSA defines that are in use have been moved into __KERNEL__
 * scope. As support gets added to these interface types, they should
 * be moved into __KERNEL__ scope with the code that uses them.
 */
#define MEDIA_INTF_T_ALSA_COMPRESS             (MEDIA_INTF_T_ALSA_BASE + 3)
#define MEDIA_INTF_T_ALSA_RAWMIDI              (MEDIA_INTF_T_ALSA_BASE + 4)
#define MEDIA_INTF_T_ALSA_HWDEP                (MEDIA_INTF_T_ALSA_BASE + 5)
#define MEDIA_INTF_T_ALSA_SEQUENCER            (MEDIA_INTF_T_ALSA_BASE + 6)
#define MEDIA_INTF_T_ALSA_TIMER                (MEDIA_INTF_T_ALSA_BASE + 7)

/* Obsolete symbol for media_version, no longer used in the kernel */
#define MEDIA_API_VERSION			((0 << 16) | (1 << 8) | 0)


#endif /* __LINUX_MEDIA_H */