Skip to content

Commit 9671854

Browse files
redstrateJiri Kosina
authored andcommitted
HID: uclogic: Add support for XP-PEN Artist 22R Pro
Adds support for the XP-PEN Artist 22R Pro, including stylus, tablet frame and pen pressure. The tablet has 20 buttons, but need to be remapped in order since the device reports invalid keycodes. Existing tablet functionality should not be inhibited, as BTN0-8 is still used. New initialization functions are added since the device differs slightly from other UGEE v2 devices. Signed-off-by: Joshua Goins <[email protected]> Signed-off-by: Jiri Kosina <[email protected]>
1 parent c8be000 commit 9671854

File tree

6 files changed

+248
-4
lines changed

6 files changed

+248
-4
lines changed

drivers/hid/hid-ids.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1402,6 +1402,7 @@
14021402
#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_S 0x0909
14031403
#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_SW 0x0933
14041404
#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_STAR06 0x0078
1405+
#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_22R_PRO 0x091b
14051406
#define USB_DEVICE_ID_UGEE_TABLET_G5 0x0074
14061407
#define USB_DEVICE_ID_UGEE_TABLET_EX07S 0x0071
14071408
#define USB_DEVICE_ID_UGEE_TABLET_RAINBOW_CV720 0x0055

drivers/hid/hid-uclogic-core.c

Lines changed: 62 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,30 @@ static const __u8 *uclogic_report_fixup(struct hid_device *hdev, __u8 *rdesc,
6262
return rdesc;
6363
}
6464

65+
/* Buttons considered valid tablet pad inputs. */
66+
static const unsigned int uclogic_extra_input_mapping[] = {
67+
BTN_0,
68+
BTN_1,
69+
BTN_2,
70+
BTN_3,
71+
BTN_4,
72+
BTN_5,
73+
BTN_6,
74+
BTN_7,
75+
BTN_8,
76+
BTN_RIGHT,
77+
BTN_MIDDLE,
78+
BTN_SIDE,
79+
BTN_EXTRA,
80+
BTN_FORWARD,
81+
BTN_BACK,
82+
BTN_B,
83+
BTN_A,
84+
BTN_BASE,
85+
BTN_BASE2,
86+
BTN_X
87+
};
88+
6589
static int uclogic_input_mapping(struct hid_device *hdev,
6690
struct hid_input *hi,
6791
struct hid_field *field,
@@ -72,9 +96,27 @@ static int uclogic_input_mapping(struct hid_device *hdev,
7296
struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev);
7397
struct uclogic_params *params = &drvdata->params;
7498

75-
/* Discard invalid pen usages */
76-
if (params->pen.usage_invalid && (field->application == HID_DG_PEN))
77-
return -1;
99+
if (field->application == HID_GD_KEYPAD) {
100+
/*
101+
* Remap input buttons to sensible ones that are not invalid.
102+
* This only affects previous behavior for devices with more than ten or so buttons.
103+
*/
104+
const int key = (usage->hid & HID_USAGE) - 1;
105+
106+
if (key < ARRAY_SIZE(uclogic_extra_input_mapping)) {
107+
hid_map_usage(hi,
108+
usage,
109+
bit,
110+
max,
111+
EV_KEY,
112+
uclogic_extra_input_mapping[key]);
113+
return 1;
114+
}
115+
} else if (field->application == HID_DG_PEN) {
116+
/* Discard invalid pen usages */
117+
if (params->pen.usage_invalid)
118+
return -1;
119+
}
78120

79121
/* Let hid-core decide what to do */
80122
return 0;
@@ -407,8 +449,22 @@ static int uclogic_raw_event_frame(
407449

408450
/* If need to, and can, transform the bitmap dial reports */
409451
if (frame->bitmap_dial_byte > 0 && frame->bitmap_dial_byte < size) {
410-
if (data[frame->bitmap_dial_byte] == 2)
452+
switch (data[frame->bitmap_dial_byte]) {
453+
case 2:
411454
data[frame->bitmap_dial_byte] = -1;
455+
break;
456+
457+
/* Everything below here is for tablets that shove multiple dials into 1 byte */
458+
case 16:
459+
data[frame->bitmap_dial_byte] = 0;
460+
data[frame->bitmap_second_dial_destination_byte] = 1;
461+
break;
462+
463+
case 32:
464+
data[frame->bitmap_dial_byte] = 0;
465+
data[frame->bitmap_second_dial_destination_byte] = -1;
466+
break;
467+
}
412468
}
413469

414470
return 0;
@@ -546,6 +602,8 @@ static const struct hid_device_id uclogic_devices[] = {
546602
.driver_data = UCLOGIC_MOUSE_FRAME_QUIRK | UCLOGIC_BATTERY_QUIRK },
547603
{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
548604
USB_DEVICE_ID_UGEE_XPPEN_TABLET_STAR06) },
605+
{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
606+
USB_DEVICE_ID_UGEE_XPPEN_TABLET_22R_PRO) },
549607
{ }
550608
};
551609
MODULE_DEVICE_TABLE(hid, uclogic_devices);

