Merge tag 'cxl-for-5.16' of git://git.kernel.org/pub/scm/linux/kernel/git/cxl/cxl
[linux-2.6-microblaze.git] / drivers / gpu / drm / selftests / test-drm_framebuffer.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Test cases for the drm_framebuffer functions
4  */
5
6 #include <linux/kernel.h>
7
8 #include <drm/drm_device.h>
9 #include <drm/drm_mode.h>
10 #include <drm/drm_fourcc.h>
11 #include <drm/drm_print.h>
12
13 #include "../drm_crtc_internal.h"
14
15 #include "test-drm_modeset_common.h"
16
17 #define MIN_WIDTH 4
18 #define MAX_WIDTH 4096
19 #define MIN_HEIGHT 4
20 #define MAX_HEIGHT 4096
21
22 struct drm_framebuffer_test {
23         int buffer_created;
24         struct drm_mode_fb_cmd2 cmd;
25         const char *name;
26 };
27
28 static struct drm_framebuffer_test createbuffer_tests[] = {
29 { .buffer_created = 1, .name = "ABGR8888 normal sizes",
30         .cmd = { .width = 600, .height = 600, .pixel_format = DRM_FORMAT_ABGR8888,
31                  .handles = { 1, 0, 0 }, .pitches = { 4 * 600, 0, 0 },
32         }
33 },
34 { .buffer_created = 1, .name = "ABGR8888 max sizes",
35         .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
36                  .handles = { 1, 0, 0 }, .pitches = { 4 * MAX_WIDTH, 0, 0 },
37         }
38 },
39 { .buffer_created = 1, .name = "ABGR8888 pitch greater than min required",
40         .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
41                  .handles = { 1, 0, 0 }, .pitches = { 4 * MAX_WIDTH + 1, 0, 0 },
42         }
43 },
44 { .buffer_created = 0, .name = "ABGR8888 pitch less than min required",
45         .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
46                  .handles = { 1, 0, 0 }, .pitches = { 4 * MAX_WIDTH - 1, 0, 0 },
47         }
48 },
49 { .buffer_created = 0, .name = "ABGR8888 Invalid width",
50         .cmd = { .width = MAX_WIDTH + 1, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
51                  .handles = { 1, 0, 0 }, .pitches = { 4 * (MAX_WIDTH + 1), 0, 0 },
52         }
53 },
54 { .buffer_created = 0, .name = "ABGR8888 Invalid buffer handle",
55         .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
56                  .handles = { 0, 0, 0 }, .pitches = { 4 * MAX_WIDTH, 0, 0 },
57         }
58 },
59 { .buffer_created = 0, .name = "No pixel format",
60         .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = 0,
61                  .handles = { 1, 0, 0 }, .pitches = { 4 * MAX_WIDTH, 0, 0 },
62         }
63 },
64 { .buffer_created = 0, .name = "ABGR8888 Width 0",
65         .cmd = { .width = 0, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
66                  .handles = { 1, 0, 0 }, .pitches = { 4 * MAX_WIDTH, 0, 0 },
67         }
68 },
69 { .buffer_created = 0, .name = "ABGR8888 Height 0",
70         .cmd = { .width = MAX_WIDTH, .height = 0, .pixel_format = DRM_FORMAT_ABGR8888,
71                  .handles = { 1, 0, 0 }, .pitches = { 4 * MAX_WIDTH, 0, 0 },
72         }
73 },
74 { .buffer_created = 0, .name = "ABGR8888 Out of bound height * pitch combination",
75         .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
76                  .handles = { 1, 0, 0 }, .offsets = { UINT_MAX - 1, 0, 0 }, .pitches = { 4 * MAX_WIDTH, 0, 0 },
77         }
78 },
79 { .buffer_created = 1, .name = "ABGR8888 Large buffer offset",
80         .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
81                  .handles = { 1, 0, 0 }, .offsets = { UINT_MAX / 2, 0, 0 }, .pitches = { 4 * MAX_WIDTH, 0, 0 },
82         }
83 },
84 { .buffer_created = 1, .name = "ABGR8888 Set DRM_MODE_FB_MODIFIERS without modifiers",
85         .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
86                  .handles = { 1, 0, 0 }, .offsets = { UINT_MAX / 2, 0, 0 },
87                  .pitches = { 4 * MAX_WIDTH, 0, 0 }, .flags = DRM_MODE_FB_MODIFIERS,
88         }
89 },
90 { .buffer_created = 1, .name = "ABGR8888 Valid buffer modifier",
91         .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
92                  .handles = { 1, 0, 0 }, .offsets = { UINT_MAX / 2, 0, 0 }, .pitches = { 4 * MAX_WIDTH, 0, 0 },
93                  .flags = DRM_MODE_FB_MODIFIERS, .modifier = { AFBC_FORMAT_MOD_YTR, 0, 0 },
94         }
95 },
96 { .buffer_created = 0, .name = "ABGR8888 Invalid buffer modifier(DRM_FORMAT_MOD_SAMSUNG_64_32_TILE)",
97         .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
98                  .handles = { 1, 0, 0 }, .offsets = { UINT_MAX / 2, 0, 0 },
99                  .pitches = { 4 * MAX_WIDTH, 0, 0 }, .flags = DRM_MODE_FB_MODIFIERS,
100                  .modifier = { DRM_FORMAT_MOD_SAMSUNG_64_32_TILE, 0, 0 },
101         }
102 },
103 { .buffer_created = 1, .name = "ABGR8888 Extra pitches without DRM_MODE_FB_MODIFIERS",
104         .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
105                  .handles = { 1, 0, 0 }, .offsets = { UINT_MAX / 2, 0, 0 },
106                  .pitches = { 4 * MAX_WIDTH, 4 * MAX_WIDTH, 0 },
107         }
108 },
109 { .buffer_created = 0, .name = "ABGR8888 Extra pitches with DRM_MODE_FB_MODIFIERS",
110         .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
111                  .handles = { 1, 0, 0 }, .flags = DRM_MODE_FB_MODIFIERS,
112                  .pitches = { 4 * MAX_WIDTH, 4 * MAX_WIDTH, 0 },
113         }
114 },
115 { .buffer_created = 1, .name = "NV12 Normal sizes",
116         .cmd = { .width = 600, .height = 600, .pixel_format = DRM_FORMAT_NV12,
117                  .handles = { 1, 1, 0 }, .pitches = { 600, 600, 0 },
118         }
119 },
120 { .buffer_created = 1, .name = "NV12 Max sizes",
121         .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_NV12,
122                  .handles = { 1, 1, 0 }, .pitches = { MAX_WIDTH, MAX_WIDTH, 0 },
123         }
124 },
125 { .buffer_created = 0, .name = "NV12 Invalid pitch",
126         .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_NV12,
127                  .handles = { 1, 1, 0 }, .pitches = { MAX_WIDTH, MAX_WIDTH - 1, 0 },
128         }
129 },
130 { .buffer_created = 0, .name = "NV12 Invalid modifier/missing DRM_MODE_FB_MODIFIERS flag",
131         .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_NV12,
132                  .handles = { 1, 1, 0 }, .modifier = { DRM_FORMAT_MOD_SAMSUNG_64_32_TILE, 0, 0 },
133                  .pitches = { MAX_WIDTH, MAX_WIDTH, 0 },
134         }
135 },
136 { .buffer_created = 0, .name = "NV12 different  modifier per-plane",
137         .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_NV12,
138                  .handles = { 1, 1, 0 }, .flags = DRM_MODE_FB_MODIFIERS,
139                  .modifier = { DRM_FORMAT_MOD_SAMSUNG_64_32_TILE, 0, 0 },
140                  .pitches = { MAX_WIDTH, MAX_WIDTH, 0 },
141         }
142 },
143 { .buffer_created = 1, .name = "NV12 with DRM_FORMAT_MOD_SAMSUNG_64_32_TILE",
144         .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_NV12,
145                  .handles = { 1, 1, 0 }, .flags = DRM_MODE_FB_MODIFIERS,
146                  .modifier = { DRM_FORMAT_MOD_SAMSUNG_64_32_TILE, DRM_FORMAT_MOD_SAMSUNG_64_32_TILE, 0 },
147                  .pitches = { MAX_WIDTH, MAX_WIDTH, 0 },
148         }
149 },
150 { .buffer_created = 0, .name = "NV12 Valid modifiers without DRM_MODE_FB_MODIFIERS",
151         .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_NV12,
152                  .handles = { 1, 1, 0 }, .modifier = { DRM_FORMAT_MOD_SAMSUNG_64_32_TILE,
153                                                        DRM_FORMAT_MOD_SAMSUNG_64_32_TILE, 0 },
154                  .pitches = { MAX_WIDTH, MAX_WIDTH, 0 },
155         }
156 },
157 { .buffer_created = 0, .name = "NV12 Modifier for inexistent plane",
158         .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_NV12,
159                  .handles = { 1, 1, 0 }, .flags = DRM_MODE_FB_MODIFIERS,
160                  .modifier = { DRM_FORMAT_MOD_SAMSUNG_64_32_TILE, DRM_FORMAT_MOD_SAMSUNG_64_32_TILE,
161                                DRM_FORMAT_MOD_SAMSUNG_64_32_TILE },
162                  .pitches = { MAX_WIDTH, MAX_WIDTH, 0 },
163         }
164 },
165 { .buffer_created = 0, .name = "NV12 Handle for inexistent plane",
166         .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_NV12,
167                  .handles = { 1, 1, 1 }, .flags = DRM_MODE_FB_MODIFIERS, .pitches = { MAX_WIDTH, MAX_WIDTH, 0 },
168         }
169 },
170 { .buffer_created = 1, .name = "NV12 Handle for inexistent plane without DRM_MODE_FB_MODIFIERS",
171         .cmd = { .width = 600, .height = 600, .pixel_format = DRM_FORMAT_NV12,
172                  .handles = { 1, 1, 1 }, .pitches = { 600, 600, 600 },
173         }
174 },
175 { .buffer_created = 1, .name = "YVU420 Normal sizes",
176         .cmd = { .width = 600, .height = 600, .pixel_format = DRM_FORMAT_YVU420,
177                  .handles = { 1, 1, 1 }, .flags = DRM_MODE_FB_MODIFIERS,
178                  .pitches = { 600, 300, 300 },
179         }
180 },
181 { .buffer_created = 1, .name = "YVU420 DRM_MODE_FB_MODIFIERS set without modifier",
182         .cmd = { .width = 600, .height = 600, .pixel_format = DRM_FORMAT_YVU420,
183                  .handles = { 1, 1, 1 }, .pitches = { 600, 300, 300 },
184         }
185 },
186 { .buffer_created = 1, .name = "YVU420 Max sizes",
187         .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_YVU420,
188                  .handles = { 1, 1, 1 }, .pitches = { MAX_WIDTH, DIV_ROUND_UP(MAX_WIDTH, 2),
189                                                       DIV_ROUND_UP(MAX_WIDTH, 2) },
190         }
191 },
192 { .buffer_created = 0, .name = "YVU420 Invalid pitch",
193         .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_YVU420,
194                  .handles = { 1, 1, 1 }, .pitches = { MAX_WIDTH, DIV_ROUND_UP(MAX_WIDTH, 2) - 1,
195                                                       DIV_ROUND_UP(MAX_WIDTH, 2) },
196         }
197 },
198 { .buffer_created = 1, .name = "YVU420 Different pitches",
199         .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_YVU420,
200                  .handles = { 1, 1, 1 }, .pitches = { MAX_WIDTH, DIV_ROUND_UP(MAX_WIDTH, 2) + 1,
201                                                       DIV_ROUND_UP(MAX_WIDTH, 2) + 7 },
202         }
203 },
204 { .buffer_created = 1, .name = "YVU420 Different buffer offsets/pitches",
205         .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_YVU420,
206                  .handles = { 1, 1, 1 }, .offsets = { MAX_WIDTH, MAX_WIDTH  + MAX_WIDTH * MAX_HEIGHT,
207                                                       MAX_WIDTH  + 2 * MAX_WIDTH * MAX_HEIGHT },
208                  .pitches = { MAX_WIDTH, DIV_ROUND_UP(MAX_WIDTH, 2) + 1, DIV_ROUND_UP(MAX_WIDTH, 2) + 7 },
209         }
210 },
211 { .buffer_created = 0, .name = "YVU420 Modifier set just for plane 0, without DRM_MODE_FB_MODIFIERS",
212         .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_YVU420,
213                  .handles = { 1, 1, 1 }, .modifier = { AFBC_FORMAT_MOD_SPARSE, 0, 0 },
214                  .pitches = { MAX_WIDTH, DIV_ROUND_UP(MAX_WIDTH, 2), DIV_ROUND_UP(MAX_WIDTH, 2) },
215         }
216 },
217 { .buffer_created = 0, .name = "YVU420 Modifier set just for planes 0, 1, without DRM_MODE_FB_MODIFIERS",
218         .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_YVU420,
219                  .handles = { 1, 1, 1 }, .modifier = { AFBC_FORMAT_MOD_SPARSE, AFBC_FORMAT_MOD_SPARSE, 0 },
220                  .pitches = { MAX_WIDTH, DIV_ROUND_UP(MAX_WIDTH, 2), DIV_ROUND_UP(MAX_WIDTH, 2) },
221         }
222 },
223 { .buffer_created = 0, .name = "YVU420 Modifier set just for plane 0, 1, with DRM_MODE_FB_MODIFIERS",
224         .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_YVU420,
225                  .handles = { 1, 1, 1 }, .flags = DRM_MODE_FB_MODIFIERS,
226                  .modifier = { AFBC_FORMAT_MOD_SPARSE, AFBC_FORMAT_MOD_SPARSE, 0 },
227                  .pitches = { MAX_WIDTH, DIV_ROUND_UP(MAX_WIDTH, 2), DIV_ROUND_UP(MAX_WIDTH, 2) },
228         }
229 },
230 { .buffer_created = 1, .name = "YVU420 Valid modifier",
231         .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_YVU420,
232                  .handles = { 1, 1, 1 }, .flags = DRM_MODE_FB_MODIFIERS,
233                  .modifier = { AFBC_FORMAT_MOD_SPARSE, AFBC_FORMAT_MOD_SPARSE, AFBC_FORMAT_MOD_SPARSE },
234                  .pitches = { MAX_WIDTH, DIV_ROUND_UP(MAX_WIDTH, 2), DIV_ROUND_UP(MAX_WIDTH, 2) },
235         }
236 },
237 { .buffer_created = 0, .name = "YVU420 Different modifiers per plane",
238         .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_YVU420,
239                  .handles = { 1, 1, 1 }, .flags = DRM_MODE_FB_MODIFIERS,
240                  .modifier = { AFBC_FORMAT_MOD_SPARSE, AFBC_FORMAT_MOD_SPARSE | AFBC_FORMAT_MOD_YTR,
241                                AFBC_FORMAT_MOD_SPARSE },
242                  .pitches = { MAX_WIDTH, DIV_ROUND_UP(MAX_WIDTH, 2), DIV_ROUND_UP(MAX_WIDTH, 2) },
243         }
244 },
245 { .buffer_created = 0, .name = "YVU420 Modifier for inexistent plane",
246         .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_YVU420,
247                  .handles = { 1, 1, 1 }, .flags = DRM_MODE_FB_MODIFIERS,
248                  .modifier = { AFBC_FORMAT_MOD_SPARSE, AFBC_FORMAT_MOD_SPARSE, AFBC_FORMAT_MOD_SPARSE,
249                                AFBC_FORMAT_MOD_SPARSE },
250                  .pitches = { MAX_WIDTH, DIV_ROUND_UP(MAX_WIDTH, 2), DIV_ROUND_UP(MAX_WIDTH, 2) },
251         }
252 },
253 { .buffer_created = 1, .name = "X0L2 Normal sizes",
254         .cmd = { .width = 600, .height = 600, .pixel_format = DRM_FORMAT_X0L2,
255                  .handles = { 1, 0, 0 }, .pitches = { 1200, 0, 0 }
256         }
257 },
258 { .buffer_created = 1, .name = "X0L2 Max sizes",
259         .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_X0L2,
260                  .handles = { 1, 0, 0 }, .pitches = { 2 * MAX_WIDTH, 0, 0 }
261         }
262 },
263 { .buffer_created = 0, .name = "X0L2 Invalid pitch",
264         .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_X0L2,
265                  .handles = { 1, 0, 0 }, .pitches = { 2 * MAX_WIDTH - 1, 0, 0 }
266         }
267 },
268 { .buffer_created = 1, .name = "X0L2 Pitch greater than minimum required",
269         .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_X0L2,
270                  .handles = { 1, 0, 0 }, .pitches = { 2 * MAX_WIDTH + 1, 0, 0 }
271         }
272 },
273 { .buffer_created = 0, .name = "X0L2 Handle for inexistent plane",
274         .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_X0L2,
275                  .handles = { 1, 1, 0 }, .flags = DRM_MODE_FB_MODIFIERS,
276                  .pitches = { 2 * MAX_WIDTH + 1, 0, 0 }
277         }
278 },
279 { .buffer_created = 1, .name = "X0L2 Offset for inexistent plane, without DRM_MODE_FB_MODIFIERS set",
280         .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_X0L2,
281                  .handles = { 1, 0, 0 }, .offsets = { 0, 0, 3 },
282                  .pitches = { 2 * MAX_WIDTH + 1, 0, 0 }
283         }
284 },
285 { .buffer_created = 0, .name = "X0L2 Modifier without DRM_MODE_FB_MODIFIERS set",
286         .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_X0L2,
287                  .handles = { 1, 0, 0 }, .pitches = { 2 * MAX_WIDTH + 1, 0, 0 },
288                  .modifier = { AFBC_FORMAT_MOD_SPARSE, 0, 0 },
289         }
290 },
291 { .buffer_created = 1, .name = "X0L2 Valid modifier",
292         .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_X0L2,
293                  .handles = { 1, 0, 0 }, .pitches = { 2 * MAX_WIDTH + 1, 0, 0 },
294                  .modifier = { AFBC_FORMAT_MOD_SPARSE, 0, 0 }, .flags = DRM_MODE_FB_MODIFIERS,
295         }
296 },
297 { .buffer_created = 0, .name = "X0L2 Modifier for inexistent plane",
298         .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT,
299                  .pixel_format = DRM_FORMAT_X0L2, .handles = { 1, 0, 0 },
300                  .pitches = { 2 * MAX_WIDTH + 1, 0, 0 },
301                  .modifier = { AFBC_FORMAT_MOD_SPARSE, AFBC_FORMAT_MOD_SPARSE, 0 },
302                  .flags = DRM_MODE_FB_MODIFIERS,
303         }
304 },
305 };
306
307 static struct drm_framebuffer *fb_create_mock(struct drm_device *dev,
308                                               struct drm_file *file_priv,
309                                               const struct drm_mode_fb_cmd2 *mode_cmd)
310 {
311         int *buffer_created = dev->dev_private;
312         *buffer_created = 1;
313         return ERR_PTR(-EINVAL);
314 }
315
316 static struct drm_mode_config_funcs mock_config_funcs = {
317         .fb_create = fb_create_mock,
318 };
319
320 static struct drm_device mock_drm_device = {
321         .mode_config = {
322                 .min_width = MIN_WIDTH,
323                 .max_width = MAX_WIDTH,
324                 .min_height = MIN_HEIGHT,
325                 .max_height = MAX_HEIGHT,
326                 .allow_fb_modifiers = true,
327                 .funcs = &mock_config_funcs,
328         },
329 };
330
331 static int execute_drm_mode_fb_cmd2(struct drm_mode_fb_cmd2 *r)
332 {
333         int buffer_created = 0;
334
335         mock_drm_device.dev_private = &buffer_created;
336         drm_internal_framebuffer_create(&mock_drm_device, r, NULL);
337         return buffer_created;
338 }
339
340 int igt_check_drm_framebuffer_create(void *ignored)
341 {
342         int i = 0;
343
344         for (i = 0; i < ARRAY_SIZE(createbuffer_tests); i++) {
345                 FAIL(createbuffer_tests[i].buffer_created !=
346                                 execute_drm_mode_fb_cmd2(&createbuffer_tests[i].cmd),
347                      "Test %d: \"%s\" failed\n", i, createbuffer_tests[i].name);
348         }
349
350         return 0;
351 }