--- /dev/null
+// SPDX-License-Identifier: GPL-2.0+
+
+/*
+ *  HID driver for UC-Logic devices not fully compliant with HID standard
+ *
+ *  Copyright (c) 2022 José Expósito <jose.exposito89@gmail.com>
+ */
+
+#include <kunit/test.h>
+#include "./hid-uclogic-params.h"
+
+#define MAX_EVENT_SIZE 12
+
+struct uclogic_raw_event_hook_test {
+       u8 event[MAX_EVENT_SIZE];
+       size_t size;
+       bool expected;
+};
+
+static struct uclogic_raw_event_hook_test hook_events[] = {
+       {
+               .event = { 0xA1, 0xB2, 0xC3, 0xD4 },
+               .size = 4,
+       },
+       {
+               .event = { 0x1F, 0x2E, 0x3D, 0x4C, 0x5B, 0x6A },
+               .size = 6,
+       },
+};
+
+static struct uclogic_raw_event_hook_test test_events[] = {
+       {
+               .event = { 0xA1, 0xB2, 0xC3, 0xD4 },
+               .size = 4,
+               .expected = true,
+       },
+       {
+               .event = { 0x1F, 0x2E, 0x3D, 0x4C, 0x5B, 0x6A },
+               .size = 6,
+               .expected = true,
+       },
+       {
+               .event = { 0xA1, 0xB2, 0xC3 },
+               .size = 3,
+               .expected = false,
+       },
+       {
+               .event = { 0xA1, 0xB2, 0xC3, 0xD4, 0x00 },
+               .size = 5,
+               .expected = false,
+       },
+       {
+               .event = { 0x2E, 0x3D, 0x4C, 0x5B, 0x6A, 0x1F },
+               .size = 6,
+               .expected = false,
+       },
+};
+
+static void hid_test_uclogic_exec_event_hook_test(struct kunit *test)
+{
+       struct uclogic_params p = {0, };
+       struct uclogic_raw_event_hook *filter;
+       bool res;
+       int n;
+
+       /* Initialize the list of events to hook */
+       p.event_hooks = kunit_kzalloc(test, sizeof(*p.event_hooks), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, p.event_hooks);
+       INIT_LIST_HEAD(&p.event_hooks->list);
+
+       for (n = 0; n < ARRAY_SIZE(hook_events); n++) {
+               filter = kunit_kzalloc(test, sizeof(*filter), GFP_KERNEL);
+               KUNIT_ASSERT_NOT_ERR_OR_NULL(test, filter);
+
+               filter->size = hook_events[n].size;
+               filter->event = kunit_kzalloc(test, filter->size, GFP_KERNEL);
+               KUNIT_ASSERT_NOT_ERR_OR_NULL(test, filter->event);
+               memcpy(filter->event, &hook_events[n].event[0], filter->size);
+
+               list_add_tail(&filter->list, &p.event_hooks->list);
+       }
+
+       /* Test uclogic_exec_event_hook() */
+       for (n = 0; n < ARRAY_SIZE(test_events); n++) {
+               res = uclogic_exec_event_hook(&p, &test_events[n].event[0],
+                                             test_events[n].size);
+               KUNIT_ASSERT_EQ(test, res, test_events[n].expected);
+       }
+}
+
+static struct kunit_case hid_uclogic_core_test_cases[] = {
+       KUNIT_CASE(hid_test_uclogic_exec_event_hook_test),
+       {}
+};
+
+static struct kunit_suite hid_uclogic_core_test_suite = {
+       .name = "hid_uclogic_core_test",
+       .test_cases = hid_uclogic_core_test_cases,
+};
+
+kunit_test_suite(hid_uclogic_core_test_suite);
+
+MODULE_DESCRIPTION("KUnit tests for the UC-Logic driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("José Expósito <jose.exposito89@gmail.com>");
 
 }
 #endif
 
