sdl

FORK: Simple Directmedia Layer
git clone https://git.neptards.moe/neptards/sdl.git
Log | Files | Refs

testevdev.c (32056B)


      1 /*
      2   Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
      3   Copyright (C) 2020 Collabora Ltd.
      4 
      5   This software is provided 'as-is', without any express or implied
      6   warranty.  In no event will the authors be held liable for any damages
      7   arising from the use of this software.
      8 
      9   Permission is granted to anyone to use this software for any purpose,
     10   including commercial applications, and to alter it and redistribute it
     11   freely.
     12 */
     13 
     14 #include "../src/SDL_internal.h"
     15 
     16 #include <stdio.h>
     17 #include <string.h>
     18 
     19 static int run_test(void);
     20 
     21 #if HAVE_LIBUDEV_H || defined(SDL_JOYSTICK_LINUX)
     22 
     23 #include <stdint.h>
     24 
     25 #include "SDL_stdinc.h"
     26 #include "SDL_endian.h"
     27 #include "../src/core/linux/SDL_evdev_capabilities.h"
     28 #include "../src/core/linux/SDL_evdev_capabilities.c"
     29 
     30 static const struct
     31 {
     32     int code;
     33     const char *name;
     34 } device_classes[] =
     35 {
     36 #define CLS(x) \
     37     { SDL_UDEV_DEVICE_ ## x, #x }
     38     CLS(MOUSE),
     39     CLS(KEYBOARD),
     40     CLS(JOYSTICK),
     41     CLS(SOUND),
     42     CLS(TOUCHSCREEN),
     43     CLS(ACCELEROMETER),
     44 #undef CLS
     45     { 0, NULL }
     46 };
     47 
     48 typedef struct
     49 {
     50   const char *name;
     51   uint16_t bus_type;
     52   uint16_t vendor_id;
     53   uint16_t product_id;
     54   uint16_t version;
     55   uint8_t ev[(EV_MAX + 1) / 8];
     56   uint8_t keys[(KEY_MAX + 1) / 8];
     57   uint8_t abs[(ABS_MAX + 1) / 8];
     58   uint8_t rel[(REL_MAX + 1) / 8];
     59   uint8_t ff[(FF_MAX + 1) / 8];
     60   uint8_t props[INPUT_PROP_MAX / 8];
     61   int expected;
     62 } GuessTest;
     63 
     64 /*
     65  * Test-cases for guessing a device type from its capabilities.
     66  *
     67  * The bytes in ev, etc. are in little-endian byte order
     68  * Trailing zeroes can be omitted.
     69  *
     70  * The evemu-describe tool is a convenient way to add a test-case for
     71  * a physically available device.
     72  */
     73 #define ZEROx4 0, 0, 0, 0
     74 #define ZEROx8 ZEROx4, ZEROx4
     75 #define FFx4 0xff, 0xff, 0xff, 0xff
     76 #define FFx8 FFx4, FFx4
     77 
     78 /* Test-cases derived from real devices or from Linux kernel source */
     79 static const GuessTest guess_tests[] =
     80 {
     81     {
     82       .name = "Xbox 360 wired USB controller",
     83       .bus_type = 0x0003,
     84       .vendor_id = 0x045e,
     85       .product_id = 0x028e,
     86       .expected = SDL_UDEV_DEVICE_JOYSTICK,
     87       /* SYN, KEY, ABS, FF */
     88       .ev = { 0x0b, 0x00, 0x20 },
     89       /* X, Y, Z, RX, RY, RZ, HAT0X, HAT0Y */
     90       .abs = { 0x3f, 0x00, 0x03 },
     91       .keys = {
     92           /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
     93           /* A, B, X, Y, TL, TR, SELECT, START, MODE, THUMBL, THUMBR */
     94           /* 0x100 */ ZEROx4, 0x00, 0x00, 0xdb, 0x7c,
     95       },
     96     },
     97     {
     98       .name = "X-Box One Elite",
     99       .bus_type = 0x0003,
    100       .vendor_id = 0x045e,
    101       .product_id = 0x02e3,
    102       .expected = SDL_UDEV_DEVICE_JOYSTICK,
    103       /* SYN, KEY, ABS */
    104       .ev = { 0x0b },
    105       /* X, Y, Z, RX, RY, RZ, HAT0X, HAT0Y */
    106       .abs = { 0x3f, 0x00, 0x03 },
    107       .keys = {
    108           /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
    109           /* A, B, X, Y, TL, TR, SELECT, START, MODE, THUMBL, THUMBR */
    110           /* 0x100 */ ZEROx4, 0x00, 0x00, 0xdb, 0x7c,
    111       },
    112     },
    113     {
    114       .name = "X-Box One S via Bluetooth",
    115       .bus_type = 0x0005,
    116       .vendor_id = 0x045e,
    117       .product_id = 0x02e0,
    118       .version = 0x1130,
    119       .expected = SDL_UDEV_DEVICE_JOYSTICK,
    120       /* SYN, KEY, ABS */
    121       .ev = { 0x0b },
    122       /* X, Y, Z, RX, RY, RZ, HAT0X, HAT0Y */
    123       .abs = { 0x3f, 0x00, 0x03 },
    124       .keys = {
    125           /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
    126           /* A, B, X, Y, TL, TR, SELECT, START, MODE, THUMBL, THUMBR */
    127           /* 0x100 */ ZEROx4, 0x00, 0x00, 0xdb, 0x7c,
    128       },
    129     },
    130     {
    131       .name = "X-Box One S wired",
    132       .bus_type = 0x0003,
    133       .vendor_id = 0x045e,
    134       .product_id = 0x02ea,
    135       .version = 0x0301,
    136       .expected = SDL_UDEV_DEVICE_JOYSTICK,
    137       /* SYN, KEY, ABS */
    138       .ev = { 0x0b },
    139       /* X, Y, Z, RX, RY, RZ, HAT0X, HAT0Y */
    140       .abs = { 0x3f, 0x00, 0x03 },
    141       .keys = {
    142           /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
    143           /* A, B, X, Y, TL, TR, SELECT, START, MODE, THUMBL, THUMBR */
    144           /* 0x100 */ ZEROx4, 0x00, 0x00, 0xdb, 0x7c,
    145       },
    146     },
    147     {
    148       .name = "DualShock 4 - gamepad",
    149       .bus_type = 0x0003,
    150       .vendor_id = 0x054c,
    151       .product_id = 0x09cc,
    152       .expected = SDL_UDEV_DEVICE_JOYSTICK,
    153       /* SYN, KEY, ABS, MSC, FF */
    154       /* Some versions only have 0x0b, SYN, KEY, ABS, like the
    155        * Bluetooth example below */
    156       .ev = { 0x1b, 0x00, 0x20 },
    157       /* X, Y, Z, RX, RY, RZ, HAT0X, HAT0Y */
    158       .abs = { 0x3f, 0x00, 0x03 },
    159       .keys = {
    160           /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
    161           /* A, B, X, Y, TL, TR, TL2, TR2, SELECT, START, MODE,
    162            * THUMBL, THUMBR */
    163           /* 0x100 */ ZEROx4, 0x00, 0x00, 0xdb, 0x7f,
    164       },
    165     },
    166     {
    167       .name = "DualShock 4 - gamepad via Bluetooth",
    168       .bus_type = 0x0005,
    169       .vendor_id = 0x054c,
    170       .product_id = 0x09cc,
    171       .expected = SDL_UDEV_DEVICE_JOYSTICK,
    172       /* SYN, KEY, ABS */
    173       .ev = { 0x0b },
    174       /* X, Y, Z, RX, RY, RZ, HAT0X, HAT0Y */
    175       .abs = { 0x3f, 0x00, 0x03 },
    176       .keys = {
    177           /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
    178           /* A, B, X, Y, TL, TR, TL2, TR2, SELECT, START, MODE,
    179            * THUMBL, THUMBR */
    180           /* 0x100 */ ZEROx4, 0x00, 0x00, 0xdb, 0x7f,
    181       },
    182     },
    183     {
    184       .name = "DualShock 4 - touchpad",
    185       .bus_type = 0x0003,
    186       .vendor_id = 0x054c,
    187       .product_id = 0x09cc,
    188       /* TODO: Should this be MOUSE? That's what it most closely
    189        * resembles */
    190       .expected = SDL_UDEV_DEVICE_UNKNOWN,
    191       /* SYN, KEY, ABS */
    192       .ev = { 0x0b },
    193       /* X, Y, multitouch */
    194       .abs = { 0x03, 0x00, 0x00, 0x00, 0x00, 0x80, 0x60, 0x02 },
    195       .keys = {
    196           /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
    197           /* Left mouse button */
    198           /* 0x100 */ 0x00, 0x00, 0x01, 0x00, ZEROx4,
    199           /* BTN_TOOL_FINGER and some multitouch stuff */
    200           /* 0x140 */ 0x20, 0x24, 0x00, 0x00
    201       },
    202       /* POINTER, BUTTONPAD */
    203       .props = { 0x05 },
    204     },
    205     {
    206       .name = "DualShock 4 - accelerometer",
    207       .bus_type = 0x0003,
    208       .vendor_id = 0x054c,
    209       .product_id = 0x09cc,
    210       .expected = SDL_UDEV_DEVICE_ACCELEROMETER,
    211       /* SYN, ABS, MSC */
    212       .ev = { 0x19 },
    213       /* X, Y, Z, RX, RY, RZ */
    214       .abs = { 0x3f },
    215       /* ACCELEROMETER */
    216       .props = { 0x40 },
    217     },
    218     {
    219       .name = "DualShock 4 via USB dongle",
    220       .bus_type = 0x0003,
    221       .vendor_id = 0x054c,
    222       .product_id = 0x0ba0,
    223       .version = 0x8111,
    224       .expected = SDL_UDEV_DEVICE_JOYSTICK,
    225       /* SYN, ABS, KEY */
    226       .ev = { 0x0b },
    227       /* X, Y, Z, RX, RY, RZ, HAT0X, HAT0Y */
    228       .abs = { 0x3f, 0x00, 0x03 },
    229       .keys = {
    230           /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
    231           /* A, B, X, Y, TL, TR, TL2, TR2, SELECT, START, MODE,
    232            * THUMBL, THUMBR */
    233           /* 0x100 */ ZEROx4, 0x00, 0x00, 0xdb, 0x7f,
    234       },
    235     },
    236     {
    237       .name = "DualShock 3 - gamepad",
    238       .bus_type = 0x0003,
    239       .vendor_id = 0x054c,
    240       .product_id = 0x0268,
    241       .expected = SDL_UDEV_DEVICE_JOYSTICK,
    242       /* SYN, KEY, ABS, MSC, FF */
    243       .ev = { 0x1b, 0x00, 0x20 },
    244       /* X, Y, Z, RX, RY, RZ */
    245       .abs = { 0x3f },
    246       .keys = {
    247           /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
    248           /* A, B, X, Y, TL, TR, TL2, TR2, SELECT, START, MODE,
    249            * THUMBL, THUMBR */
    250           /* 0x100 */ ZEROx4, 0x00, 0x00, 0xdb, 0x7f,
    251           /* 0x140 */ ZEROx8,
    252           /* 0x180 */ ZEROx8,
    253           /* 0x1c0 */ ZEROx8,
    254           /* Digital dpad */
    255           /* 0x200 */ ZEROx4, 0x0f, 0x00, 0x00, 0x00,
    256       },
    257     },
    258     {
    259       .name = "DualShock 3 - accelerometer",
    260       .bus_type = 0x0003,
    261       .vendor_id = 0x054c,
    262       .product_id = 0x0268,
    263       .expected = SDL_UDEV_DEVICE_ACCELEROMETER,
    264       /* SYN, ABS */
    265       .ev = { 0x09 },
    266       /* X, Y, Z */
    267       .abs = { 0x07 },
    268       /* ACCELEROMETER */
    269       .props = { 0x40 },
    270     },
    271     {
    272       .name = "Steam Controller - gamepad",
    273       .bus_type = 0x0003,
    274       .vendor_id = 0x28de,
    275       .product_id = 0x1142,
    276       .expected = SDL_UDEV_DEVICE_JOYSTICK,
    277       /* SYN, KEY, ABS */
    278       .ev = { 0x0b },
    279       /* X, Y, RX, RY, HAT0X, HAT0Y, HAT2X, HAT2Y */
    280       .abs = { 0x1b, 0x00, 0x33 },
    281       .keys = {
    282           /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
    283           /* A, B, X, Y, TL, TR, TL2, TR2, SELECT, START, MODE,
    284            * THUMBL, THUMBR, joystick THUMB, joystick THUMB2  */
    285           /* 0x100 */ ZEROx4, 0x06, 0x00, 0xdb, 0x7f,
    286           /* GEAR_DOWN, GEAR_UP */
    287           /* 0x140 */ 0x00, 0x00, 0x03, 0x00, ZEROx4,
    288           /* 0x180 */ ZEROx8,
    289           /* 0x1c0 */ ZEROx8,
    290           /* Digital dpad */
    291           /* 0x200 */ ZEROx4, 0x0f, 0x00, 0x00, 0x00,
    292       },
    293     },
    294     {
    295       /* Present to support lizard mode, even if no Steam Controller
    296        * is connected */
    297       .name = "Steam Controller - dongle",
    298       .bus_type = 0x0003,
    299       .vendor_id = 0x28de,
    300       .product_id = 0x1142,
    301       .expected = (SDL_UDEV_DEVICE_KEYBOARD
    302                    | SDL_UDEV_DEVICE_MOUSE),
    303       /* SYN, KEY, REL, MSC, LED, REP */
    304       .ev = { 0x17, 0x00, 0x12 },
    305       /* X, Y, mouse wheel, high-res mouse wheel */
    306       .rel = { 0x03, 0x09 },
    307       .keys = {
    308           /* 0x00 */ 0xfe, 0xff, 0xff, 0xff, FFx4,
    309           /* 0x40 */ 0xff, 0xff, 0xcf, 0x01, 0xdf, 0xff, 0x80, 0xe0,
    310           /* 0x80 */ ZEROx8,
    311           /* 0xc0 */ ZEROx8,
    312           /* 0x100 */ 0x00, 0x00, 0x1f, 0x00, ZEROx4,
    313       },
    314     },
    315     {
    316       .name = "Guitar Hero for PS3",
    317       .bus_type = 0x0003,
    318       .vendor_id = 0x12ba,
    319       .product_id = 0x0100,
    320       .version = 0x0110,
    321       .expected = SDL_UDEV_DEVICE_JOYSTICK,
    322       /* SYN, KEY, ABS */
    323       .ev = { 0x0b },
    324       /* X, Y, Z, RZ, HAT0X, HAT0Y */
    325       .abs = { 0x27, 0x00, 0x03 },
    326       .keys = {
    327           /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
    328           /* ABC, XYZ, TL, TR, TL2, TR2, SELECT, START, MODE */
    329           /* 0x100 */ ZEROx4, 0x00, 0x00, 0xff, 0x1f,
    330       },
    331     },
    332     {
    333       .name = "G27 Racing Wheel, 0003:046d:c29b v0111",
    334       .bus_type = 0x0003,
    335       .vendor_id = 0x046d,
    336       .product_id = 0xc29b,
    337       .version = 0x0111,
    338       .expected = SDL_UDEV_DEVICE_JOYSTICK,
    339       /* SYN, KEY, ABS */
    340       .ev = { 0x0b },
    341       /* X, Y, Z, RZ, HAT0X, HAT0Y */
    342       .abs = { 0x27, 0x00, 0x03 },
    343       .keys = {
    344           /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
    345           /* 16 buttons: TRIGGER, THUMB, THUMB2, TOP, TOP2, PINKIE, BASE,
    346            * BASE2..BASE6, unregistered event codes 0x12c-0x12e, DEAD */
    347           /* 0x100 */ ZEROx4, 0xff, 0xff, 0x00, 0x00,
    348           /* 0x140 */ ZEROx8,
    349           /* 0x180 */ ZEROx8,
    350           /* 0x1c0 */ ZEROx8,
    351           /* 0x200 */ ZEROx8,
    352           /* 0x240 */ ZEROx8,
    353           /* 0x280 */ ZEROx8,
    354           /* TRIGGER_HAPPY1..TRIGGER_HAPPY7 */
    355           /* 0x2c0 */ 0x7f,
    356       },
    357     },
    358     {
    359       .name = "Logitech Driving Force, 0003:046d:c294 v0100",
    360       .bus_type = 0x0003,
    361       .vendor_id = 0x046d,
    362       .product_id = 0xc294,
    363       .version = 0x0100,
    364       .expected = SDL_UDEV_DEVICE_JOYSTICK,
    365       /* SYN, KEY, ABS */
    366       .ev = { 0x0b },
    367       /* X, Y, RZ, HAT0X, HAT0Y */
    368       .abs = { 0x23, 0x00, 0x03 },
    369       .keys = {
    370           /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
    371           /* 12 buttons: TRIGGER, THUMB, THUMB2, TOP, TOP2, PINKIE, BASE,
    372            * BASE2..BASE6 */
    373           /* 0x100 */ ZEROx4, 0xff, 0x0f, 0x00, 0x00,
    374       },
    375     },
    376     {
    377       .name = "Logitech Dual Action",
    378       .bus_type = 0x0003,
    379       .vendor_id = 0x046d,
    380       .product_id = 0xc216,
    381       .version = 0x0110,
    382       /* Logitech RumblePad 2 USB, 0003:046d:c218 v0110, is the same
    383        * except for having force feedback, which we don't use in our
    384        * heuristic */
    385       /* Jess Tech GGE909 PC Recoil Pad, 0003:0f30:010b v0110, is the same */
    386       /* 8BitDo SNES30, 0003:2dc8:ab20 v0110, is the same */
    387       .expected = SDL_UDEV_DEVICE_JOYSTICK,
    388       /* SYN, KEY, ABS */
    389       .ev = { 0x0b },
    390       /* X, Y, Z, RZ, HAT0X, HAT0Y */
    391       .abs = { 0x27, 0x00, 0x03 },
    392       .keys = {
    393           /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
    394           /* 12 buttons: TRIGGER, THUMB, THUMB2, TOP, TOP2, PINKIE, BASE,
    395            * BASE2..BASE6 */
    396           /* 0x100 */ ZEROx4, 0xff, 0x0f, 0x00, 0x00,
    397       },
    398     },
    399     {
    400       .name = "Saitek ST290 Pro flight stick",
    401       .bus_type = 0x0003,
    402       .vendor_id = 0x06a3,
    403       .product_id = 0x0160,   /* 0x0460 seems to be the same */
    404       .version = 0x0100,
    405       .expected = SDL_UDEV_DEVICE_JOYSTICK,
    406       /* SYN, KEY, ABS, MSC */
    407       .ev = { 0x1b },
    408       /* X, Y, Z, RZ, HAT0X, HAT0Y */
    409       .abs = { 0x27, 0x00, 0x03 },
    410       .keys = {
    411           /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
    412           /* TRIGGER, THUMB, THUMB2, TOP, TOP2, PINKIE */
    413           /* 0x100 */ ZEROx4, 0x3f, 0x00, 0x00, 0x00,
    414       },
    415     },
    416     {
    417       .name = "Saitek X52 Pro Flight Control System",
    418       .bus_type = 0x0003,
    419       .vendor_id = 0x06a3,
    420       .product_id = 0x0762,
    421       .version = 0x0111,
    422       .expected = SDL_UDEV_DEVICE_JOYSTICK,
    423       .ev = { 0x0b },
    424       /* XYZ, RXYZ, throttle, hat0, MISC, unregistered event code 0x29 */
    425       .abs = { 0x7f, 0x00, 0x03, 0x00, 0x00, 0x03 },
    426       .keys = {
    427           /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
    428           /* 16 buttons: TRIGGER, THUMB, THUMB2, TOP, TOP2, PINKIE, BASE,
    429            * BASE2..BASE6, unregistered event codes 0x12c-0x12e, DEAD */
    430           /* 0x100 */ ZEROx4, 0xff, 0xff, 0x00, 0x00,
    431           /* 0x140 */ ZEROx8,
    432           /* 0x180 */ ZEROx8,
    433           /* 0x1c0 */ ZEROx8,
    434           /* 0x200 */ ZEROx8,
    435           /* 0x240 */ ZEROx8,
    436           /* 0x280 */ ZEROx8,
    437           /* TRIGGER_HAPPY1..TRIGGER_HAPPY23 */
    438           /* 0x2c0 */ 0xff, 0xff, 0x7f,
    439       },
    440     },
    441     {
    442       .name = "Logitech Extreme 3D",
    443       .bus_type = 0x0003,
    444       .vendor_id = 0x046d,
    445       .product_id = 0xc215,
    446       .version = 0x0110,
    447       .expected = SDL_UDEV_DEVICE_JOYSTICK,
    448       /* SYN, KEY, ABS, MSC */
    449       .ev = { 0x0b },
    450       /* X, Y, RZ, throttle, hat 0 */
    451       .abs = { 0x63, 0x00, 0x03 },
    452       .keys = {
    453           /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
    454           /* 12 buttons: TRIGGER, THUMB, THUMB2, TOP, TOP2, PINKIE, BASE,
    455            * BASE2..BASE6 */
    456           /* 0x100 */ ZEROx4, 0xff, 0x0f, 0x00, 0x00,
    457       },
    458     },
    459     {
    460       .name = "Hori Real Arcade Pro VX-SA",
    461       .bus_type = 0x0003,
    462       .vendor_id = 0x24c6,
    463       .product_id = 0x5501,
    464       .version = 0x0533,
    465       .expected = SDL_UDEV_DEVICE_JOYSTICK,
    466       /* SYN, KEY, ABS */
    467       .ev = { 0x0b },
    468       /* X, Y, Z, RX, RY, RZ, hat 0 */
    469       .abs = { 0x3f, 0x00, 0x03 },
    470       .keys = {
    471           /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
    472           /* A, B, X, Y, TL, TR, SELECT, START, MODE, THUMBL, THUMBR */
    473           /* 0x100 */ ZEROx4, 0x00, 0x00, 0xdb, 0x7c,
    474       },
    475     },
    476     {
    477       .name = "Switch Pro Controller via Bluetooth",
    478       .bus_type = 0x0005,
    479       .vendor_id = 0x057e,
    480       .product_id = 0x2009,
    481       .version = 0x0001,
    482       .expected = SDL_UDEV_DEVICE_JOYSTICK,
    483       /* SYN, KEY, ABS */
    484       .ev = { 0x0b },
    485       /* X, Y, RX, RY, hat 0 */
    486       .abs = { 0x1b, 0x00, 0x03 },
    487       .keys = {
    488           /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
    489           /* 16 buttons: TRIGGER, THUMB, THUMB2, TOP, TOP2, PINKIE, BASE,
    490            * BASE2..BASE6, unregistered event codes 0x12c-0x12e, DEAD */
    491           /* 0x100 */ ZEROx4, 0xff, 0xff, 0x00, 0x00,
    492           /* 0x140 */ ZEROx8,
    493           /* 0x180 */ ZEROx8,
    494           /* 0x1c0 */ ZEROx8,
    495           /* 0x200 */ ZEROx8,
    496           /* 0x240 */ ZEROx8,
    497           /* 0x280 */ ZEROx8,
    498           /* TRIGGER_HAPPY1..TRIGGER_HAPPY2 */
    499           /* 0x2c0 */ 0x03,
    500       },
    501     },
    502     {
    503       .name = "Switch Pro Controller via USB",
    504       .bus_type = 0x0003,
    505       .vendor_id = 0x057e,
    506       .product_id = 0x2009,
    507       .version = 0x0111,
    508       .expected = SDL_UDEV_DEVICE_JOYSTICK,
    509       /* SYN, KEY, ABS */
    510       .ev = { 0x0b },
    511       /* X, Y, Z, RZ, HAT0X, HAT0Y */
    512       .abs = { 0x27, 0x00, 0x03 },
    513       .keys = {
    514           /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
    515       },
    516     },
    517     {
    518       .name = "Thrustmaster Racing Wheel FFB",
    519       /* Mad Catz FightStick TE S+ PS4, 0003:0738:8384:0111 v0111
    520        * (aka Street Fighter V Arcade FightStick TES+)
    521        * is functionally the same */
    522       .bus_type = 0x0003,
    523       .vendor_id = 0x044f,
    524       .product_id = 0xb66d,
    525       .version = 0x0110,
    526       .expected = SDL_UDEV_DEVICE_JOYSTICK,
    527       .ev = { 0x0b },
    528       /* XYZ, RXYZ, hat 0 */
    529       .abs = { 0x3f, 0x00, 0x03 },
    530       .keys = {
    531           /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
    532           /* ABC, XYZ, TL, TR, TL2, TR2, SELECT, START, MODE,
    533            * THUMBL */
    534           /* 0x100 */ ZEROx4, 0x00, 0x00, 0xff, 0x3f,
    535       },
    536     },
    537     {
    538       .name = "Thrustmaster T.Flight Hotas X",
    539       .bus_type = 0x0003,
    540       .vendor_id = 0x044f,
    541       .product_id = 0xb108,
    542       .version = 0x0100,
    543       .expected = SDL_UDEV_DEVICE_JOYSTICK,
    544       .ev = { 0x0b },
    545       /* XYZ, RZ, throttle, hat 0 */
    546       .abs = { 0x67, 0x00, 0x03 },
    547       .keys = {
    548           /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
    549           /* trigger, thumb, thumb2, top, top2, pinkie, base,
    550            * base2..base6 */
    551           /* 0x100 */ ZEROx4, 0xff, 0x0f
    552       },
    553     },
    554     {
    555       .name = "8BitDo N30 Pro 2",
    556       .bus_type = 0x0003,
    557       .vendor_id = 0x2dc8,
    558       .product_id = 0x9015,
    559       .version = 0x0111,
    560       /* 8BitDo NES30 Pro, 0003:2dc8:9001 v0111, is the same */
    561       .expected = SDL_UDEV_DEVICE_JOYSTICK,
    562       .ev = { 0x0b },
    563       /* XYZ, RZ, gas, brake, hat0 */
    564       .abs = { 0x27, 0x06, 0x03 },
    565       .keys = {
    566           /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
    567           /* ABC, XYZ, TL, TR, TL2, TR2, select, start, mode, thumbl,
    568            * thumbr */
    569           /* 0x100 */ ZEROx4, 0x00, 0x00, 0xff, 0x7f,
    570       },
    571     },
    572     {
    573       .name = "Retro Power SNES-style controller, 0003:0079:0011 v0110",
    574       .bus_type = 0x0003,
    575       .vendor_id = 0x0079,
    576       .product_id = 0x0011,
    577       .version = 0x0110,
    578       .expected = SDL_UDEV_DEVICE_JOYSTICK,
    579       .ev = { 0x0b },
    580       /* X, Y */
    581       .abs = { 0x03 },
    582       .keys = {
    583           /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
    584           /* trigger, thumb, thumb2, top, top2, pinkie, base,
    585            * base2..base4 */
    586           /* 0x100 */ ZEROx4, 0xff, 0x03, 0x00, 0x00,
    587       },
    588     },
    589     {
    590       .name = "Wiimote - buttons",
    591       .bus_type = 0x0005,
    592       .vendor_id = 0x057e,
    593       .product_id = 0x0306,
    594       .version = 0x8600,
    595       /* This one is a bit weird because some of the buttons are mapped
    596        * to the arrow, page up and page down keys, so it's a joystick
    597        * with a subset of a keyboard attached. */
    598       /* TODO: Should this be JOYSTICK, or even JOYSTICK|KEYBOARD? */
    599       .expected = SDL_UDEV_DEVICE_UNKNOWN,
    600       /* SYN, KEY */
    601       .ev = { 0x03 },
    602       .keys = {
    603           /* 0x00 */ ZEROx8,
    604           /* left, right, up down */
    605           /* 0x40 */ ZEROx4, 0x80, 0x16, 0x00, 0x00,
    606           /* 0x80 */ ZEROx8,
    607           /* 0xc0 */ ZEROx8,
    608           /* BTN_1, BTN_2, BTN_A, BTN_B, BTN_MODE */
    609           /* 0x100 */ 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x10,
    610           /* 0x140 */ ZEROx8,
    611           /* next, previous */
    612           /* 0x180 */ 0x00, 0x00, 0x80, 0x10, ZEROx4,
    613       },
    614     },
    615     {
    616       .name = "Wiimote - Motion Plus or accelerometer",
    617       .bus_type = 0x0005,
    618       .vendor_id = 0x057e,
    619       .product_id = 0x0306,
    620       .version = 0x8600,
    621       .expected = SDL_UDEV_DEVICE_ACCELEROMETER,
    622       /* SYN, ABS */
    623       .ev = { 0x09 },
    624       /* RX, RY, RZ */
    625       .abs = { 0x38 },
    626     },
    627     {
    628       .name = "Wiimote - IR positioning",
    629       .bus_type = 0x0005,
    630       .vendor_id = 0x057e,
    631       .product_id = 0x0306,
    632       .version = 0x8600,
    633       .expected = SDL_UDEV_DEVICE_UNKNOWN,
    634       /* SYN, ABS */
    635       .ev = { 0x09 },
    636       /* HAT0 to HAT3 */
    637       .abs = { 0x00, 0x1f },
    638     },
    639     {
    640       .name = "Wiimote - Nunchuck",
    641       .bus_type = 0x0005,
    642       .vendor_id = 0x057e,
    643       .product_id = 0x0306,
    644       .version = 0x8600,
    645       /* TODO: Should this be JOYSTICK? It has one stick and two buttons */
    646       .expected = SDL_UDEV_DEVICE_UNKNOWN,
    647       /* SYN, KEY, ABS */
    648       .ev = { 0x0b },
    649       /* RX, RY, RZ, hat 0 */
    650       .abs = { 0x38, 0x00, 0x03 },
    651       .keys = {
    652           /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
    653          /* C and Z buttons */
    654           /* 0x100 */ ZEROx4, 0x00, 0x00, 0x24, 0x00,
    655       },
    656     },
    657     {
    658       /* Flags guessed from kernel source code */
    659       .name = "Wiimote - Classic Controller",
    660       /* TODO: Should this be JOYSTICK, or maybe JOYSTICK|KEYBOARD?
    661        * It's unusual in the same ways as the Wiimote */
    662       .expected = SDL_UDEV_DEVICE_UNKNOWN,
    663       /* SYN, KEY, ABS */
    664       .ev = { 0x0b },
    665       /* Hat 1-3 */
    666       .abs = { 0x00, 0x1c },
    667       .keys = {
    668           /* 0x00 */ ZEROx8,
    669           /* left, right, up down */
    670           /* 0x40 */ ZEROx4, 0x80, 0x16, 0x00, 0x00,
    671           /* 0x80 */ ZEROx8,
    672           /* 0xc0 */ ZEROx8,
    673           /* A, B, X, Y, MODE, TL, TL2, TR, TR2 */
    674           /* 0x100 */ ZEROx4, 0x00, 0x13, 0xdb, 0x10,
    675           /* 0x140 */ ZEROx8,
    676           /* next, previous */
    677           /* 0x180 */ 0x00, 0x00, 0x80, 0x10, ZEROx4,
    678       },
    679     },
    680     {
    681       /* Flags guessed from kernel source code */
    682       .name = "Wiimote - Balance Board",
    683       /* TODO: Should this be JOYSTICK? */
    684       .expected = SDL_UDEV_DEVICE_UNKNOWN,
    685       /* SYN, KEY, ABS */
    686       .ev = { 0x0b },
    687       /* Hat 0-1 */
    688       .abs = { 0x00, 0x0f },
    689       .keys = {
    690           /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
    691           /* A */
    692           /* 0x100 */ ZEROx4, 0x00, 0x00, 0x01, 0x00,
    693       },
    694     },
    695     {
    696       /* Flags guessed from kernel source code */
    697       .name = "Wiimote - Wii U Pro Controller",
    698       .expected = SDL_UDEV_DEVICE_JOYSTICK,
    699       /* SYN, KEY, ABS */
    700       .ev = { 0x0b },
    701       /* X, Y, RX, RY */
    702       .abs = { 0x1b },
    703       .keys = {
    704           /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
    705           /* A, B, X, Y, TL, TR, TL2, TR2, SELECT, START, MODE,
    706            * THUMBL, THUMBR */
    707           /* 0x100 */ ZEROx4, 0x00, 0x00, 0xdb, 0x7f,
    708           /* 0x140 */ ZEROx8,
    709           /* 0x180 */ ZEROx8,
    710           /* 0x1c0 */ ZEROx8,
    711           /* Digital dpad */
    712           /* 0x200 */ ZEROx4, 0x0f, 0x00, 0x00, 0x00,
    713       },
    714     },
    715     {
    716       .name = "Synaptics TM3381-002 (Thinkpad X280 trackpad)",
    717       .bus_type = 0x001d,   /* BUS_RMI */
    718       .vendor_id = 0x06cb,
    719       .product_id = 0x0000,
    720       .version = 0x0000,
    721       /* TODO: Should this be MOUSE? That's what it most closely
    722        * resembles */
    723       .expected = SDL_UDEV_DEVICE_UNKNOWN,
    724       /* SYN, KEY, ABS */
    725       .ev = { 0x0b },
    726       /* X, Y, pressure, multitouch */
    727       .abs = { 0x03, 0x00, 0x00, 0x01, 0x00, 0x80, 0xf3, 0x06 },
    728       .keys = {
    729           /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
    730           /* Left mouse button */
    731           /* 0x100 */ 0x00, 0x00, 0x01, 0x00, ZEROx4,
    732           /* BTN_TOOL_FINGER and some multitouch gestures */
    733           /* 0x140 */ 0x20, 0xe5
    734       },
    735       /* POINTER, BUTTONPAD */
    736       .props = { 0x05 },
    737     },
    738     {
    739       .name = "TPPS/2 Elan TrackPoint (Thinkpad X280)",
    740       .bus_type = 0x0011,   /* BUS_I8042 */
    741       .vendor_id = 0x0002,
    742       .product_id = 0x000a,
    743       .version = 0x0000,
    744       .expected = SDL_UDEV_DEVICE_MOUSE,
    745       /* SYN, KEY, REL */
    746       .ev = { 0x07 },
    747       /* X, Y */
    748       .rel = { 0x03 },
    749       .keys = {
    750           /* 0x00-0xff */ ZEROx8, ZEROx8, ZEROx8, ZEROx8,
    751           /* Left, middle, right mouse buttons */
    752           /* 0x100 */ 0x00, 0x00, 0x07,
    753       },
    754       /* POINTER, POINTING_STICK */
    755       .props = { 0x21 },
    756     },
    757     {
    758       .name = "Thinkpad ACPI buttons",
    759       .expected = SDL_UDEV_DEVICE_UNKNOWN,
    760       /* SYN, KEY, MSC, SW */
    761       .ev = { 0x33 },
    762       .keys = {
    763           /* 0x00 */ ZEROx8,
    764           /* 0x40 */ ZEROx4, 0x00, 0x00, 0x0e, 0x01,
    765           /* 0x80 */ 0x00, 0x50, 0x11, 0x51, 0x00, 0x28, 0x00, 0xc0,
    766           /* 0xc0 */ 0x04, 0x20, 0x10, 0x02, 0x1b, 0x70, 0x01, 0x00,
    767           /* 0x100 */ ZEROx8,
    768           /* 0x140 */ ZEROx4, 0x00, 0x00, 0x50, 0x00,
    769           /* 0x180 */ ZEROx8,
    770           /* 0x1c0 */ 0x00, 0x00, 0x04, 0x18, ZEROx4,
    771           /* 0x200 */ ZEROx8,
    772           /* 0x240 */ 0x40, 0x00, 0x01, 0x00, ZEROx4,
    773       },
    774     },
    775     {
    776       .name = "PC speaker",
    777       .bus_type = 0x0010,   /* BUS_ISA */
    778       .vendor_id = 0x001f,
    779       .product_id = 0x0001,
    780       .version = 0x0100,
    781       .expected = SDL_UDEV_DEVICE_UNKNOWN,
    782       /* SYN, SND */
    783       .ev = { 0x01, 0x00, 0x04 },
    784     },
    785     {
    786       .name = "ALSA headphone detection, etc.",
    787       .bus_type = 0x0000,
    788       .vendor_id = 0x0000,
    789       .product_id = 0x0000,
    790       .version = 0x0000,
    791       .expected = SDL_UDEV_DEVICE_UNKNOWN,
    792       /* SYN, SW */
    793       .ev = { 0x21 },
    794     },
    795     {
    796       /* Assumed to be a reasonably typical i8042 (PC AT) keyboard */
    797       .name = "Thinkpad T520 and X280 keyboards",
    798       .bus_type = 0x0011,   /* BUS_I8042 */
    799       .vendor_id = 0x0001,
    800       .product_id = 0x0001,
    801       .version = 0xab54,
    802       .expected = SDL_UDEV_DEVICE_KEYBOARD,
    803       /* SYN, KEY, MSC, LED, REP */
    804       .ev = { 0x13, 0x00, 0x12 },
    805       .keys = {
    806           /* 0x00 */ 0xfe, 0xff, 0xff, 0xff, FFx4,
    807           /* 0x40 */ 0xff, 0xff, 0xef, 0xff, 0xdf, 0xff, 0xff, 0xfe,
    808           /* 0x80 */ 0x01, 0xd0, 0x00, 0xf8, 0x78, 0x30, 0x80, 0x03,
    809           /* 0xc0 */ 0x00, 0x00, 0x00, 0x02, 0x04, 0x00, 0x00, 0x00,
    810       },
    811     },
    812     {
    813       .name = "Thinkpad X280 sleep button",
    814       .bus_type = 0x0019,   /* BUS_HOST */
    815       .vendor_id = 0x0000,
    816       .product_id = 0x0003,
    817       .version = 0x0000,
    818       .expected = SDL_UDEV_DEVICE_UNKNOWN,
    819       /* SYN, KEY */
    820       .ev = { 0x03 },
    821       .keys = {
    822           /* 0x00 */ ZEROx8,
    823           /* 0x40 */ ZEROx8,
    824           /* KEY_SLEEP */
    825           /* 0x80 */ 0x00, 0x40,
    826       },
    827     },
    828     {
    829       .name = "Thinkpad X280 lid switch",
    830       .bus_type = 0x0019,   /* BUS_HOST */
    831       .vendor_id = 0x0000,
    832       .product_id = 0x0005,
    833       .version = 0x0000,
    834       .expected = SDL_UDEV_DEVICE_UNKNOWN,
    835       /* SYN, SW */
    836       .ev = { 0x21 },
    837     },
    838     {
    839       .name = "Thinkpad X280 power button",
    840       .bus_type = 0x0019,   /* BUS_HOST */
    841       .vendor_id = 0x0000,
    842       .product_id = 0x0001,
    843       .version = 0x0000,
    844       .expected = SDL_UDEV_DEVICE_UNKNOWN,
    845       /* SYN, KEY */
    846       .ev = { 0x03 },
    847       .keys = {
    848           /* 0x00 */ ZEROx8,
    849           /* KEY_POWER */
    850           /* 0x40 */ ZEROx4, 0x00, 0x00, 0x10, 0x00,
    851       },
    852     },
    853     {
    854       .name = "Thinkpad X280 video bus",
    855       .bus_type = 0x0019,   /* BUS_HOST */
    856       .vendor_id = 0x0000,
    857       .product_id = 0x0006,
    858       .version = 0x0000,
    859       .expected = SDL_UDEV_DEVICE_UNKNOWN,
    860       /* SYN, KEY */
    861       .ev = { 0x03 },
    862       .keys = {
    863           /* 0x00 */ ZEROx8,
    864           /* 0x40 */ ZEROx8,
    865           /* 0x80 */ ZEROx8,
    866           /* brightness control, video mode, display off */
    867           /* 0xc0 */ ZEROx4, 0x0b, 0x00, 0x3e, 0x00,
    868       },
    869     },
    870     {
    871       .name = "Thinkpad X280 extra buttons",
    872       .bus_type = 0x0019,   /* BUS_HOST */
    873       .vendor_id = 0x17aa,
    874       .product_id = 0x5054,
    875       .version = 0x4101,
    876       .expected = SDL_UDEV_DEVICE_UNKNOWN,
    877       /* SYN, KEY */
    878       .ev = { 0x03 },
    879       .keys = {
    880           /* 0x00 */ ZEROx8,
    881           /* 0x40 */ ZEROx4, 0x00, 0x00, 0x0e, 0x01,
    882           /* 0x80 */ 0x00, 0x50, 0x11, 0x51, 0x00, 0x28, 0x00, 0xc0,
    883           /* 0xc0 */ 0x04, 0x20, 0x10, 0x02, 0x1b, 0x70, 0x01, 0x00,
    884           /* 0x100 */ ZEROx8,
    885           /* 0x140 */ ZEROx4, 0x00, 0x00, 0x50, 0x00,
    886           /* 0x180 */ ZEROx8,
    887           /* 0x1c0 */ 0x00, 0x00, 0x04, 0x18, ZEROx4,
    888           /* 0x200 */ ZEROx8,
    889           /* 0x240 */ 0x40, 0x00, 0x01, 0x00, ZEROx4,
    890       },
    891     },
    892     {
    893       .name = "Thinkpad USB keyboard with Trackpoint - keyboard",
    894       .bus_type = 0x0003,
    895       .vendor_id = 0x17ef,
    896       .product_id = 0x6009,
    897       .expected = SDL_UDEV_DEVICE_KEYBOARD,
    898       /* SYN, KEY, MSC, LED, REP */
    899       .ev = { 0x13, 0x00, 0x12 },
    900       .keys = {
    901           /* 0x00 */ 0xfe, 0xff, 0xff, 0xff, FFx4,
    902           /* 0x40 */ 0xff, 0xff, 0xef, 0xff, 0xdf, 0xff, 0xbe, 0xfe,
    903           /* 0x80 */ 0xff, 0x57, 0x40, 0xc1, 0x7a, 0x20, 0x9f, 0xff,
    904           /* 0xc0 */ 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
    905       },
    906     },
    907     {
    908       .name = "Thinkpad USB keyboard with Trackpoint - Trackpoint",
    909       .bus_type = 0x0003,
    910       .vendor_id = 0x17ef,
    911       .product_id = 0x6009,
    912       /* For some reason the special keys like mute and wlan toggle
    913        * show up here instead of, or in addition to, as part of
    914        * the keyboard - so udev reports this as having keys too.
    915        * SDL currently doesn't. */
    916       .expected = SDL_UDEV_DEVICE_MOUSE,
    917       /* SYN, KEY, REL, MSC, LED */
    918       .ev = { 0x17, 0x00, 0x02 },
    919       /* X, Y */
    920       .rel = { 0x03 },
    921       .keys = {
    922           /* 0x00 */ ZEROx8,
    923           /* 0x40 */ ZEROx4, 0x00, 0x00, 0x1e, 0x00,
    924           /* 0x80 */ 0x00, 0xcc, 0x11, 0x01, 0x78, 0x40, 0x00, 0xc0,
    925           /* 0xc0 */ 0x00, 0x20, 0x10, 0x00, 0x0b, 0x50, 0x00, 0x00,
    926           /* Mouse buttons: left, right, middle, "task" */
    927           /* 0x100 */ 0x00, 0x00, 0x87, 0x68, ZEROx4,
    928           /* 0x140 */ ZEROx4, 0x00, 0x00, 0x10, 0x00,
    929           /* 0x180 */ ZEROx4, 0x00, 0x00, 0x40, 0x00,
    930       },
    931     },
    932     {
    933       .name = "No information",
    934       .expected = SDL_UDEV_DEVICE_UNKNOWN,
    935     }
    936 };
    937 
    938 #if ULONG_MAX == 0xFFFFFFFFUL
    939 #   define SwapLongLE(X) SDL_SwapLE32(X)
    940 #else
    941     /* assume 64-bit */
    942 #   define SwapLongLE(X) SDL_SwapLE64(X)
    943 #endif
    944 
    945 static int
    946 run_test(void)
    947 {
    948     int success = 1;
    949     size_t i;
    950 
    951     for (i = 0; i < SDL_arraysize(guess_tests); i++) {
    952         const GuessTest *t = &guess_tests[i];
    953         size_t j;
    954         int actual;
    955         struct {
    956             unsigned long ev[NBITS(EV_MAX)];
    957             unsigned long abs[NBITS(ABS_MAX)];
    958             unsigned long keys[NBITS(KEY_MAX)];
    959             unsigned long rel[NBITS(REL_MAX)];
    960         } caps = {};
    961 
    962         printf("%s...\n", t->name);
    963 
    964         memset(&caps, '\0', sizeof(caps));
    965         memcpy(caps.ev, t->ev, sizeof(t->ev));
    966         memcpy(caps.keys, t->keys, sizeof(t->keys));
    967         memcpy(caps.abs, t->abs, sizeof(t->abs));
    968         memcpy(caps.rel, t->rel, sizeof(t->rel));
    969 
    970         for (j = 0; j < SDL_arraysize(caps.ev); j++) {
    971             caps.ev[j] = SwapLongLE(caps.ev[j]);
    972         }
    973 
    974         for (j = 0; j < SDL_arraysize(caps.keys); j++) {
    975             caps.keys[j] = SwapLongLE(caps.keys[j]);
    976         }
    977 
    978         for (j = 0; j < SDL_arraysize(caps.abs); j++) {
    979             caps.abs[j] = SwapLongLE(caps.abs[j]);
    980         }
    981 
    982         for (j = 0; j < SDL_arraysize(caps.rel); j++) {
    983             caps.rel[j] = SwapLongLE(caps.rel[j]);
    984         }
    985 
    986         actual = SDL_EVDEV_GuessDeviceClass(caps.ev, caps.abs, caps.keys,
    987                                             caps.rel);
    988 
    989         if (actual == t->expected) {
    990             printf("\tOK\n");
    991         }
    992         else {
    993             printf("\tExpected 0x%08x\n", t->expected);
    994 
    995             for (j = 0; device_classes[j].code != 0; j++) {
    996                 if (t->expected & device_classes[j].code) {
    997                     printf("\t\t%s\n", device_classes[j].name);
    998                 }
    999             }
   1000 
   1001             printf("\tGot      0x%08x\n", actual);
   1002 
   1003             for (j = 0; device_classes[j].code != 0; j++) {
   1004                 if (actual & device_classes[j].code) {
   1005                     printf("\t\t%s\n", device_classes[j].name);
   1006                 }
   1007             }
   1008 
   1009             success = 0;
   1010         }
   1011     }
   1012 
   1013     return success;
   1014 }
   1015 
   1016 #else /* !(HAVE_LIBUDEV_H || defined(SDL_JOYSTICK_LINUX)) */
   1017 
   1018 static int
   1019 run_test(void)
   1020 {
   1021     printf("SDL compiled without evdev capability check.\n");
   1022     return 0;
   1023 }
   1024 
   1025 #endif
   1026 
   1027 int
   1028 main(int argc, char *argv[])
   1029 {
   1030     return run_test() ? 0 : 1;
   1031 }