]> granicus.if.org Git - strace/blob - v4l2.c
Implement Video4Linux video-input ioctls decoder
[strace] / v4l2.c
1 /*
2  * Copyright (c) 2014 Philippe De Muyter <phdm@macqel.be>
3  * Copyright (c) 2014 William Manley <will@williammanley.net>
4  * Copyright (c) 2011 Peter Zotov <whitequark@whitequark.org>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. The name of the author may not be used to endorse or promote products
16  *    derived from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include "defs.h"
31
32 #include <stdint.h>
33 #include <sys/ioctl.h>
34 #include <linux/videodev2.h>
35 /* some historical constants */
36 #ifndef V4L2_CID_HCENTER
37 #define V4L2_CID_HCENTER (V4L2_CID_BASE+22)
38 #endif
39 #ifndef V4L2_CID_VCENTER
40 #define V4L2_CID_VCENTER (V4L2_CID_BASE+23)
41 #endif
42 #ifndef V4L2_CID_BAND_STOP_FILTER
43 #define V4L2_CID_BAND_STOP_FILTER (V4L2_CID_BASE+33)
44 #endif
45
46 #include "xlat/v4l2_device_capabilities_flags.h"
47 #include "xlat/v4l2_buf_types.h"
48 #include "xlat/v4l2_buf_flags.h"
49 #include "xlat/v4l2_framesize_types.h"
50 #include "xlat/v4l2_frameinterval_types.h"
51 #include "xlat/v4l2_fields.h"
52 #include "xlat/v4l2_colorspaces.h"
53 #include "xlat/v4l2_format_description_flags.h"
54 #include "xlat/v4l2_memories.h"
55 #include "xlat/v4l2_control_ids.h"
56 #include "xlat/v4l2_control_types.h"
57 #include "xlat/v4l2_control_flags.h"
58 #include "xlat/v4l2_control_classes.h"
59 #include "xlat/v4l2_streaming_capabilities.h"
60 #include "xlat/v4l2_capture_modes.h"
61 #include "xlat/v4l2_input_types.h"
62
63 #define FMT_FRACT "%u/%u"
64 #define ARGS_FRACT(x) ((x).numerator), ((x).denominator)
65
66 #define FMT_RECT "{left=%i, top=%i, width=%i, height=%i}"
67 #define ARGS_RECT(x) (x).left, (x).top, (x).width, (x).height
68
69 static void print_pixelformat(uint32_t fourcc)
70 {
71 #if WORDS_BIGENDIAN
72         fourcc = htole32(fourcc);
73 #endif
74         tprintf("%.4s", (char*)&fourcc);
75 }
76
77 static void print_v4l2_format_fmt(const struct v4l2_format *f)
78 {
79         tprints("fmt.");
80         switch (f->type) {
81         case V4L2_BUF_TYPE_VIDEO_CAPTURE:
82         case V4L2_BUF_TYPE_VIDEO_OUTPUT: {
83                 const struct v4l2_pix_format *pix = &f->fmt.pix;
84
85                 tprintf("pix={width=%u, height=%u, pixelformat=",
86                         pix->width, pix->height);
87                 print_pixelformat(pix->pixelformat);
88                 tprints(", field=");
89                 printxval(v4l2_fields, pix->field, "V4L2_FIELD_???");
90                 tprintf(", bytesperline=%u, sizeimage=%u, colorspace=",
91                         pix->bytesperline, pix->sizeimage);
92                 printxval(v4l2_colorspaces, pix->colorspace,
93                           "V4L2_COLORSPACE_???");
94                 tprints("}");
95                 break;
96         }
97 #if HAVE_DECL_V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
98         case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
99         case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: {
100                 const struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
101                 unsigned int i, max;
102
103                 tprintf("pix_mp={width=%u, height=%u, pixelformat=",
104                         pix_mp->width, pix_mp->height);
105                 print_pixelformat(pix_mp->pixelformat);
106                 tprints(", field=");
107                 printxval(v4l2_fields, pix_mp->field, "V4L2_FIELD_???");
108                 tprints(", colorspace=");
109                 printxval(v4l2_colorspaces, pix_mp->colorspace,
110                           "V4L2_COLORSPACE_???");
111                 tprints("plane_fmt=[");
112                 max = pix_mp->num_planes;
113                 if (max > VIDEO_MAX_PLANES)
114                         max = VIDEO_MAX_PLANES;
115                 for (i = 0; i < max; i++) {
116                         if (i > 0)
117                                 tprints(", ");
118                         tprintf("{sizeimage=%u, bytesperline=%u}",
119                                 pix_mp->plane_fmt[i].sizeimage,
120                                 pix_mp->plane_fmt[i].bytesperline);
121                 }
122                 tprintf("], num_planes=%u}", (unsigned) pix_mp->num_planes);
123                 break;
124         }
125 #endif
126
127         /* TODO: Complete this switch statement */
128         case V4L2_BUF_TYPE_VIDEO_OVERLAY:
129         case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
130                 tprints("win={???}");
131                 break;
132
133         case V4L2_BUF_TYPE_VBI_CAPTURE:
134         case V4L2_BUF_TYPE_VBI_OUTPUT:
135                 tprints("vbi={???}");
136                 break;
137
138         case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
139         case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
140                 tprints("sliced={???}");
141                 break;
142
143         default:
144                 tprints("???");
145                 break;
146         }
147 }
148
149 int
150 v4l2_ioctl(struct tcb *tcp, unsigned long code, long arg)
151 {
152         if (!verbose(tcp))
153                 return 0;
154
155         switch (code) {
156         case VIDIOC_QUERYCAP: /* decode on exit */ {
157                 struct v4l2_capability caps;
158
159                 if (entering(tcp) || syserror(tcp) || umove(tcp, arg, &caps) < 0)
160                         return 0;
161                 tprintf(", {driver=\"%s\", card=\"%s\", bus_info=\"%s\", "
162                         "version=%u.%u.%u, capabilities=", caps.driver, caps.card,
163                         caps.bus_info, (caps.version >> 16) & 0xFF,
164                         (caps.version >> 8) & 0xFF, caps.version & 0xFF);
165                 printflags(v4l2_device_capabilities_flags, caps.capabilities,
166                            "V4L2_CAP_???");
167 #ifdef V4L2_CAP_DEVICE_CAPS
168                 tprints(", device_caps=");
169                 printflags(v4l2_device_capabilities_flags, caps.device_caps,
170                            "V4L2_CAP_???");
171 #endif
172                 tprints("}");
173                 return 1;
174         }
175
176         case VIDIOC_ENUM_FRAMESIZES: /* decode on exit */ {
177                 struct v4l2_frmsizeenum s;
178
179                 if (entering(tcp) || umove(tcp, arg, &s) < 0)
180                         return 0;
181                 tprintf(", {index=%u, pixel_format=", s.index);
182                 print_pixelformat(s.pixel_format);
183
184                 if (!syserror(tcp)) {
185                         tprints(", type=");
186                         printxval(v4l2_framesize_types, s.type, "V4L2_FRMSIZE_TYPE_???");
187                         switch (s.type) {
188                         case V4L2_FRMSIZE_TYPE_DISCRETE:
189                                 tprintf(", discrete={width=%u, height=%u}",
190                                         s.discrete.width, s.discrete.height);
191                                 break;
192                         case V4L2_FRMSIZE_TYPE_STEPWISE:
193                                 tprintf(", stepwise={min_width=%u, max_width=%u, "
194                                         "step_width=%u, min_height=%u, max_height=%u, "
195                                         "step_height=%u}",
196                                         s.stepwise.min_width, s.stepwise.max_width,
197                                         s.stepwise.step_width, s.stepwise.min_height,
198                                         s.stepwise.max_height, s.stepwise.step_height);
199                                 break;
200                         }
201                 }
202                 tprints("}");
203                 return 1;
204         }
205
206         case VIDIOC_G_FMT:
207         case VIDIOC_S_FMT:
208         case VIDIOC_TRY_FMT: {
209                 struct v4l2_format f;
210
211                 if (umove(tcp, arg, &f) < 0)
212                         return 0;
213                 if (entering(tcp)) {
214                         tprints(", {type=");
215                         printxval(v4l2_buf_types, f.type, "V4L2_BUF_TYPE_???");
216                 }
217                 if ((entering(tcp) && code != VIDIOC_G_FMT)
218                     || (exiting(tcp) && !syserror(tcp))) {
219                         tprints(exiting(tcp) && code != VIDIOC_G_FMT ? " => " : ", ");
220                         print_v4l2_format_fmt(&f);
221                 }
222                 if (exiting(tcp))
223                         tprints("}");
224                 return 1;
225         }
226
227         case VIDIOC_ENUM_FMT: {
228                 struct v4l2_fmtdesc f;
229
230                 if (entering(tcp) || umove(tcp, arg, &f) < 0)
231                         return 0;
232
233                 tprintf(", {index=%u", f.index);
234                 if (!syserror(tcp)) {
235                         tprints(", type=");
236                         printxval(v4l2_buf_types, f.type, "V4L2_BUF_TYPE_???");
237                         tprints(", flags=");
238                         printflags(v4l2_format_description_flags, f.flags,
239                                    "V4L2_FMT_FLAG_???");
240                         tprintf(", description=\"%s\", pixelformat=",
241                                 f.description);
242                         print_pixelformat(f.pixelformat);
243                 }
244                 tprints("}");
245                 return 1;
246         }
247
248         case VIDIOC_G_PARM:
249         case VIDIOC_S_PARM: {
250                 struct v4l2_streamparm s;
251
252                 if (entering(tcp) && code == VIDIOC_G_PARM)
253                         return 1;
254                 if (exiting(tcp) && syserror(tcp))
255                         return code == VIDIOC_S_PARM;
256                 if (umove(tcp, arg, &s) < 0)
257                         return 0;
258                 if (entering(tcp)) {
259                         tprints(", {type=");
260                         printxval(v4l2_buf_types, s.type, "V4L2_BUF_TYPE_???");
261                 }
262
263                 tprints(exiting(tcp) && code == VIDIOC_S_PARM ? " => {" : ", {");
264                 if (s.type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
265                         struct v4l2_captureparm *cap = &s.parm.capture;
266
267                         tprints("capability=");
268                         printflags(v4l2_streaming_capabilities,
269                                    cap->capability, "V4L2_CAP_???");
270
271                         tprints(", capturemode=");
272                         printflags(v4l2_capture_modes,
273                                    cap->capturemode, "V4L2_MODE_???");
274
275                         tprintf(", timeperframe=" FMT_FRACT,
276                                 ARGS_FRACT(cap->timeperframe));
277
278                         tprintf(", extendedmode=%u, readbuffers=%u",
279                                 cap->extendedmode,
280                                 cap->readbuffers);
281                 } else
282                         tprints("...");
283                 tprints("}");
284                 if (exiting(tcp))
285                         tprints("}");
286                 return 1;
287         }
288
289         case VIDIOC_QUERYCTRL: {
290                 struct v4l2_queryctrl c;
291
292                 if (umove(tcp, arg, &c) < 0)
293                         return 0;
294                 /* 'id' field must be printed :
295                 * on enter
296                 * on exit if !syserror(tcp) && V4L2_CTRL_FLAG_NEXT_CTRL was set
297                 */
298                 if (entering(tcp)
299                     || (exiting(tcp) && tcp->auxstr && !syserror(tcp))) {
300                         tprints(exiting(tcp) ? " => " : ", {id=");
301                         tcp->auxstr = (c.id & V4L2_CTRL_FLAG_NEXT_CTRL) ? "" : NULL;
302                         if (tcp->auxstr) {
303                                 tprints("V4L2_CTRL_FLAG_NEXT_CTRL|");
304                                 c.id &= ~V4L2_CTRL_FLAG_NEXT_CTRL;
305                         }
306                         printxval(v4l2_control_ids, c.id, "V4L2_CID_???");
307                 }
308                 if (exiting(tcp)) {
309                         if (!syserror(tcp)) {
310                                 tprints(", type=");
311                                 printxval(v4l2_control_types, c.type,
312                                           "V4L2_CTRL_TYPE_???");
313                                 tprintf(", name=\"%s\", minimum=%i, maximum=%i, step=%i, "
314                                         "default_value=%i, flags=",
315                                         c.name, c.minimum, c.maximum,
316                                         c.step, c.default_value);
317                                 printflags(v4l2_control_flags, c.flags,
318                                            "V4L2_CTRL_FLAG_???");
319                         }
320                         tprints("}");
321                 }
322                 return 1;
323         }
324
325         case VIDIOC_G_CTRL:
326         case VIDIOC_S_CTRL: {
327                 struct v4l2_control c;
328
329                 if (entering(tcp) || umove(tcp, arg, &c) < 0)
330                         return 0;
331                 tprints(", {id=");
332                 printxval(v4l2_control_ids, c.id, "V4L2_CID_???");
333                 if (!syserror(tcp) || code != VIDIOC_G_CTRL)
334                         tprintf(", value=%i", c.value);
335                 tprints("}");
336                 return 1;
337         }
338
339         case VIDIOC_S_EXT_CTRLS:
340         case VIDIOC_TRY_EXT_CTRLS:
341         case VIDIOC_G_EXT_CTRLS: {
342                 struct v4l2_ext_controls c;
343                 unsigned int n;
344                 bool must_print_values;
345
346                 if (entering(tcp) && code == VIDIOC_G_EXT_CTRLS)
347                         return 0;
348                 if (exiting(tcp) && syserror(tcp) && code != VIDIOC_G_EXT_CTRLS)
349                         return 0;
350                 must_print_values = ((entering(tcp) && code != VIDIOC_G_EXT_CTRLS)
351                                      || (exiting(tcp) && !syserror(tcp)));
352                 if (umove(tcp, arg, &c) < 0)
353                         return 0;
354                 tprints(code != VIDIOC_G_EXT_CTRLS && exiting(tcp) ? " => " : ", ");
355                 tprints("{ctrl_class=");
356                 printxval(v4l2_control_classes, c.ctrl_class,
357                           "V4L2_CTRL_CLASS_???");
358                 tprintf(", count=%u", c.count);
359                 if (exiting(tcp) && syserror(tcp))
360                         tprintf(", error_idx=%u", c.error_idx);
361                 tprints(", controls=[");
362                 for (n = 0; n < c.count; ++n) {
363                         struct v4l2_ext_control ctrl;
364
365                         if (n > 0)
366                                 tprints(", ");
367                         if (umove(tcp, (long) (c.controls + n), &ctrl) < 0)
368                                 break;
369                         if (abbrev(tcp) && n == 2) {
370                                 tprints("...");
371                                 break;
372                         }
373                         tprints("{id=");
374                         printxval(v4l2_control_ids, ctrl.id, "V4L2_CID_???");
375 #if HAVE_DECL_V4L2_CTRL_TYPE_STRING
376                         tprintf(", size=%u", ctrl.size);
377                         if (ctrl.size > 0) {
378                                 if (must_print_values) {
379                                         tprints(", string=");
380                                         printstr(tcp, (long) ctrl.string, ctrl.size);
381                                 }
382                         } else
383 #endif
384                         {
385                                 if (must_print_values) {
386                                         tprintf(", value=%i, value64=%lli", ctrl.value,
387                                                 ctrl.value64);
388                                 }
389                         }
390                         tprints("}");
391                 }
392                 tprints("]}");
393                 return 1;
394         }
395
396         case VIDIOC_ENUMSTD: {
397                 struct v4l2_standard s;
398
399                 if (umove(tcp, arg, &s) < 0)
400                         return 0;
401                 if (entering(tcp))
402                         tprintf(", {index=%i", s.index);
403                 else {
404                         if (!syserror(tcp)) {
405                                 tprintf(", name=\"%s\"", s.name);
406                                 tprintf(", frameperiod=" FMT_FRACT, ARGS_FRACT(s.frameperiod));
407                                 tprintf(", framelines=%i", s.framelines);
408                         }
409                         tprints("}");
410                 }
411                 return 1;
412         }
413
414         case VIDIOC_G_STD:
415         case VIDIOC_S_STD: {
416                 v4l2_std_id s;
417
418                 if (code == VIDIOC_G_STD && exiting(tcp) && syserror(tcp))
419                         return 0;
420                 if (umove(tcp, arg, &s) < 0)
421                         return 0;
422                 if ((code == VIDIOC_S_STD) == entering(tcp))
423                         tprintf(", std=%#llx", s);
424                 return 1;
425         }
426
427         case VIDIOC_ENUMINPUT: {
428                 struct v4l2_input i;
429
430                 if (entering(tcp) || umove(tcp, arg, &i) < 0)
431                         return 0;
432                 tprintf(", {index=%i", i.index);
433                 if (!syserror(tcp)) {
434                         tprintf(", name=\"%s\", type=", i.name);
435                         printxval(v4l2_input_types, i.type,
436                                   "V4L2_INPUT_TYPE_???");
437                 }
438                 tprints("}");
439                 return 1;
440         }
441
442         case VIDIOC_G_INPUT:
443         case VIDIOC_S_INPUT: {
444                 int index;
445
446                 if (entering(tcp) || syserror(tcp) || umove(tcp, arg, &index) < 0)
447                         return 0;
448
449                 tprintf(", index=%i", index);
450                 return 1;
451         }
452
453         case VIDIOC_ENUM_FRAMEINTERVALS: {
454                 struct v4l2_frmivalenum f;
455
456                 if (entering(tcp) || umove(tcp, arg, &f) < 0)
457                         return 0;
458                 tprintf(", {index=%i, pixel_format=", f.index);
459                 print_pixelformat(f.pixel_format);
460                 tprintf(", width=%u, height=%u", f.width, f.height);
461                 if (!syserror(tcp)) {
462                         tprints(", type=");
463                         printxval(v4l2_frameinterval_types, f.type,
464                                   "V4L2_FRMIVAL_TYPE_???");
465                         switch (f.type) {
466                         case V4L2_FRMIVAL_TYPE_DISCRETE:
467                                 tprintf(", discrete=" FMT_FRACT,
468                                         ARGS_FRACT(f.discrete));
469                                 break;
470                         case V4L2_FRMIVAL_TYPE_STEPWISE:
471                         case V4L2_FRMSIZE_TYPE_CONTINUOUS:
472                                 tprintf(", stepwise={min=" FMT_FRACT ", max="
473                                         FMT_FRACT ", step=" FMT_FRACT "}",
474                                         ARGS_FRACT(f.stepwise.min),
475                                         ARGS_FRACT(f.stepwise.max),
476                                         ARGS_FRACT(f.stepwise.step));
477                                 break;
478                         }
479                 }
480                 tprints("}");
481                 return 1;
482         }
483
484         case VIDIOC_CROPCAP: {
485                 struct v4l2_cropcap c;
486
487                 if (entering(tcp) || umove(tcp, arg, &c) < 0)
488                         return 0;
489                 tprints(", type=");
490                 printxval(v4l2_buf_types, c.type, "V4L2_BUF_TYPE_???");
491                 if (syserror(tcp))
492                         return 1;
493                 tprintf(", bounds=" FMT_RECT ", defrect=" FMT_RECT ", "
494                         "pixelaspect=" FMT_FRACT, ARGS_RECT(c.bounds),
495                         ARGS_RECT(c.defrect), ARGS_FRACT(c.pixelaspect));
496                 return 1;
497         }
498
499         case VIDIOC_G_FBUF:
500         case VIDIOC_S_FBUF: {
501                 struct v4l2_framebuffer b;
502
503                 if (syserror(tcp) && code == VIDIOC_G_FBUF)
504                         return 0;
505                 if (entering(tcp) || umove(tcp, arg, &b) < 0)
506                         return 0;
507                 tprintf(", {capability=%x, flags=%x, base=%p}",
508                         b.capability, b.flags, b.base);
509                 return 1;
510         }
511
512         case VIDIOC_REQBUFS: {
513                 struct v4l2_requestbuffers reqbufs;
514
515                 if (umove(tcp, arg, &reqbufs) < 0)
516                         return 0;
517                 if (entering(tcp)) {
518                         tprintf(", {count=%u, type=", reqbufs.count);
519                         printxval(v4l2_buf_types, reqbufs.type, "V4L2_BUF_TYPE_???");
520                         tprints(", memory=");
521                         printxval(v4l2_memories, reqbufs.memory, "V4L2_MEMORY_???");
522                         tprints("}");
523                         return 1;
524                 } else if (syserror(tcp))
525                         return 1;
526                 else {
527                         static char outstr[sizeof("{count=}") + sizeof(int) * 3];
528
529                         sprintf(outstr, "{count=%u}", reqbufs.count);
530                         tcp->auxstr = outstr;
531                         return 1 + RVAL_STR;
532                 }
533         }
534
535         case VIDIOC_QUERYBUF:
536         case VIDIOC_QBUF:
537         case VIDIOC_DQBUF: {
538                 struct v4l2_buffer b;
539
540                 if (umove(tcp, arg, &b) < 0)
541                         return 0;
542                 if (entering(tcp)) {
543                         tprints(", {type=");
544                         printxval(v4l2_buf_types, b.type, "V4L2_BUF_TYPE_???");
545                         if (code != VIDIOC_DQBUF)
546                                 tprintf(", index=%u", b.index);
547                 } else {
548                         if (!syserror(tcp)) {
549                                 if (code == VIDIOC_DQBUF)
550                                         tprintf(", index=%u", b.index);
551                                 tprints(", memory=");
552                                 printxval(v4l2_memories, b.memory, "V4L2_MEMORY_???");
553
554                                 if (b.memory == V4L2_MEMORY_MMAP) {
555                                         tprintf(", m.offset=%#x", b.m.offset);
556                                 } else if (b.memory == V4L2_MEMORY_USERPTR) {
557                                         tprintf(", m.userptr=%#lx", b.m.userptr);
558                                 }
559
560                                 tprintf(", length=%u, bytesused=%u, flags=",
561                                         b.length, b.bytesused);
562                                 printflags(v4l2_buf_flags, b.flags, "V4L2_BUF_FLAG_???");
563                                 if (code == VIDIOC_DQBUF)
564                                         tprintf(", timestamp = {%lu.%06lu}",
565                                                 b.timestamp.tv_sec,
566                                                 b.timestamp.tv_usec);
567                                 tprints(", ...");
568                         }
569                         tprints("}");
570                 }
571                 return 1;
572         }
573
574         case VIDIOC_STREAMON:
575         case VIDIOC_STREAMOFF: {
576                 int type;
577
578                 if (umove(tcp, arg, &type) < 0)
579                         return 0;
580                 if (entering(tcp)) {
581                         tprints(", ");
582                         printxval(v4l2_buf_types, type, "V4L2_BUF_TYPE_???");
583                 }
584                 return 1;
585         }
586
587         default: /* decode on exit */
588                 return 0;
589         }
590 }