+/**
+ * uclogic_exec_event_hook - if the received event is hooked schedules the
+ * associated work.
+ *
+ * @p:         Tablet interface report parameters.
+ * @event:     Raw event.
+ * @size:      The size of event.
+ *
+ * Returns:
+ *     Whether the event was hooked or not.
+ */
+static bool uclogic_exec_event_hook(struct uclogic_params *p, u8 *event, int size)
+{
+       struct uclogic_raw_event_hook *curr;
+
+       if (!p->event_hooks)
+               return false;
+
+       list_for_each_entry(curr, &p->event_hooks->list, list) {
+               if (curr->size == size && memcmp(curr->event, event, size) == 0) {
+                       schedule_work(&curr->work);
+                       return true;
+               }
+       }
+
+       return false;
+}
+
 /**
  * uclogic_raw_event_pen - handle raw pen events (pen HID reports).
  *
        if (report->type != HID_INPUT_REPORT)
                return 0;
 
+       if (uclogic_exec_event_hook(params, data, size))
+               return 0;
+
        while (true) {
                /* Tweak pen reports, if necessary */
                if ((report_id == params->pen.id) && (size >= 2)) {
 MODULE_AUTHOR("Martin Rusko");
 MODULE_AUTHOR("Nikolai Kondrashov");
 MODULE_LICENSE("GPL");
+
+#ifdef CONFIG_HID_KUNIT_TEST
+#include "hid-uclogic-core-test.c"
+#endif
 
        KUNIT_EXPECT_EQ(test, params->frame_type, frame_type);
 }
 
+static void hid_test_uclogic_params_cleanup_event_hooks(struct kunit *test)
+{
+       int res, n;
+       struct uclogic_params p = {0, };
+
+       res = uclogic_params_ugee_v2_init_event_hooks(NULL, &p);
+       KUNIT_ASSERT_EQ(test, res, 0);
+
+       /* Check that the function can be called repeatedly */
+       for (n = 0; n < 4; n++) {
+               uclogic_params_cleanup_event_hooks(&p);
+               KUNIT_EXPECT_PTR_EQ(test, p.event_hooks, NULL);
+       }
+}
+
 static struct kunit_case hid_uclogic_params_test_cases[] = {
        KUNIT_CASE_PARAM(hid_test_uclogic_parse_ugee_v2_desc,
                         uclogic_parse_ugee_v2_desc_gen_params),
+       KUNIT_CASE(hid_test_uclogic_params_cleanup_event_hooks),
        {}
 };
 
 
        return rc;
 }
 
