162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci 362306a36Sopenharmony_ci/* 462306a36Sopenharmony_ci * HID driver for UC-Logic devices not fully compliant with HID standard 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright (c) 2022 José Expósito <jose.exposito89@gmail.com> 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <kunit/test.h> 1062306a36Sopenharmony_ci#include "./hid-uclogic-params.h" 1162306a36Sopenharmony_ci#include "./hid-uclogic-rdesc.h" 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#define MAX_STR_DESC_SIZE 14 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_cistruct uclogic_parse_ugee_v2_desc_case { 1662306a36Sopenharmony_ci const char *name; 1762306a36Sopenharmony_ci int res; 1862306a36Sopenharmony_ci const __u8 str_desc[MAX_STR_DESC_SIZE]; 1962306a36Sopenharmony_ci size_t str_desc_size; 2062306a36Sopenharmony_ci const s32 desc_params[UCLOGIC_RDESC_PH_ID_NUM]; 2162306a36Sopenharmony_ci enum uclogic_params_frame_type frame_type; 2262306a36Sopenharmony_ci}; 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_cistatic struct uclogic_parse_ugee_v2_desc_case uclogic_parse_ugee_v2_desc_cases[] = { 2562306a36Sopenharmony_ci { 2662306a36Sopenharmony_ci .name = "invalid_str_desc", 2762306a36Sopenharmony_ci .res = -EINVAL, 2862306a36Sopenharmony_ci .str_desc = {}, 2962306a36Sopenharmony_ci .str_desc_size = 0, 3062306a36Sopenharmony_ci .desc_params = {}, 3162306a36Sopenharmony_ci .frame_type = UCLOGIC_PARAMS_FRAME_BUTTONS, 3262306a36Sopenharmony_ci }, 3362306a36Sopenharmony_ci { 3462306a36Sopenharmony_ci .name = "resolution_with_value_0", 3562306a36Sopenharmony_ci .res = 0, 3662306a36Sopenharmony_ci .str_desc = { 3762306a36Sopenharmony_ci 0x0E, 0x03, 3862306a36Sopenharmony_ci 0x70, 0xB2, 3962306a36Sopenharmony_ci 0x10, 0x77, 4062306a36Sopenharmony_ci 0x08, 4162306a36Sopenharmony_ci 0x00, 4262306a36Sopenharmony_ci 0xFF, 0x1F, 4362306a36Sopenharmony_ci 0x00, 0x00, 4462306a36Sopenharmony_ci }, 4562306a36Sopenharmony_ci .str_desc_size = 12, 4662306a36Sopenharmony_ci .desc_params = { 4762306a36Sopenharmony_ci [UCLOGIC_RDESC_PEN_PH_ID_X_LM] = 0xB270, 4862306a36Sopenharmony_ci [UCLOGIC_RDESC_PEN_PH_ID_X_PM] = 0, 4962306a36Sopenharmony_ci [UCLOGIC_RDESC_PEN_PH_ID_Y_LM] = 0x7710, 5062306a36Sopenharmony_ci [UCLOGIC_RDESC_PEN_PH_ID_Y_PM] = 0, 5162306a36Sopenharmony_ci [UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM] = 0x1FFF, 5262306a36Sopenharmony_ci [UCLOGIC_RDESC_FRAME_PH_ID_UM] = 0x08, 5362306a36Sopenharmony_ci }, 5462306a36Sopenharmony_ci .frame_type = UCLOGIC_PARAMS_FRAME_BUTTONS, 5562306a36Sopenharmony_ci }, 5662306a36Sopenharmony_ci /* XP-PEN Deco L str_desc: Frame with 8 buttons */ 5762306a36Sopenharmony_ci { 5862306a36Sopenharmony_ci .name = "frame_type_buttons", 5962306a36Sopenharmony_ci .res = 0, 6062306a36Sopenharmony_ci .str_desc = { 6162306a36Sopenharmony_ci 0x0E, 0x03, 6262306a36Sopenharmony_ci 0x70, 0xB2, 6362306a36Sopenharmony_ci 0x10, 0x77, 6462306a36Sopenharmony_ci 0x08, 6562306a36Sopenharmony_ci 0x00, 6662306a36Sopenharmony_ci 0xFF, 0x1F, 6762306a36Sopenharmony_ci 0xD8, 0x13, 6862306a36Sopenharmony_ci }, 6962306a36Sopenharmony_ci .str_desc_size = 12, 7062306a36Sopenharmony_ci .desc_params = { 7162306a36Sopenharmony_ci [UCLOGIC_RDESC_PEN_PH_ID_X_LM] = 0xB270, 7262306a36Sopenharmony_ci [UCLOGIC_RDESC_PEN_PH_ID_X_PM] = 0x2320, 7362306a36Sopenharmony_ci [UCLOGIC_RDESC_PEN_PH_ID_Y_LM] = 0x7710, 7462306a36Sopenharmony_ci [UCLOGIC_RDESC_PEN_PH_ID_Y_PM] = 0x1770, 7562306a36Sopenharmony_ci [UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM] = 0x1FFF, 7662306a36Sopenharmony_ci [UCLOGIC_RDESC_FRAME_PH_ID_UM] = 0x08, 7762306a36Sopenharmony_ci }, 7862306a36Sopenharmony_ci .frame_type = UCLOGIC_PARAMS_FRAME_BUTTONS, 7962306a36Sopenharmony_ci }, 8062306a36Sopenharmony_ci /* PARBLO A610 PRO str_desc: Frame with 9 buttons and dial */ 8162306a36Sopenharmony_ci { 8262306a36Sopenharmony_ci .name = "frame_type_dial", 8362306a36Sopenharmony_ci .res = 0, 8462306a36Sopenharmony_ci .str_desc = { 8562306a36Sopenharmony_ci 0x0E, 0x03, 8662306a36Sopenharmony_ci 0x96, 0xC7, 8762306a36Sopenharmony_ci 0xF9, 0x7C, 8862306a36Sopenharmony_ci 0x09, 8962306a36Sopenharmony_ci 0x01, 9062306a36Sopenharmony_ci 0xFF, 0x1F, 9162306a36Sopenharmony_ci 0xD8, 0x13, 9262306a36Sopenharmony_ci }, 9362306a36Sopenharmony_ci .str_desc_size = 12, 9462306a36Sopenharmony_ci .desc_params = { 9562306a36Sopenharmony_ci [UCLOGIC_RDESC_PEN_PH_ID_X_LM] = 0xC796, 9662306a36Sopenharmony_ci [UCLOGIC_RDESC_PEN_PH_ID_X_PM] = 0x2749, 9762306a36Sopenharmony_ci [UCLOGIC_RDESC_PEN_PH_ID_Y_LM] = 0x7CF9, 9862306a36Sopenharmony_ci [UCLOGIC_RDESC_PEN_PH_ID_Y_PM] = 0x1899, 9962306a36Sopenharmony_ci [UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM] = 0x1FFF, 10062306a36Sopenharmony_ci [UCLOGIC_RDESC_FRAME_PH_ID_UM] = 0x09, 10162306a36Sopenharmony_ci }, 10262306a36Sopenharmony_ci .frame_type = UCLOGIC_PARAMS_FRAME_DIAL, 10362306a36Sopenharmony_ci }, 10462306a36Sopenharmony_ci /* XP-PEN Deco Pro S str_desc: Frame with 8 buttons and mouse */ 10562306a36Sopenharmony_ci { 10662306a36Sopenharmony_ci .name = "frame_type_mouse", 10762306a36Sopenharmony_ci .res = 0, 10862306a36Sopenharmony_ci .str_desc = { 10962306a36Sopenharmony_ci 0x0E, 0x03, 11062306a36Sopenharmony_ci 0xC8, 0xB3, 11162306a36Sopenharmony_ci 0x34, 0x65, 11262306a36Sopenharmony_ci 0x08, 11362306a36Sopenharmony_ci 0x02, 11462306a36Sopenharmony_ci 0xFF, 0x1F, 11562306a36Sopenharmony_ci 0xD8, 0x13, 11662306a36Sopenharmony_ci }, 11762306a36Sopenharmony_ci .str_desc_size = 12, 11862306a36Sopenharmony_ci .desc_params = { 11962306a36Sopenharmony_ci [UCLOGIC_RDESC_PEN_PH_ID_X_LM] = 0xB3C8, 12062306a36Sopenharmony_ci [UCLOGIC_RDESC_PEN_PH_ID_X_PM] = 0x2363, 12162306a36Sopenharmony_ci [UCLOGIC_RDESC_PEN_PH_ID_Y_LM] = 0x6534, 12262306a36Sopenharmony_ci [UCLOGIC_RDESC_PEN_PH_ID_Y_PM] = 0x13EC, 12362306a36Sopenharmony_ci [UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM] = 0x1FFF, 12462306a36Sopenharmony_ci [UCLOGIC_RDESC_FRAME_PH_ID_UM] = 0x08, 12562306a36Sopenharmony_ci }, 12662306a36Sopenharmony_ci .frame_type = UCLOGIC_PARAMS_FRAME_MOUSE, 12762306a36Sopenharmony_ci }, 12862306a36Sopenharmony_ci}; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_cistatic void uclogic_parse_ugee_v2_desc_case_desc(struct uclogic_parse_ugee_v2_desc_case *t, 13162306a36Sopenharmony_ci char *desc) 13262306a36Sopenharmony_ci{ 13362306a36Sopenharmony_ci strscpy(desc, t->name, KUNIT_PARAM_DESC_SIZE); 13462306a36Sopenharmony_ci} 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ciKUNIT_ARRAY_PARAM(uclogic_parse_ugee_v2_desc, uclogic_parse_ugee_v2_desc_cases, 13762306a36Sopenharmony_ci uclogic_parse_ugee_v2_desc_case_desc); 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_cistatic void hid_test_uclogic_parse_ugee_v2_desc(struct kunit *test) 14062306a36Sopenharmony_ci{ 14162306a36Sopenharmony_ci int res; 14262306a36Sopenharmony_ci s32 desc_params[UCLOGIC_RDESC_PH_ID_NUM]; 14362306a36Sopenharmony_ci enum uclogic_params_frame_type frame_type; 14462306a36Sopenharmony_ci const struct uclogic_parse_ugee_v2_desc_case *params = test->param_value; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci res = uclogic_params_parse_ugee_v2_desc(params->str_desc, 14762306a36Sopenharmony_ci params->str_desc_size, 14862306a36Sopenharmony_ci desc_params, 14962306a36Sopenharmony_ci ARRAY_SIZE(desc_params), 15062306a36Sopenharmony_ci &frame_type); 15162306a36Sopenharmony_ci KUNIT_ASSERT_EQ(test, res, params->res); 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci if (res) 15462306a36Sopenharmony_ci return; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci KUNIT_EXPECT_EQ(test, 15762306a36Sopenharmony_ci params->desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_LM], 15862306a36Sopenharmony_ci desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_LM]); 15962306a36Sopenharmony_ci KUNIT_EXPECT_EQ(test, 16062306a36Sopenharmony_ci params->desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_PM], 16162306a36Sopenharmony_ci desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_PM]); 16262306a36Sopenharmony_ci KUNIT_EXPECT_EQ(test, 16362306a36Sopenharmony_ci params->desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM], 16462306a36Sopenharmony_ci desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM]); 16562306a36Sopenharmony_ci KUNIT_EXPECT_EQ(test, 16662306a36Sopenharmony_ci params->desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM], 16762306a36Sopenharmony_ci desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM]); 16862306a36Sopenharmony_ci KUNIT_EXPECT_EQ(test, 16962306a36Sopenharmony_ci params->desc_params[UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM], 17062306a36Sopenharmony_ci desc_params[UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM]); 17162306a36Sopenharmony_ci KUNIT_EXPECT_EQ(test, 17262306a36Sopenharmony_ci params->desc_params[UCLOGIC_RDESC_FRAME_PH_ID_UM], 17362306a36Sopenharmony_ci desc_params[UCLOGIC_RDESC_FRAME_PH_ID_UM]); 17462306a36Sopenharmony_ci KUNIT_EXPECT_EQ(test, params->frame_type, frame_type); 17562306a36Sopenharmony_ci} 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_cistruct fake_device { 17862306a36Sopenharmony_ci unsigned long quirks; 17962306a36Sopenharmony_ci}; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_cistatic void hid_test_uclogic_params_cleanup_event_hooks(struct kunit *test) 18262306a36Sopenharmony_ci{ 18362306a36Sopenharmony_ci int res, n; 18462306a36Sopenharmony_ci struct hid_device *hdev; 18562306a36Sopenharmony_ci struct fake_device *fake_dev; 18662306a36Sopenharmony_ci struct uclogic_params p = {0, }; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci hdev = kunit_kzalloc(test, sizeof(struct hid_device), GFP_KERNEL); 18962306a36Sopenharmony_ci KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hdev); 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci fake_dev = kunit_kzalloc(test, sizeof(struct fake_device), GFP_KERNEL); 19262306a36Sopenharmony_ci KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fake_dev); 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci hid_set_drvdata(hdev, fake_dev); 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci res = uclogic_params_ugee_v2_init_event_hooks(hdev, &p); 19762306a36Sopenharmony_ci KUNIT_ASSERT_EQ(test, res, 0); 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci /* Check that the function can be called repeatedly */ 20062306a36Sopenharmony_ci for (n = 0; n < 4; n++) { 20162306a36Sopenharmony_ci uclogic_params_cleanup_event_hooks(&p); 20262306a36Sopenharmony_ci KUNIT_EXPECT_PTR_EQ(test, p.event_hooks, NULL); 20362306a36Sopenharmony_ci } 20462306a36Sopenharmony_ci} 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_cistatic struct kunit_case hid_uclogic_params_test_cases[] = { 20762306a36Sopenharmony_ci KUNIT_CASE_PARAM(hid_test_uclogic_parse_ugee_v2_desc, 20862306a36Sopenharmony_ci uclogic_parse_ugee_v2_desc_gen_params), 20962306a36Sopenharmony_ci KUNIT_CASE(hid_test_uclogic_params_cleanup_event_hooks), 21062306a36Sopenharmony_ci {} 21162306a36Sopenharmony_ci}; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_cistatic struct kunit_suite hid_uclogic_params_test_suite = { 21462306a36Sopenharmony_ci .name = "hid_uclogic_params_test", 21562306a36Sopenharmony_ci .test_cases = hid_uclogic_params_test_cases, 21662306a36Sopenharmony_ci}; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_cikunit_test_suite(hid_uclogic_params_test_suite); 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ciMODULE_DESCRIPTION("KUnit tests for the UC-Logic driver"); 22162306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 22262306a36Sopenharmony_ciMODULE_AUTHOR("José Expósito <jose.exposito89@gmail.com>"); 223