drivers/hid/hid-uclogic-params.c

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,8 @@ static void uclogic_params_frame_hid_dbg(
103103
frame->touch_flip_at);
104104
hid_dbg(hdev, "\t\t.bitmap_dial_byte = %u\n",
105105
frame->bitmap_dial_byte);
106+
hid_dbg(hdev, "\t\t.bitmap_second_dial_destination_byte = %u\n",
107+
frame->bitmap_second_dial_destination_byte);
106108
}
107109

108110
/**
@@ -1529,6 +1531,126 @@ static int uclogic_params_ugee_v2_init(struct uclogic_params *params,
15291531
return rc;
15301532
}
15311533

1534+
/*
1535+
* uclogic_params_init_ugee_xppen_pro_22r() - Initializes a UGEE XP-Pen Pro 22R tablet device.
1536+
*
1537+
* @hdev: The HID device of the tablet interface to initialize and get
1538+
* parameters from. Cannot be NULL.
1539+
* @params: Parameters to fill in (to be cleaned with
1540+
* uclogic_params_cleanup()). Not modified in case of error.
1541+
* Cannot be NULL.
1542+
*
1543+
* Returns:
1544+
* Zero, if successful. A negative errno code on error.
1545+
*/
1546+
static int uclogic_params_init_ugee_xppen_pro_22r(struct uclogic_params *params,
1547+
struct hid_device *hdev,
1548+
const u8 rdesc_frame_arr[],
1549+
const size_t rdesc_frame_size)
1550+
{
1551+
int rc = 0;
1552+
struct usb_interface *iface;
1553+
__u8 bInterfaceNumber;
1554+
const int str_desc_len = 12;
1555+
u8 *str_desc = NULL;
1556+
__u8 *rdesc_pen = NULL;
1557+
s32 desc_params[UCLOGIC_RDESC_PH_ID_NUM];
1558+
enum uclogic_params_frame_type frame_type;
1559+
/* The resulting parameters (noop) */
1560+
struct uclogic_params p = {0, };
1561+
1562+
if (!hdev || !params) {
1563+
rc = -EINVAL;
1564+
goto cleanup;
1565+
}
1566+
1567+
iface = to_usb_interface(hdev->dev.parent);
1568+
bInterfaceNumber = iface->cur_altsetting->desc.bInterfaceNumber;
1569+
1570+
/* Ignore non-pen interfaces */
1571+
if (bInterfaceNumber != 2) {
1572+
rc = -EINVAL;
1573+
uclogic_params_init_invalid(&p);
1574+
goto cleanup;
1575+
}
1576+
1577+
/*
1578+
* Initialize the interface by sending magic data.
1579+
* This magic data is the same as other UGEE v2 tablets.
1580+
*/
1581+
rc = uclogic_probe_interface(hdev,
1582+
uclogic_ugee_v2_probe_arr,
1583+
uclogic_ugee_v2_probe_size,
1584+
uclogic_ugee_v2_probe_endpoint);
1585+
if (rc) {
1586+
uclogic_params_init_invalid(&p);
1587+
goto cleanup;
1588+
}
1589+
1590+
/**
1591+
* Read the string descriptor containing pen and frame parameters.
1592+
* These are slightly different than typical UGEE v2 devices.
1593+
*/
1594+
rc = uclogic_params_get_str_desc(&str_desc, hdev, 100, str_desc_len);
1595+
if (rc != str_desc_len) {
1596+
rc = (rc < 0) ? rc : -EINVAL;
1597+
hid_err(hdev, "failed retrieving pen and frame parameters: %d\n", rc);
1598+
uclogic_params_init_invalid(&p);
1599+
goto cleanup;
1600+
}
1601+
1602+
rc = uclogic_params_parse_ugee_v2_desc(str_desc, str_desc_len,
1603+
desc_params,
1604+
ARRAY_SIZE(desc_params),
1605+
&frame_type);
1606+
if (rc)
1607+
goto cleanup;
1608+
1609+
// str_desc doesn't report the correct amount of buttons, so manually fix it
1610+
desc_params[UCLOGIC_RDESC_FRAME_PH_ID_UM] = 20;
1611+
1612+
kfree(str_desc);
1613+
str_desc = NULL;
1614+
1615+
/* Initialize the pen interface */
1616+
rdesc_pen = uclogic_rdesc_template_apply(
1617+
uclogic_rdesc_ugee_v2_pen_template_arr,
1618+
uclogic_rdesc_ugee_v2_pen_template_size,
1619+
desc_params, ARRAY_SIZE(desc_params));
1620+
if (!rdesc_pen) {
1621+
rc = -ENOMEM;
1622+
goto cleanup;
1623+
}
1624+
1625+
p.pen.desc_ptr = rdesc_pen;
1626+
p.pen.desc_size = uclogic_rdesc_ugee_v2_pen_template_size;
1627+
p.pen.id = 0x02;
1628+
p.pen.subreport_list[0].value = 0xf0;
1629+
p.pen.subreport_list[0].id = UCLOGIC_RDESC_V1_FRAME_ID;
1630+
1631+
/* Initialize the frame interface */
1632+
rc = uclogic_params_frame_init_with_desc(
1633+
&p.frame_list[0],
1634+
rdesc_frame_arr,
1635+
rdesc_frame_size,
1636+
UCLOGIC_RDESC_V1_FRAME_ID);
1637+
if (rc < 0) {
1638+
hid_err(hdev, "initializing frame params failed: %d\n", rc);
1639+
goto cleanup;
1640+
}
1641+
1642+
p.frame_list[0].bitmap_dial_byte = 7;
1643+
p.frame_list[0].bitmap_second_dial_destination_byte = 8;
1644+
1645+
/* Output parameters */
1646+
memcpy(params, &p, sizeof(*params));
1647+
memset(&p, 0, sizeof(p));
1648+
cleanup:
1649+
kfree(str_desc);
1650+
uclogic_params_cleanup(&p);
1651+
return rc;
1652+
}
1653+
15321654
/**
15331655
* uclogic_params_init() - initialize a tablet interface and discover its
15341656
* parameters.
@@ -1845,6 +1967,16 @@ int uclogic_params_init(struct uclogic_params *params,
18451967
uclogic_params_init_invalid(&p);
18461968
}
18471969

1970+
break;
1971+
case VID_PID(USB_VENDOR_ID_UGEE,
1972+
USB_DEVICE_ID_UGEE_XPPEN_TABLET_22R_PRO):
1973+
rc = uclogic_params_init_ugee_xppen_pro_22r(&p,
1974+
hdev,
1975+
uclogic_rdesc_xppen_artist_22r_pro_frame_arr,
1976+
uclogic_rdesc_xppen_artist_22r_pro_frame_size);
1977+
if (rc != 0)
1978+
goto cleanup;
1979+
18481980
break;
18491981
}
18501982

drivers/hid/hid-uclogic-params.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,11 @@ struct uclogic_params_frame {
175175
* counterclockwise, as opposed to the normal 1 and -1.
176176
*/
177177
unsigned int bitmap_dial_byte;
178+
/*
179+
* Destination offset for the second bitmap dial byte, if the tablet
180+
* supports a second dial at all.
181+
*/
182+
unsigned int bitmap_second_dial_destination_byte;
178183
};
179184