+/**
+ * uclogic_params_cleanup_event_hooks - free resources used by the list of raw
+ * event hooks.
+ * Can be called repeatedly.
+ *
+ * @params: Input parameters to cleanup. Cannot be NULL.
+ */
+static void uclogic_params_cleanup_event_hooks(struct uclogic_params *params)
+{
+       struct uclogic_raw_event_hook *curr, *n;
+
+       if (!params || !params->event_hooks)
+               return;
+
+       list_for_each_entry_safe(curr, n, ¶ms->event_hooks->list, list) {
+               cancel_work_sync(&curr->work);
+               list_del(&curr->list);
+               kfree(curr->event);
+               kfree(curr);
+       }
+
+       kfree(params->event_hooks);
+       params->event_hooks = NULL;
+}
+
 /**
  * uclogic_params_cleanup - free resources used by struct uclogic_params
  * (tablet interface's parameters).
                for (i = 0; i < ARRAY_SIZE(params->frame_list); i++)
                        uclogic_params_frame_cleanup(¶ms->frame_list[i]);
 
+               uclogic_params_cleanup_event_hooks(params);
                memset(params, 0, sizeof(*params));
        }
 }
        return rc;
 }
 
+/**
+ * uclogic_params_ugee_v2_reconnect_work() - When a wireless tablet looses
+ * connection to the USB dongle and reconnects, either because of its physical
+ * distance or because it was switches off and on using the frame's switch,
+ * uclogic_probe_interface() needs to be called again to enable the tablet.
+ *
+ * @work: The work that triggered this function.
+ */
+static void uclogic_params_ugee_v2_reconnect_work(struct work_struct *work)
+{
+       struct uclogic_raw_event_hook *event_hook;
+
+       event_hook = container_of(work, struct uclogic_raw_event_hook, work);
+       uclogic_probe_interface(event_hook->hdev, uclogic_ugee_v2_probe_arr,
+                               uclogic_ugee_v2_probe_size,
+                               uclogic_ugee_v2_probe_endpoint);
+}
+
+/**
+ * uclogic_params_ugee_v2_init_event_hooks() - initialize the list of events
+ * to be hooked for UGEE v2 devices.
+ * @hdev:      The HID device of the tablet interface to initialize and get
+ *             parameters from.
+ * @p:         Parameters to fill in, cannot be NULL.
+ *
+ * Returns:
+ *     Zero, if successful. A negative errno code on error.
+ */
+static int uclogic_params_ugee_v2_init_event_hooks(struct hid_device *hdev,
+                                                  struct uclogic_params *p)
+{
+       struct uclogic_raw_event_hook *event_hook;
+       __u8 reconnect_event[] = {
+               /* Event received on wireless tablet reconnection */
+               0x02, 0xF8, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+       };
+
+       if (!p)
+               return -EINVAL;
+
+       /* The reconnection event is only received if the tablet has battery */
+       if (!uclogic_params_ugee_v2_has_battery(hdev))
+               return 0;
+
+       p->event_hooks = kzalloc(sizeof(*p->event_hooks), GFP_KERNEL);
+       if (!p->event_hooks)
+               return -ENOMEM;
+
+       INIT_LIST_HEAD(&p->event_hooks->list);
+
+       event_hook = kzalloc(sizeof(*event_hook), GFP_KERNEL);
+       if (!event_hook)
+               return -ENOMEM;
+
+       INIT_WORK(&event_hook->work, uclogic_params_ugee_v2_reconnect_work);
+       event_hook->hdev = hdev;
+       event_hook->size = ARRAY_SIZE(reconnect_event);
+       event_hook->event = kmemdup(reconnect_event, event_hook->size, GFP_KERNEL);
+       if (!event_hook->event)
+               return -ENOMEM;
+
+       list_add_tail(&event_hook->list, &p->event_hooks->list);
+
+       return 0;
+}
+
 /**
  * uclogic_params_ugee_v2_init() - initialize a UGEE graphics tablets by
  * discovering their parameters.
                }
        }
 
+       /* Create a list of raw events to be ignored */
+       rc = uclogic_params_ugee_v2_init_event_hooks(hdev, &p);
+       if (rc) {
+               hid_err(hdev, "error initializing event hook list: %d\n", rc);
+               goto cleanup;
+       }
+
 output:
        /* Output parameters */
        memcpy(params, &p, sizeof(*params));
 
 
 #include <linux/usb.h>
 #include <linux/hid.h>
+#include <linux/list.h>
 
 #define UCLOGIC_MOUSE_FRAME_QUIRK      BIT(0)
 #define UCLOGIC_BATTERY_QUIRK          BIT(1)
        unsigned int bitmap_dial_byte;
 };
 
+/*
+ * List of works to be performed when a certain raw event is received.
+ */
+struct uclogic_raw_event_hook {
+       struct hid_device *hdev;
+       __u8 *event;
+       size_t size;
+       struct work_struct work;
+       struct list_head list;
+};
+
 /*
  * Tablet interface report parameters.
  *
         * parts. Only valid, if "invalid" is false.
         */
        struct uclogic_params_frame frame_list[3];
+       /*
+        * List of event hooks.
+        */
+       struct uclogic_raw_event_hook *event_hooks;
 };
 
 /* Driver data */