1 // SPDX-License-Identifier: GPL-2.0+ 2 3 /* 4 * HID driver for UC-Logic devices not fully compliant with HID standard 5 * 6 * Copyright (c) 2022 José Expósito <jose.exposito89@gmail.com> 7 */ 8 9 #include <kunit/test.h> 10 #include "./hid-uclogic-params.h" 11 #include "./hid-uclogic-rdesc.h" 12 13 #define MAX_STR_DESC_SIZE 14 14 15 struct uclogic_parse_ugee_v2_desc_case { 16 const char *name; 17 int res; 18 const __u8 str_desc[MAX_STR_DESC_SIZE]; 19 size_t str_desc_size; 20 const s32 desc_params[UCLOGIC_RDESC_PH_ID_NUM]; 21 enum uclogic_params_frame_type frame_type; 22 }; 23 24 static struct uclogic_parse_ugee_v2_desc_case uclogic_parse_ugee_v2_desc_cases[] = { 25 { 26 .name = "invalid_str_desc", 27 .res = -EINVAL, 28 .str_desc = {}, 29 .str_desc_size = 0, 30 .desc_params = {}, 31 .frame_type = UCLOGIC_PARAMS_FRAME_BUTTONS, 32 }, 33 { 34 .name = "resolution_with_value_0", 35 .res = 0, 36 .str_desc = { 37 0x0E, 0x03, 38 0x70, 0xB2, 39 0x10, 0x77, 40 0x08, 41 0x00, 42 0xFF, 0x1F, 43 0x00, 0x00, 44 }, 45 .str_desc_size = 12, 46 .desc_params = { 47 [UCLOGIC_RDESC_PEN_PH_ID_X_LM] = 0xB270, 48 [UCLOGIC_RDESC_PEN_PH_ID_X_PM] = 0, 49 [UCLOGIC_RDESC_PEN_PH_ID_Y_LM] = 0x7710, 50 [UCLOGIC_RDESC_PEN_PH_ID_Y_PM] = 0, 51 [UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM] = 0x1FFF, 52 [UCLOGIC_RDESC_FRAME_PH_ID_UM] = 0x08, 53 }, 54 .frame_type = UCLOGIC_PARAMS_FRAME_BUTTONS, 55 }, 56 /* XP-PEN Deco L str_desc: Frame with 8 buttons */ 57 { 58 .name = "frame_type_buttons", 59 .res = 0, 60 .str_desc = { 61 0x0E, 0x03, 62 0x70, 0xB2, 63 0x10, 0x77, 64 0x08, 65 0x00, 66 0xFF, 0x1F, 67 0xD8, 0x13, 68 }, 69 .str_desc_size = 12, 70 .desc_params = { 71 [UCLOGIC_RDESC_PEN_PH_ID_X_LM] = 0xB270, 72 [UCLOGIC_RDESC_PEN_PH_ID_X_PM] = 0x2320, 73 [UCLOGIC_RDESC_PEN_PH_ID_Y_LM] = 0x7710, 74 [UCLOGIC_RDESC_PEN_PH_ID_Y_PM] = 0x1770, 75 [UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM] = 0x1FFF, 76 [UCLOGIC_RDESC_FRAME_PH_ID_UM] = 0x08, 77 }, 78 .frame_type = UCLOGIC_PARAMS_FRAME_BUTTONS, 79 }, 80 /* PARBLO A610 PRO str_desc: Frame with 9 buttons and dial */ 81 { 82 .name = "frame_type_dial", 83 .res = 0, 84 .str_desc = { 85 0x0E, 0x03, 86 0x96, 0xC7, 87 0xF9, 0x7C, 88 0x09, 89 0x01, 90 0xFF, 0x1F, 91 0xD8, 0x13, 92 }, 93 .str_desc_size = 12, 94 .desc_params = { 95 [UCLOGIC_RDESC_PEN_PH_ID_X_LM] = 0xC796, 96 [UCLOGIC_RDESC_PEN_PH_ID_X_PM] = 0x2749, 97 [UCLOGIC_RDESC_PEN_PH_ID_Y_LM] = 0x7CF9, 98 [UCLOGIC_RDESC_PEN_PH_ID_Y_PM] = 0x1899, 99 [UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM] = 0x1FFF, 100 [UCLOGIC_RDESC_FRAME_PH_ID_UM] = 0x09, 101 }, 102 .frame_type = UCLOGIC_PARAMS_FRAME_DIAL, 103 }, 104 /* XP-PEN Deco Pro S str_desc: Frame with 8 buttons and mouse */ 105 { 106 .name = "frame_type_mouse", 107 .res = 0, 108 .str_desc = { 109 0x0E, 0x03, 110 0xC8, 0xB3, 111 0x34, 0x65, 112 0x08, 113 0x02, 114 0xFF, 0x1F, 115 0xD8, 0x13, 116 }, 117 .str_desc_size = 12, 118 .desc_params = { 119 [UCLOGIC_RDESC_PEN_PH_ID_X_LM] = 0xB3C8, 120 [UCLOGIC_RDESC_PEN_PH_ID_X_PM] = 0x2363, 121 [UCLOGIC_RDESC_PEN_PH_ID_Y_LM] = 0x6534, 122 [UCLOGIC_RDESC_PEN_PH_ID_Y_PM] = 0x13EC, 123 [UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM] = 0x1FFF, 124 [UCLOGIC_RDESC_FRAME_PH_ID_UM] = 0x08, 125 }, 126 .frame_type = UCLOGIC_PARAMS_FRAME_MOUSE, 127 }, 128 }; 129 130 static void uclogic_parse_ugee_v2_desc_case_desc(struct uclogic_parse_ugee_v2_desc_case *t, 131 char *desc) 132 { 133 strscpy(desc, t->name, KUNIT_PARAM_DESC_SIZE); 134 } 135 136 KUNIT_ARRAY_PARAM(uclogic_parse_ugee_v2_desc, uclogic_parse_ugee_v2_desc_cases, 137 uclogic_parse_ugee_v2_desc_case_desc); 138 139 static void hid_test_uclogic_parse_ugee_v2_desc(struct kunit *test) 140 { 141 int res; 142 s32 desc_params[UCLOGIC_RDESC_PH_ID_NUM]; 143 enum uclogic_params_frame_type frame_type; 144 const struct uclogic_parse_ugee_v2_desc_case *params = test->param_value; 145 146 res = uclogic_params_parse_ugee_v2_desc(params->str_desc, 147 params->str_desc_size, 148 desc_params, 149 ARRAY_SIZE(desc_params), 150 &frame_type); 151 KUNIT_ASSERT_EQ(test, res, params->res); 152 153 if (res) 154 return; 155 156 KUNIT_EXPECT_EQ(test, 157 params->desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_LM], 158 desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_LM]); 159 KUNIT_EXPECT_EQ(test, 160 params->desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_PM], 161 desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_PM]); 162 KUNIT_EXPECT_EQ(test, 163 params->desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM], 164 desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM]); 165 KUNIT_EXPECT_EQ(test, 166 params->desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM], 167 desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM]); 168 KUNIT_EXPECT_EQ(test, 169 params->desc_params[UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM], 170 desc_params[UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM]); 171 KUNIT_EXPECT_EQ(test, 172 params->desc_params[UCLOGIC_RDESC_FRAME_PH_ID_UM], 173 desc_params[UCLOGIC_RDESC_FRAME_PH_ID_UM]); 174 KUNIT_EXPECT_EQ(test, params->frame_type, frame_type); 175 } 176 177 static void hid_test_uclogic_params_cleanup_event_hooks(struct kunit *test) 178 { 179 int res, n; 180 struct uclogic_params p = {0, }; 181 182 res = uclogic_params_ugee_v2_init_event_hooks(NULL, &p); 183 KUNIT_ASSERT_EQ(test, res, 0); 184 185 /* Check that the function can be called repeatedly */ 186 for (n = 0; n < 4; n++) { 187 uclogic_params_cleanup_event_hooks(&p); 188 KUNIT_EXPECT_PTR_EQ(test, p.event_hooks, NULL); 189 } 190 } 191 192 static struct kunit_case hid_uclogic_params_test_cases[] = { 193 KUNIT_CASE_PARAM(hid_test_uclogic_parse_ugee_v2_desc, 194 uclogic_parse_ugee_v2_desc_gen_params), 195 KUNIT_CASE(hid_test_uclogic_params_cleanup_event_hooks), 196 {} 197 }; 198 199 static struct kunit_suite hid_uclogic_params_test_suite = { 200 .name = "hid_uclogic_params_test", 201 .test_cases = hid_uclogic_params_test_cases, 202 }; 203 204 kunit_test_suite(hid_uclogic_params_test_suite); 205 206 MODULE_DESCRIPTION("KUnit tests for the UC-Logic driver"); 207 MODULE_LICENSE("GPL"); 208 MODULE_AUTHOR("José Expósito <jose.exposito89@gmail.com>"); 209