Skip to content

Commit c62f87e

Browse files
author
Jiri Kosina
committed
Merge branch 'for-6.17/uclogic' into for-linus
- support for XP-PEN Artist 22R Pro (Joshua Goins)
2 parents ddb7a62 + 9671854 commit c62f87e

File tree

6 files changed

+249
-5
lines changed

6 files changed

+249
-5
lines changed

drivers/hid/hid-ids.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1409,6 +1409,7 @@
14091409
#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_S 0x0909
14101410
#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_SW 0x0933
14111411
#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_STAR06 0x0078
1412+
#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_22R_PRO 0x091b
14121413
#define USB_DEVICE_ID_UGEE_TABLET_G5 0x0074
14131414
#define USB_DEVICE_ID_UGEE_TABLET_EX07S 0x0071
14141415
#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: 133 additions & 1 deletion
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
/**
@@ -1341,7 +1343,7 @@ static int uclogic_params_ugee_v2_init_event_hooks(struct hid_device *hdev,
13411343
struct uclogic_params *p)
13421344
{
13431345
struct uclogic_raw_event_hook *event_hook;
1344-
__u8 reconnect_event[] = {
1346+
static const __u8 reconnect_event[] = {
13451347
/* Event received on wireless tablet reconnection */
13461348
0x02, 0xF8, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
13471349
};
@@ -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)