180185
/*

drivers/hid/hid-uclogic-rdesc.c

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1193,6 +1193,50 @@ const __u8 uclogic_rdesc_xppen_deco01_frame_arr[] = {
11931193
const size_t uclogic_rdesc_xppen_deco01_frame_size =
11941194
sizeof(uclogic_rdesc_xppen_deco01_frame_arr);
11951195

1196+
/* Fixed report descriptor for XP-Pen Arist 22R Pro frame */
1197+
const __u8 uclogic_rdesc_xppen_artist_22r_pro_frame_arr[] = {
1198+
0x05, 0x01, /* Usage Page (Desktop), */
1199+
0x09, 0x07, /* Usage (Keypad), */
1200+
0xA1, 0x01, /* Collection (Application), */
1201+
0x85, UCLOGIC_RDESC_V1_FRAME_ID,
1202+
/* Report ID (Virtual report), */
1203+
0x05, 0x0D, /* Usage Page (Digitizer), */
1204+
0x09, 0x39, /* Usage (Tablet Function Keys), */
1205+
0xA0, /* Collection (Physical), */
1206+
0x14, /* Logical Minimum (0), */
1207+
0x25, 0x01, /* Logical Maximum (1), */
1208+
0x75, 0x01, /* Report Size (1), */
1209+
0x95, 0x08, /* Report Count (8), */
1210+
0x81, 0x01, /* Input (Constant), */
1211+
0x05, 0x09, /* Usage Page (Button), */
1212+
0x19, 0x01, /* Usage Minimum (01h), */
1213+
0x29, 0x14, /* Usage Maximum (14h), */
1214+
0x95, 0x14, /* Report Count (20), */
1215+
0x81, 0x02, /* Input (Variable), */
1216+
0x95, 0x14, /* Report Count (20), */
1217+
0x81, 0x01, /* Input (Constant), */
1218+
0x05, 0x01, /* Usage Page (Desktop), */
1219+
0x09, 0x38, /* Usage (Wheel), */
1220+
0x75, 0x08, /* Report Size (8), */
1221+
0x95, 0x01, /* Report Count (1), */
1222+
0x15, 0xFF, /* Logical Minimum (-1), */
1223+
0x25, 0x08, /* Logical Maximum (8), */
1224+
0x81, 0x06, /* Input (Variable, Relative), */
1225+
0x05, 0x0C, /* Usage Page (Consumer Devices), */
1226+
0x0A, 0x38, 0x02, /* Usage (AC PAN), */
1227+
0x95, 0x01, /* Report Count (1), */
1228+
0x81, 0x06, /* Input (Variable, Relative), */
1229+
0x26, 0xFF, 0x00, /* Logical Maximum (255), */
1230+
0x75, 0x08, /* Report Size (8), */
1231+
0x95, 0x01, /* Report Count (1), */
1232+
0x81, 0x02, /* Input (Variable), */
1233+
0xC0, /* End Collection */
1234+
0xC0, /* End Collection */
1235+
};
1236+
1237+
const size_t uclogic_rdesc_xppen_artist_22r_pro_frame_size =
1238+
sizeof(uclogic_rdesc_xppen_artist_22r_pro_frame_arr);
1239+
11961240
/**
11971241
* uclogic_rdesc_template_apply() - apply report descriptor parameters to a
11981242
* report descriptor template, creating a report descriptor. Copies the

drivers/hid/hid-uclogic-rdesc.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,4 +210,8 @@ extern const size_t uclogic_rdesc_ugee_g5_frame_size;
210210
/* Least-significant bit of Ugee G5 frame rotary encoder state */
211211
#define UCLOGIC_RDESC_UGEE_G5_FRAME_RE_LSB 38
212212

213+
/* Fixed report descriptor for XP-Pen Arist 22R Pro frame */
214+
extern const __u8 uclogic_rdesc_xppen_artist_22r_pro_frame_arr[];
215+
extern const size_t uclogic_rdesc_xppen_artist_22r_pro_frame_size;
216+
213217
#endif /* _HID_UCLOGIC_RDESC_H */

0 commit comments

Comments
 (0)