Commit b146dbbd authored by Jiri Kosina's avatar Jiri Kosina

Merge branch 'for-5.18/uclogic' into for-linus

- integration of first part of DIGImend [1] patches in order to vastly
  improve Linux support of tablets (Nikolai Kondrashov, José Expósito)

[1] https://github.com/DIGImend/digimend-kernel-drivers
parents bda3c85a 337fa051
...@@ -614,7 +614,7 @@ ...@@ -614,7 +614,7 @@
#define USB_VENDOR_ID_HUION 0x256c #define USB_VENDOR_ID_HUION 0x256c
#define USB_DEVICE_ID_HUION_TABLET 0x006e #define USB_DEVICE_ID_HUION_TABLET 0x006e
#define USB_DEVICE_ID_HUION_HS64 0x006d #define USB_DEVICE_ID_HUION_TABLET2 0x006d
#define USB_VENDOR_ID_IBM 0x04b3 #define USB_VENDOR_ID_IBM 0x04b3
#define USB_DEVICE_ID_IBM_SCROLLPOINT_III 0x3100 #define USB_DEVICE_ID_IBM_SCROLLPOINT_III 0x3100
......
...@@ -81,24 +81,6 @@ static __u8 *uclogic_report_fixup(struct hid_device *hdev, __u8 *rdesc, ...@@ -81,24 +81,6 @@ static __u8 *uclogic_report_fixup(struct hid_device *hdev, __u8 *rdesc,
return rdesc; return rdesc;
} }
static int uclogic_input_mapping(struct hid_device *hdev,
struct hid_input *hi,
struct hid_field *field,
struct hid_usage *usage,
unsigned long **bit,
int *max)
{
struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev);
struct uclogic_params *params = &drvdata->params;
/* discard the unused pen interface */
if (params->pen_unused && (field->application == HID_DG_PEN))
return -1;
/* let hid-core decide what to do */
return 0;
}
static int uclogic_input_configured(struct hid_device *hdev, static int uclogic_input_configured(struct hid_device *hdev,
struct hid_input *hi) struct hid_input *hi)
{ {
...@@ -246,100 +228,171 @@ static int uclogic_resume(struct hid_device *hdev) ...@@ -246,100 +228,171 @@ static int uclogic_resume(struct hid_device *hdev)
} }
#endif #endif
/**
* uclogic_raw_event_pen - handle raw pen events (pen HID reports).
*
* @drvdata: Driver data.
* @data: Report data buffer, can be modified.
* @size: Report data size, bytes.
*
* Returns:
* Negative value on error (stops event delivery), zero for success.
*/
static int uclogic_raw_event_pen(struct uclogic_drvdata *drvdata,
u8 *data, int size)
{
struct uclogic_params_pen *pen = &drvdata->params.pen;
WARN_ON(drvdata == NULL);
WARN_ON(data == NULL && size != 0);
/* If in-range reports are inverted */
if (pen->inrange ==
UCLOGIC_PARAMS_PEN_INRANGE_INVERTED) {
/* Invert the in-range bit */
data[1] ^= 0x40;
}
/*
* If report contains fragmented high-resolution pen
* coordinates
*/
if (size >= 10 && pen->fragmented_hires) {
u8 pressure_low_byte;
u8 pressure_high_byte;
/* Lift pressure bytes */
pressure_low_byte = data[6];
pressure_high_byte = data[7];
/*
* Move Y coord to make space for high-order X
* coord byte
*/
data[6] = data[5];
data[5] = data[4];
/* Move high-order X coord byte */
data[4] = data[8];
/* Move high-order Y coord byte */
data[7] = data[9];
/* Place pressure bytes */
data[8] = pressure_low_byte;
data[9] = pressure_high_byte;
}
/* If we need to emulate in-range detection */
if (pen->inrange == UCLOGIC_PARAMS_PEN_INRANGE_NONE) {
/* Set in-range bit */
data[1] |= 0x40;
/* (Re-)start in-range timeout */
mod_timer(&drvdata->inrange_timer,
jiffies + msecs_to_jiffies(100));
}
/* If we report tilt and Y direction is flipped */
if (size >= 12 && pen->tilt_y_flipped)
data[11] = -data[11];
return 0;
}
/**
* uclogic_raw_event_frame - handle raw frame events (frame HID reports).
*
* @drvdata: Driver data.
* @frame: The parameters of the frame controls to handle.
* @data: Report data buffer, can be modified.
* @size: Report data size, bytes.
*
* Returns:
* Negative value on error (stops event delivery), zero for success.
*/
static int uclogic_raw_event_frame(
struct uclogic_drvdata *drvdata,
const struct uclogic_params_frame *frame,
u8 *data, int size)
{
WARN_ON(drvdata == NULL);
WARN_ON(data == NULL && size != 0);
/* If need to, and can, set pad device ID for Wacom drivers */
if (frame->dev_id_byte > 0 && frame->dev_id_byte < size) {
data[frame->dev_id_byte] = 0xf;
}
/* If need to, and can, read rotary encoder state change */
if (frame->re_lsb > 0 && frame->re_lsb / 8 < size) {
unsigned int byte = frame->re_lsb / 8;
unsigned int bit = frame->re_lsb % 8;
u8 change;
u8 prev_state = drvdata->re_state;
/* Read Gray-coded state */
u8 state = (data[byte] >> bit) & 0x3;
/* Encode state change into 2-bit signed integer */
if ((prev_state == 1 && state == 0) ||
(prev_state == 2 && state == 3)) {
change = 1;
} else if ((prev_state == 2 && state == 0) ||
(prev_state == 1 && state == 3)) {
change = 3;
} else {
change = 0;
}
/* Write change */
data[byte] = (data[byte] & ~((u8)3 << bit)) |
(change << bit);
/* Remember state */
drvdata->re_state = state;
}
return 0;
}
static int uclogic_raw_event(struct hid_device *hdev, static int uclogic_raw_event(struct hid_device *hdev,
struct hid_report *report, struct hid_report *report,
u8 *data, int size) u8 *data, int size)
{ {
unsigned int report_id = report->id;
struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev); struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev);
struct uclogic_params *params = &drvdata->params; struct uclogic_params *params = &drvdata->params;
struct uclogic_params_pen_subreport *subreport;
struct uclogic_params_pen_subreport *subreport_list_end;
size_t i;
/* Tweak pen reports, if necessary */ /* Do not handle anything but input reports */
if (!params->pen_unused && if (report->type != HID_INPUT_REPORT)
(report->type == HID_INPUT_REPORT) && return 0;
(report->id == params->pen.id) &&
(size >= 2)) {
/* If it's the "virtual" frame controls report */
if (params->frame.id != 0 &&
data[1] & params->pen_frame_flag) {
/* Change to virtual frame controls report ID */
data[0] = params->frame.id;
return 0;
}
/* If in-range reports are inverted */
if (params->pen.inrange ==
UCLOGIC_PARAMS_PEN_INRANGE_INVERTED) {
/* Invert the in-range bit */
data[1] ^= 0x40;
}
/*
* If report contains fragmented high-resolution pen
* coordinates
*/
if (size >= 10 && params->pen.fragmented_hires) {
u8 pressure_low_byte;
u8 pressure_high_byte;
/* Lift pressure bytes */
pressure_low_byte = data[6];
pressure_high_byte = data[7];
/*
* Move Y coord to make space for high-order X
* coord byte
*/
data[6] = data[5];
data[5] = data[4];
/* Move high-order X coord byte */
data[4] = data[8];
/* Move high-order Y coord byte */
data[7] = data[9];
/* Place pressure bytes */
data[8] = pressure_low_byte;
data[9] = pressure_high_byte;
}
/* If we need to emulate in-range detection */
if (params->pen.inrange == UCLOGIC_PARAMS_PEN_INRANGE_NONE) {
/* Set in-range bit */
data[1] |= 0x40;
/* (Re-)start in-range timeout */
mod_timer(&drvdata->inrange_timer,
jiffies + msecs_to_jiffies(100));
}
}
/* Tweak frame control reports, if necessary */ while (true) {
if ((report->type == HID_INPUT_REPORT) && /* Tweak pen reports, if necessary */
(report->id == params->frame.id)) { if ((report_id == params->pen.id) && (size >= 2)) {
/* If need to, and can, set pad device ID for Wacom drivers */ subreport_list_end =
if (params->frame.dev_id_byte > 0 && params->pen.subreport_list +
params->frame.dev_id_byte < size) { ARRAY_SIZE(params->pen.subreport_list);
data[params->frame.dev_id_byte] = 0xf; /* Try to match a subreport */
} for (subreport = params->pen.subreport_list;
/* If need to, and can, read rotary encoder state change */ subreport < subreport_list_end; subreport++) {
if (params->frame.re_lsb > 0 && if (subreport->value != 0 &&
params->frame.re_lsb / 8 < size) { subreport->value == data[1]) {
unsigned int byte = params->frame.re_lsb / 8; break;
unsigned int bit = params->frame.re_lsb % 8; }
}
u8 change; /* If a subreport matched */
u8 prev_state = drvdata->re_state; if (subreport < subreport_list_end) {
/* Read Gray-coded state */ /* Change to subreport ID, and restart */
u8 state = (data[byte] >> bit) & 0x3; report_id = data[0] = subreport->id;
/* Encode state change into 2-bit signed integer */ continue;
if ((prev_state == 1 && state == 0) ||
(prev_state == 2 && state == 3)) {
change = 1;
} else if ((prev_state == 2 && state == 0) ||
(prev_state == 1 && state == 3)) {
change = 3;
} else { } else {
change = 0; return uclogic_raw_event_pen(drvdata, data, size);
}
}
/* Tweak frame control reports, if necessary */
for (i = 0; i < ARRAY_SIZE(params->frame_list); i++) {
if (report_id == params->frame_list[i].id) {
return uclogic_raw_event_frame(
drvdata, &params->frame_list[i],
data, size);
} }
/* Write change */
data[byte] = (data[byte] & ~((u8)3 << bit)) |
(change << bit);
/* Remember state */
drvdata->re_state = state;
} }
break;
} }
return 0; return 0;
...@@ -373,7 +426,7 @@ static const struct hid_device_id uclogic_devices[] = { ...@@ -373,7 +426,7 @@ static const struct hid_device_id uclogic_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_HUION, { HID_USB_DEVICE(USB_VENDOR_ID_HUION,
USB_DEVICE_ID_HUION_TABLET) }, USB_DEVICE_ID_HUION_TABLET) },
{ HID_USB_DEVICE(USB_VENDOR_ID_HUION, { HID_USB_DEVICE(USB_VENDOR_ID_HUION,
USB_DEVICE_ID_HUION_HS64) }, USB_DEVICE_ID_HUION_TABLET2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_TRUST, { HID_USB_DEVICE(USB_VENDOR_ID_TRUST,
USB_DEVICE_ID_TRUST_PANORA_TABLET) }, USB_DEVICE_ID_TRUST_PANORA_TABLET) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
...@@ -415,7 +468,6 @@ static struct hid_driver uclogic_driver = { ...@@ -415,7 +468,6 @@ static struct hid_driver uclogic_driver = {
.remove = uclogic_remove, .remove = uclogic_remove,
.report_fixup = uclogic_report_fixup, .report_fixup = uclogic_report_fixup,
.raw_event = uclogic_raw_event, .raw_event = uclogic_raw_event,
.input_mapping = uclogic_input_mapping,
.input_configured = uclogic_input_configured, .input_configured = uclogic_input_configured,
#ifdef CONFIG_PM #ifdef CONFIG_PM
.resume = uclogic_resume, .resume = uclogic_resume,
......
...@@ -207,8 +207,8 @@ static int uclogic_params_pen_init_v1(struct uclogic_params_pen *pen, ...@@ -207,8 +207,8 @@ static int uclogic_params_pen_init_v1(struct uclogic_params_pen *pen,
* Generate pen report descriptor * Generate pen report descriptor
*/ */
desc_ptr = uclogic_rdesc_template_apply( desc_ptr = uclogic_rdesc_template_apply(
uclogic_rdesc_pen_v1_template_arr, uclogic_rdesc_v1_pen_template_arr,
uclogic_rdesc_pen_v1_template_size, uclogic_rdesc_v1_pen_template_size,
desc_params, ARRAY_SIZE(desc_params)); desc_params, ARRAY_SIZE(desc_params));
if (desc_ptr == NULL) { if (desc_ptr == NULL) {
rc = -ENOMEM; rc = -ENOMEM;
...@@ -221,8 +221,8 @@ static int uclogic_params_pen_init_v1(struct uclogic_params_pen *pen, ...@@ -221,8 +221,8 @@ static int uclogic_params_pen_init_v1(struct uclogic_params_pen *pen,
memset(pen, 0, sizeof(*pen)); memset(pen, 0, sizeof(*pen));
pen->desc_ptr = desc_ptr; pen->desc_ptr = desc_ptr;
desc_ptr = NULL; desc_ptr = NULL;
pen->desc_size = uclogic_rdesc_pen_v1_template_size; pen->desc_size = uclogic_rdesc_v1_pen_template_size;
pen->id = UCLOGIC_RDESC_PEN_V1_ID; pen->id = UCLOGIC_RDESC_V1_PEN_ID;
pen->inrange = UCLOGIC_PARAMS_PEN_INRANGE_INVERTED; pen->inrange = UCLOGIC_PARAMS_PEN_INRANGE_INVERTED;
found = true; found = true;
finish: finish:
...@@ -351,8 +351,8 @@ static int uclogic_params_pen_init_v2(struct uclogic_params_pen *pen, ...@@ -351,8 +351,8 @@ static int uclogic_params_pen_init_v2(struct uclogic_params_pen *pen,
* Generate pen report descriptor * Generate pen report descriptor
*/ */
desc_ptr = uclogic_rdesc_template_apply( desc_ptr = uclogic_rdesc_template_apply(
uclogic_rdesc_pen_v2_template_arr, uclogic_rdesc_v2_pen_template_arr,
uclogic_rdesc_pen_v2_template_size, uclogic_rdesc_v2_pen_template_size,
desc_params, ARRAY_SIZE(desc_params)); desc_params, ARRAY_SIZE(desc_params));
if (desc_ptr == NULL) { if (desc_ptr == NULL) {
rc = -ENOMEM; rc = -ENOMEM;
...@@ -365,10 +365,11 @@ static int uclogic_params_pen_init_v2(struct uclogic_params_pen *pen, ...@@ -365,10 +365,11 @@ static int uclogic_params_pen_init_v2(struct uclogic_params_pen *pen,
memset(pen, 0, sizeof(*pen)); memset(pen, 0, sizeof(*pen));
pen->desc_ptr = desc_ptr; pen->desc_ptr = desc_ptr;
desc_ptr = NULL; desc_ptr = NULL;
pen->desc_size = uclogic_rdesc_pen_v2_template_size; pen->desc_size = uclogic_rdesc_v2_pen_template_size;
pen->id = UCLOGIC_RDESC_PEN_V2_ID; pen->id = UCLOGIC_RDESC_V2_PEN_ID;
pen->inrange = UCLOGIC_PARAMS_PEN_INRANGE_NONE; pen->inrange = UCLOGIC_PARAMS_PEN_INRANGE_NONE;
pen->fragmented_hires = true; pen->fragmented_hires = true;
pen->tilt_y_flipped = true;
found = true; found = true;
finish: finish:
*pfound = found; *pfound = found;
...@@ -430,8 +431,8 @@ static int uclogic_params_frame_init_with_desc( ...@@ -430,8 +431,8 @@ static int uclogic_params_frame_init_with_desc(
} }
/** /**
* uclogic_params_frame_init_v1_buttonpad() - initialize abstract buttonpad * uclogic_params_frame_init_v1() - initialize v1 tablet interface frame
* on a v1 tablet interface. * controls.
* *
* @frame: Pointer to the frame parameters to initialize (to be cleaned * @frame: Pointer to the frame parameters to initialize (to be cleaned
* up with uclogic_params_frame_cleanup()). Not modified in case * up with uclogic_params_frame_cleanup()). Not modified in case
...@@ -445,8 +446,7 @@ static int uclogic_params_frame_init_with_desc( ...@@ -445,8 +446,7 @@ static int uclogic_params_frame_init_with_desc(
* Returns: * Returns:
* Zero, if successful. A negative errno code on error. * Zero, if successful. A negative errno code on error.
*/ */
static int uclogic_params_frame_init_v1_buttonpad( static int uclogic_params_frame_init_v1(struct uclogic_params_frame *frame,
struct uclogic_params_frame *frame,
bool *pfound, bool *pfound,
struct hid_device *hdev) struct hid_device *hdev)
{ {
...@@ -487,9 +487,9 @@ static int uclogic_params_frame_init_v1_buttonpad( ...@@ -487,9 +487,9 @@ static int uclogic_params_frame_init_v1_buttonpad(
hid_dbg(hdev, "generic buttons enabled\n"); hid_dbg(hdev, "generic buttons enabled\n");
rc = uclogic_params_frame_init_with_desc( rc = uclogic_params_frame_init_with_desc(
frame, frame,
uclogic_rdesc_buttonpad_v1_arr, uclogic_rdesc_v1_frame_arr,
uclogic_rdesc_buttonpad_v1_size, uclogic_rdesc_v1_frame_size,
UCLOGIC_RDESC_BUTTONPAD_V1_ID); UCLOGIC_RDESC_V1_FRAME_ID);
if (rc != 0) if (rc != 0)
goto cleanup; goto cleanup;
found = true; found = true;
...@@ -512,10 +512,12 @@ static int uclogic_params_frame_init_v1_buttonpad( ...@@ -512,10 +512,12 @@ static int uclogic_params_frame_init_v1_buttonpad(
void uclogic_params_cleanup(struct uclogic_params *params) void uclogic_params_cleanup(struct uclogic_params *params)
{ {
if (!params->invalid) { if (!params->invalid) {
size_t i;
kfree(params->desc_ptr); kfree(params->desc_ptr);
if (!params->pen_unused) uclogic_params_pen_cleanup(&params->pen);
uclogic_params_pen_cleanup(&params->pen); for (i = 0; i < ARRAY_SIZE(params->frame_list); i++)
uclogic_params_frame_cleanup(&params->frame); uclogic_params_frame_cleanup(&params->frame_list[i]);
memset(params, 0, sizeof(*params)); memset(params, 0, sizeof(*params));
} }
} }
...@@ -543,60 +545,53 @@ int uclogic_params_get_desc(const struct uclogic_params *params, ...@@ -543,60 +545,53 @@ int uclogic_params_get_desc(const struct uclogic_params *params,
__u8 **pdesc, __u8 **pdesc,
unsigned int *psize) unsigned int *psize)
{ {
bool common_present; int rc = -ENOMEM;
bool pen_present; bool present = false;
bool frame_present; unsigned int size = 0;
unsigned int size;
__u8 *desc = NULL; __u8 *desc = NULL;
size_t i;
/* Check arguments */ /* Check arguments */
if (params == NULL || pdesc == NULL || psize == NULL) if (params == NULL || pdesc == NULL || psize == NULL)
return -EINVAL; return -EINVAL;
size = 0; /* Concatenate descriptors */
#define ADD_DESC(_desc_ptr, _desc_size) \
common_present = (params->desc_ptr != NULL); do { \
pen_present = (!params->pen_unused && params->pen.desc_ptr != NULL); unsigned int new_size; \
frame_present = (params->frame.desc_ptr != NULL); __u8 *new_desc; \
if ((_desc_ptr) == NULL) { \
if (common_present) break; \
size += params->desc_size; } \
if (pen_present) new_size = size + (_desc_size); \
size += params->pen.desc_size; new_desc = krealloc(desc, new_size, GFP_KERNEL); \
if (frame_present) if (new_desc == NULL) { \
size += params->frame.desc_size; goto cleanup; \
} \
if (common_present || pen_present || frame_present) { memcpy(new_desc + size, (_desc_ptr), (_desc_size)); \
__u8 *p; desc = new_desc; \
size = new_size; \
desc = kmalloc(size, GFP_KERNEL); present = true; \
if (desc == NULL) } while (0)
return -ENOMEM;
p = desc; ADD_DESC(params->desc_ptr, params->desc_size);
ADD_DESC(params->pen.desc_ptr, params->pen.desc_size);
if (common_present) { for (i = 0; i < ARRAY_SIZE(params->frame_list); i++) {
memcpy(p, params->desc_ptr, ADD_DESC(params->frame_list[i].desc_ptr,
params->desc_size); params->frame_list[i].desc_size);
p += params->desc_size; }
}
if (pen_present) {
memcpy(p, params->pen.desc_ptr,
params->pen.desc_size);
p += params->pen.desc_size;
}
if (frame_present) {
memcpy(p, params->frame.desc_ptr,
params->frame.desc_size);
p += params->frame.desc_size;
}
WARN_ON(p != desc + size); #undef ADD_DESC
if (present) {
*pdesc = desc;
*psize = size; *psize = size;
desc = NULL;
} }
rc = 0;
*pdesc = desc; cleanup:
return 0; kfree(desc);
return rc;
} }
/** /**
...@@ -679,21 +674,6 @@ static int uclogic_params_init_with_opt_desc(struct uclogic_params *params, ...@@ -679,21 +674,6 @@ static int uclogic_params_init_with_opt_desc(struct uclogic_params *params,
return rc; return rc;
} }
/**
* uclogic_params_init_with_pen_unused() - initialize tablet interface
* parameters preserving original reports and generic HID processing, but
* disabling pen usage.
*
* @params: Parameters to initialize (to be cleaned with
* uclogic_params_cleanup()). Not modified in case of
* error. Cannot be NULL.
*/
static void uclogic_params_init_with_pen_unused(struct uclogic_params *params)
{
memset(params, 0, sizeof(*params));
params->pen_unused = true;
}
/** /**
* uclogic_params_huion_init() - initialize a Huion tablet interface and discover * uclogic_params_huion_init() - initialize a Huion tablet interface and discover
* its parameters. * its parameters.
...@@ -733,8 +713,7 @@ static int uclogic_params_huion_init(struct uclogic_params *params, ...@@ -733,8 +713,7 @@ static int uclogic_params_huion_init(struct uclogic_params *params,
/* If it's not a pen interface */ /* If it's not a pen interface */
if (bInterfaceNumber != 0) { if (bInterfaceNumber != 0) {
/* TODO: Consider marking the interface invalid */ uclogic_params_init_invalid(&p);
uclogic_params_init_with_pen_unused(&p);
goto output; goto output;
} }
...@@ -766,20 +745,22 @@ static int uclogic_params_huion_init(struct uclogic_params *params, ...@@ -766,20 +745,22 @@ static int uclogic_params_huion_init(struct uclogic_params *params,
goto cleanup; goto cleanup;
} else if (found) { } else if (found) {
hid_dbg(hdev, "pen v2 parameters found\n"); hid_dbg(hdev, "pen v2 parameters found\n");
/* Create v2 buttonpad parameters */ /* Create v2 frame parameters */
rc = uclogic_params_frame_init_with_desc( rc = uclogic_params_frame_init_with_desc(
&p.frame, &p.frame_list[0],
uclogic_rdesc_buttonpad_v2_arr, uclogic_rdesc_v2_frame_arr,
uclogic_rdesc_buttonpad_v2_size, uclogic_rdesc_v2_frame_size,
UCLOGIC_RDESC_BUTTONPAD_V2_ID); UCLOGIC_RDESC_V2_FRAME_ID);
if (rc != 0) { if (rc != 0) {
hid_err(hdev, hid_err(hdev,
"failed creating v2 buttonpad parameters: %d\n", "failed creating v2 frame parameters: %d\n",
rc); rc);
goto cleanup; goto cleanup;
} }
/* Set bitmask marking frame reports in pen reports */ /* Link frame button subreports from pen reports */
p.pen_frame_flag = 0x20; p.pen.subreport_list[0].value = 0xe0;
p.pen.subreport_list[0].id =
UCLOGIC_RDESC_V2_FRAME_ID;
goto output; goto output;
} }
hid_dbg(hdev, "pen v2 parameters not found\n"); hid_dbg(hdev, "pen v2 parameters not found\n");
...@@ -793,19 +774,20 @@ static int uclogic_params_huion_init(struct uclogic_params *params, ...@@ -793,19 +774,20 @@ static int uclogic_params_huion_init(struct uclogic_params *params,
goto cleanup; goto cleanup;
} else if (found) { } else if (found) {
hid_dbg(hdev, "pen v1 parameters found\n"); hid_dbg(hdev, "pen v1 parameters found\n");
/* Try to probe v1 buttonpad */ /* Try to probe v1 frame */
rc = uclogic_params_frame_init_v1_buttonpad( rc = uclogic_params_frame_init_v1(&p.frame_list[0],
&p.frame, &found, hdev);
&found, hdev);
if (rc != 0) { if (rc != 0) {
hid_err(hdev, "v1 buttonpad probing failed: %d\n", rc); hid_err(hdev, "v1 frame probing failed: %d\n", rc);
goto cleanup; goto cleanup;
} }
hid_dbg(hdev, "buttonpad v1 parameters%s found\n", hid_dbg(hdev, "frame v1 parameters%s found\n",
(found ? "" : " not")); (found ? "" : " not"));
if (found) { if (found) {
/* Set bitmask marking frame reports */ /* Link frame button subreports from pen reports */
p.pen_frame_flag = 0x20; p.pen.subreport_list[0].value = 0xe0;
p.pen.subreport_list[0].id =
UCLOGIC_RDESC_V1_FRAME_ID;
} }
goto output; goto output;
} }
...@@ -992,7 +974,7 @@ int uclogic_params_init(struct uclogic_params *params, ...@@ -992,7 +974,7 @@ int uclogic_params_init(struct uclogic_params *params,
case VID_PID(USB_VENDOR_ID_HUION, case VID_PID(USB_VENDOR_ID_HUION,
USB_DEVICE_ID_HUION_TABLET): USB_DEVICE_ID_HUION_TABLET):
case VID_PID(USB_VENDOR_ID_HUION, case VID_PID(USB_VENDOR_ID_HUION,
USB_DEVICE_ID_HUION_HS64): USB_DEVICE_ID_HUION_TABLET2):
case VID_PID(USB_VENDOR_ID_UCLOGIC, case VID_PID(USB_VENDOR_ID_UCLOGIC,
USB_DEVICE_ID_HUION_TABLET): USB_DEVICE_ID_HUION_TABLET):
case VID_PID(USB_VENDOR_ID_UCLOGIC, case VID_PID(USB_VENDOR_ID_UCLOGIC,
...@@ -1032,8 +1014,7 @@ int uclogic_params_init(struct uclogic_params *params, ...@@ -1032,8 +1014,7 @@ int uclogic_params_init(struct uclogic_params *params,
uclogic_params_init_invalid(&p); uclogic_params_init_invalid(&p);
} }
} else { } else {
/* TODO: Consider marking the interface invalid */ uclogic_params_init_invalid(&p);
uclogic_params_init_with_pen_unused(&p);
} }
break; break;
case VID_PID(USB_VENDOR_ID_UGEE, case VID_PID(USB_VENDOR_ID_UGEE,
...@@ -1048,15 +1029,14 @@ int uclogic_params_init(struct uclogic_params *params, ...@@ -1048,15 +1029,14 @@ int uclogic_params_init(struct uclogic_params *params,
} }
/* Initialize frame parameters */ /* Initialize frame parameters */
rc = uclogic_params_frame_init_with_desc( rc = uclogic_params_frame_init_with_desc(
&p.frame, &p.frame_list[0],
uclogic_rdesc_xppen_deco01_frame_arr, uclogic_rdesc_xppen_deco01_frame_arr,
uclogic_rdesc_xppen_deco01_frame_size, uclogic_rdesc_xppen_deco01_frame_size,
0); 0);
if (rc != 0) if (rc != 0)
goto cleanup; goto cleanup;
} else { } else {
/* TODO: Consider marking the interface invalid */ uclogic_params_init_invalid(&p);
uclogic_params_init_with_pen_unused(&p);
} }
break; break;
case VID_PID(USB_VENDOR_ID_TRUST, case VID_PID(USB_VENDOR_ID_TRUST,
...@@ -1075,19 +1055,19 @@ int uclogic_params_init(struct uclogic_params *params, ...@@ -1075,19 +1055,19 @@ int uclogic_params_init(struct uclogic_params *params,
goto cleanup; goto cleanup;
} else if (found) { } else if (found) {
rc = uclogic_params_frame_init_with_desc( rc = uclogic_params_frame_init_with_desc(
&p.frame, &p.frame_list[0],
uclogic_rdesc_ugee_g5_frame_arr, uclogic_rdesc_ugee_g5_frame_arr,
uclogic_rdesc_ugee_g5_frame_size, uclogic_rdesc_ugee_g5_frame_size,
UCLOGIC_RDESC_UGEE_G5_FRAME_ID); UCLOGIC_RDESC_UGEE_G5_FRAME_ID);
if (rc != 0) { if (rc != 0) {
hid_err(hdev, hid_err(hdev,
"failed creating buttonpad parameters: %d\n", "failed creating frame parameters: %d\n",
rc); rc);
goto cleanup; goto cleanup;
} }
p.frame.re_lsb = p.frame_list[0].re_lsb =
UCLOGIC_RDESC_UGEE_G5_FRAME_RE_LSB; UCLOGIC_RDESC_UGEE_G5_FRAME_RE_LSB;
p.frame.dev_id_byte = p.frame_list[0].dev_id_byte =
UCLOGIC_RDESC_UGEE_G5_FRAME_DEV_ID_BYTE; UCLOGIC_RDESC_UGEE_G5_FRAME_DEV_ID_BYTE;
} else { } else {
hid_warn(hdev, "pen parameters not found"); hid_warn(hdev, "pen parameters not found");
...@@ -1109,13 +1089,13 @@ int uclogic_params_init(struct uclogic_params *params, ...@@ -1109,13 +1089,13 @@ int uclogic_params_init(struct uclogic_params *params,
goto cleanup; goto cleanup;
} else if (found) { } else if (found) {
rc = uclogic_params_frame_init_with_desc( rc = uclogic_params_frame_init_with_desc(
&p.frame, &p.frame_list[0],
uclogic_rdesc_ugee_ex07_buttonpad_arr, uclogic_rdesc_ugee_ex07_frame_arr,
uclogic_rdesc_ugee_ex07_buttonpad_size, uclogic_rdesc_ugee_ex07_frame_size,
0); 0);
if (rc != 0) { if (rc != 0) {
hid_err(hdev, hid_err(hdev,
"failed creating buttonpad parameters: %d\n", "failed creating frame parameters: %d\n",
rc); rc);
goto cleanup; goto cleanup;
} }
......
...@@ -33,6 +33,25 @@ enum uclogic_params_pen_inrange { ...@@ -33,6 +33,25 @@ enum uclogic_params_pen_inrange {
extern const char *uclogic_params_pen_inrange_to_str( extern const char *uclogic_params_pen_inrange_to_str(
enum uclogic_params_pen_inrange inrange); enum uclogic_params_pen_inrange inrange);
/*
* Pen report's subreport data.
*/
struct uclogic_params_pen_subreport {
/*
* The value of the second byte of the pen report indicating this
* subreport. If zero, the subreport should be considered invalid and
* not matched.
*/
__u8 value;
/*
* The ID to be assigned to the report, if the second byte of the pen
* report is equal to "value". Only valid if "value" is not zero.
*/
__u8 id;
};
/* /*
* Tablet interface's pen input parameters. * Tablet interface's pen input parameters.
* *
...@@ -54,6 +73,8 @@ struct uclogic_params_pen { ...@@ -54,6 +73,8 @@ struct uclogic_params_pen {
unsigned int desc_size; unsigned int desc_size;
/* Report ID, if reports should be tweaked, zero if not */ /* Report ID, if reports should be tweaked, zero if not */
unsigned int id; unsigned int id;
/* The list of subreports */
struct uclogic_params_pen_subreport subreport_list[1];
/* Type of in-range reporting, only valid if "id" is not zero */ /* Type of in-range reporting, only valid if "id" is not zero */
enum uclogic_params_pen_inrange inrange; enum uclogic_params_pen_inrange inrange;
/* /*
...@@ -62,6 +83,12 @@ struct uclogic_params_pen { ...@@ -62,6 +83,12 @@ struct uclogic_params_pen {
* Only valid if "id" is not zero. * Only valid if "id" is not zero.
*/ */
bool fragmented_hires; bool fragmented_hires;
/*
* True if the pen reports tilt in bytes at offset 10 (X) and 11 (Y),
* and the Y tilt direction is flipped.
* Only valid if "id" is not zero.
*/
bool tilt_y_flipped;
}; };
/* /*
...@@ -132,28 +159,16 @@ struct uclogic_params { ...@@ -132,28 +159,16 @@ struct uclogic_params {
* Only valid, if "desc_ptr" is not NULL. * Only valid, if "desc_ptr" is not NULL.
*/ */
unsigned int desc_size; unsigned int desc_size;
/*
* True, if pen usage in report descriptor is invalid, when present.
* Only valid, if "invalid" is false.
*/
bool pen_unused;
/* /*
* Pen parameters and optional report descriptor part. * Pen parameters and optional report descriptor part.
* Only valid if "pen_unused" is valid and false.
*/
struct uclogic_params_pen pen;
/*
* Frame control parameters and optional report descriptor part.
* Only valid, if "invalid" is false. * Only valid, if "invalid" is false.
*/ */
struct uclogic_params_frame frame; struct uclogic_params_pen pen;
/* /*
* Bitmask matching frame controls "sub-report" flag in the second * The list of frame control parameters and optional report descriptor
* byte of the pen report, or zero if it's not expected. * parts. Only valid, if "invalid" is false.
* Only valid if both "pen" and "frame" are valid, and "frame.id" is
* not zero.
*/ */
__u8 pen_frame_flag; struct uclogic_params_frame frame_list[1];
}; };
/* Initialize a tablet interface and discover its parameters */ /* Initialize a tablet interface and discover its parameters */
...@@ -162,39 +177,40 @@ extern int uclogic_params_init(struct uclogic_params *params, ...@@ -162,39 +177,40 @@ extern int uclogic_params_init(struct uclogic_params *params,
/* Tablet interface parameters *printf format string */ /* Tablet interface parameters *printf format string */
#define UCLOGIC_PARAMS_FMT_STR \ #define UCLOGIC_PARAMS_FMT_STR \
".invalid = %s\n" \ ".invalid = %s\n" \
".desc_ptr = %p\n" \ ".desc_ptr = %p\n" \
".desc_size = %u\n" \ ".desc_size = %u\n" \
".pen_unused = %s\n" \ ".pen.desc_ptr = %p\n" \
".pen.desc_ptr = %p\n" \ ".pen.desc_size = %u\n" \
".pen.desc_size = %u\n" \ ".pen.id = %u\n" \
".pen.id = %u\n" \ ".pen.subreport_list[0] = {0x%02hhx, %hhu}\n" \
".pen.inrange = %s\n" \ ".pen.inrange = %s\n" \
".pen.fragmented_hires = %s\n" \ ".pen.fragmented_hires = %s\n" \
".frame.desc_ptr = %p\n" \ ".pen.tilt_y_flipped = %s\n" \
".frame.desc_size = %u\n" \ ".frame_list[0].desc_ptr = %p\n" \
".frame.id = %u\n" \ ".frame_list[0].desc_size = %u\n" \
".frame.re_lsb = %u\n" \ ".frame_list[0].id = %u\n" \
".frame.dev_id_byte = %u\n" \ ".frame_list[0].re_lsb = %u\n" \
".pen_frame_flag = 0x%02x\n" ".frame_list[0].dev_id_byte = %u\n"
/* Tablet interface parameters *printf format arguments */ /* Tablet interface parameters *printf format arguments */
#define UCLOGIC_PARAMS_FMT_ARGS(_params) \ #define UCLOGIC_PARAMS_FMT_ARGS(_params) \
((_params)->invalid ? "true" : "false"), \ ((_params)->invalid ? "true" : "false"), \
(_params)->desc_ptr, \ (_params)->desc_ptr, \
(_params)->desc_size, \ (_params)->desc_size, \
((_params)->pen_unused ? "true" : "false"), \
(_params)->pen.desc_ptr, \ (_params)->pen.desc_ptr, \
(_params)->pen.desc_size, \ (_params)->pen.desc_size, \
(_params)->pen.id, \ (_params)->pen.id, \
(_params)->pen.subreport_list[0].value, \
(_params)->pen.subreport_list[0].id, \
uclogic_params_pen_inrange_to_str((_params)->pen.inrange), \ uclogic_params_pen_inrange_to_str((_params)->pen.inrange), \
((_params)->pen.fragmented_hires ? "true" : "false"), \ ((_params)->pen.fragmented_hires ? "true" : "false"), \
(_params)->frame.desc_ptr, \ ((_params)->pen.tilt_y_flipped ? "true" : "false"), \
(_params)->frame.desc_size, \ (_params)->frame_list[0].desc_ptr, \
(_params)->frame.id, \ (_params)->frame_list[0].desc_size, \
(_params)->frame.re_lsb, \ (_params)->frame_list[0].id, \
(_params)->frame.dev_id_byte, \ (_params)->frame_list[0].re_lsb, \
(_params)->pen_frame_flag (_params)->frame_list[0].dev_id_byte
/* Get a replacement report descriptor for a tablet's interface. */ /* Get a replacement report descriptor for a tablet's interface. */
extern int uclogic_params_get_desc(const struct uclogic_params *params, extern int uclogic_params_get_desc(const struct uclogic_params *params,
......
...@@ -532,7 +532,7 @@ const size_t uclogic_rdesc_twha60_fixed1_size = ...@@ -532,7 +532,7 @@ const size_t uclogic_rdesc_twha60_fixed1_size =
sizeof(uclogic_rdesc_twha60_fixed1_arr); sizeof(uclogic_rdesc_twha60_fixed1_arr);
/* Fixed report descriptor template for (tweaked) v1 pen reports */ /* Fixed report descriptor template for (tweaked) v1 pen reports */
const __u8 uclogic_rdesc_pen_v1_template_arr[] = { const __u8 uclogic_rdesc_v1_pen_template_arr[] = {
0x05, 0x0D, /* Usage Page (Digitizer), */ 0x05, 0x0D, /* Usage Page (Digitizer), */
0x09, 0x02, /* Usage (Pen), */ 0x09, 0x02, /* Usage (Pen), */
0xA1, 0x01, /* Collection (Application), */ 0xA1, 0x01, /* Collection (Application), */
...@@ -582,11 +582,11 @@ const __u8 uclogic_rdesc_pen_v1_template_arr[] = { ...@@ -582,11 +582,11 @@ const __u8 uclogic_rdesc_pen_v1_template_arr[] = {
0xC0 /* End Collection */ 0xC0 /* End Collection */
}; };
const size_t uclogic_rdesc_pen_v1_template_size = const size_t uclogic_rdesc_v1_pen_template_size =
sizeof(uclogic_rdesc_pen_v1_template_arr); sizeof(uclogic_rdesc_v1_pen_template_arr);
/* Fixed report descriptor template for (tweaked) v2 pen reports */ /* Fixed report descriptor template for (tweaked) v2 pen reports */
const __u8 uclogic_rdesc_pen_v2_template_arr[] = { const __u8 uclogic_rdesc_v2_pen_template_arr[] = {
0x05, 0x0D, /* Usage Page (Digitizer), */ 0x05, 0x0D, /* Usage Page (Digitizer), */
0x09, 0x02, /* Usage (Pen), */ 0x09, 0x02, /* Usage (Pen), */
0xA1, 0x01, /* Collection (Application), */ 0xA1, 0x01, /* Collection (Application), */
...@@ -633,25 +633,35 @@ const __u8 uclogic_rdesc_pen_v2_template_arr[] = { ...@@ -633,25 +633,35 @@ const __u8 uclogic_rdesc_pen_v2_template_arr[] = {
0x27, UCLOGIC_RDESC_PEN_PH(PRESSURE_LM), 0x27, UCLOGIC_RDESC_PEN_PH(PRESSURE_LM),
/* Logical Maximum (PLACEHOLDER), */ /* Logical Maximum (PLACEHOLDER), */
0x81, 0x02, /* Input (Variable), */ 0x81, 0x02, /* Input (Variable), */
0x81, 0x03, /* Input (Constant, Variable), */ 0x54, /* Unit Exponent (0), */
0x65, 0x14, /* Unit (Degrees), */
0x35, 0xC4, /* Physical Minimum (-60), */
0x45, 0x3C, /* Physical Maximum (60), */
0x15, 0xC4, /* Logical Minimum (-60), */
0x25, 0x3C, /* Logical Maximum (60), */
0x75, 0x08, /* Report Size (8), */
0x95, 0x02, /* Report Count (2), */
0x09, 0x3D, /* Usage (X Tilt), */
0x09, 0x3E, /* Usage (Y Tilt), */
0x81, 0x02, /* Input (Variable), */
0xC0, /* End Collection, */ 0xC0, /* End Collection, */
0xC0 /* End Collection */ 0xC0 /* End Collection */
}; };
const size_t uclogic_rdesc_pen_v2_template_size = const size_t uclogic_rdesc_v2_pen_template_size =
sizeof(uclogic_rdesc_pen_v2_template_arr); sizeof(uclogic_rdesc_v2_pen_template_arr);
/* /*
* Expand to the contents of a generic buttonpad report descriptor. * Expand to the contents of a generic frame report descriptor.
* *
* @_padding: Padding from the end of button bits at bit 44, until * @_id: The report ID to use.
* the end of the report, in bits. * @_size: Size of the report to pad to, including report ID, bytes.
*/ */
#define UCLOGIC_RDESC_BUTTONPAD_BYTES(_padding) \ #define UCLOGIC_RDESC_FRAME_BYTES(_id, _size) \
0x05, 0x01, /* Usage Page (Desktop), */ \ 0x05, 0x01, /* Usage Page (Desktop), */ \
0x09, 0x07, /* Usage (Keypad), */ \ 0x09, 0x07, /* Usage (Keypad), */ \
0xA1, 0x01, /* Collection (Application), */ \ 0xA1, 0x01, /* Collection (Application), */ \
0x85, 0xF7, /* Report ID (247), */ \ 0x85, (_id), /* Report ID (_id), */ \
0x14, /* Logical Minimum (0), */ \ 0x14, /* Logical Minimum (0), */ \
0x25, 0x01, /* Logical Maximum (1), */ \ 0x25, 0x01, /* Logical Maximum (1), */ \
0x75, 0x01, /* Report Size (1), */ \ 0x75, 0x01, /* Report Size (1), */ \
...@@ -679,30 +689,31 @@ const size_t uclogic_rdesc_pen_v2_template_size = ...@@ -679,30 +689,31 @@ const size_t uclogic_rdesc_pen_v2_template_size =
0xA0, /* Collection (Physical), */ \ 0xA0, /* Collection (Physical), */ \
0x05, 0x09, /* Usage Page (Button), */ \ 0x05, 0x09, /* Usage Page (Button), */ \
0x19, 0x01, /* Usage Minimum (01h), */ \ 0x19, 0x01, /* Usage Minimum (01h), */ \
0x29, 0x02, /* Usage Maximum (02h), */ \ 0x29, 0x03, /* Usage Maximum (03h), */ \
0x95, 0x02, /* Report Count (2), */ \ 0x95, 0x03, /* Report Count (3), */ \
0x81, 0x02, /* Input (Variable), */ \ 0x81, 0x02, /* Input (Variable), */ \
0x95, _padding, /* Report Count (_padding), */ \ 0x95, ((_size) * 8 - 45), \
/* Report Count (padding), */ \
0x81, 0x01, /* Input (Constant), */ \ 0x81, 0x01, /* Input (Constant), */ \
0xC0, /* End Collection, */ \ 0xC0, /* End Collection, */ \
0xC0 /* End Collection */ 0xC0 /* End Collection */
/* Fixed report descriptor for (tweaked) v1 buttonpad reports */ /* Fixed report descriptor for (tweaked) v1 frame reports */
const __u8 uclogic_rdesc_buttonpad_v1_arr[] = { const __u8 uclogic_rdesc_v1_frame_arr[] = {
UCLOGIC_RDESC_BUTTONPAD_BYTES(20) UCLOGIC_RDESC_FRAME_BYTES(UCLOGIC_RDESC_V1_FRAME_ID, 8)
}; };
const size_t uclogic_rdesc_buttonpad_v1_size = const size_t uclogic_rdesc_v1_frame_size =
sizeof(uclogic_rdesc_buttonpad_v1_arr); sizeof(uclogic_rdesc_v1_frame_arr);
/* Fixed report descriptor for (tweaked) v2 buttonpad reports */ /* Fixed report descriptor for (tweaked) v2 frame reports */
const __u8 uclogic_rdesc_buttonpad_v2_arr[] = { const __u8 uclogic_rdesc_v2_frame_arr[] = {
UCLOGIC_RDESC_BUTTONPAD_BYTES(52) UCLOGIC_RDESC_FRAME_BYTES(UCLOGIC_RDESC_V2_FRAME_ID, 12)
}; };
const size_t uclogic_rdesc_buttonpad_v2_size = const size_t uclogic_rdesc_v2_frame_size =
sizeof(uclogic_rdesc_buttonpad_v2_arr); sizeof(uclogic_rdesc_v2_frame_arr);
/* Fixed report descriptor for Ugee EX07 buttonpad */ /* Fixed report descriptor for Ugee EX07 frame */
const __u8 uclogic_rdesc_ugee_ex07_buttonpad_arr[] = { const __u8 uclogic_rdesc_ugee_ex07_frame_arr[] = {
0x05, 0x01, /* Usage Page (Desktop), */ 0x05, 0x01, /* Usage Page (Desktop), */
0x09, 0x07, /* Usage (Keypad), */ 0x09, 0x07, /* Usage (Keypad), */
0xA1, 0x01, /* Collection (Application), */ 0xA1, 0x01, /* Collection (Application), */
...@@ -725,8 +736,8 @@ const __u8 uclogic_rdesc_ugee_ex07_buttonpad_arr[] = { ...@@ -725,8 +736,8 @@ const __u8 uclogic_rdesc_ugee_ex07_buttonpad_arr[] = {
0xC0, /* End Collection, */ 0xC0, /* End Collection, */
0xC0 /* End Collection */ 0xC0 /* End Collection */
}; };
const size_t uclogic_rdesc_ugee_ex07_buttonpad_size = const size_t uclogic_rdesc_ugee_ex07_frame_size =
sizeof(uclogic_rdesc_ugee_ex07_buttonpad_arr); sizeof(uclogic_rdesc_ugee_ex07_frame_arr);
/* Fixed report descriptor for Ugee G5 frame controls */ /* Fixed report descriptor for Ugee G5 frame controls */
const __u8 uclogic_rdesc_ugee_g5_frame_arr[] = { const __u8 uclogic_rdesc_ugee_g5_frame_arr[] = {
......
...@@ -104,36 +104,36 @@ enum uclogic_rdesc_pen_ph_id { ...@@ -104,36 +104,36 @@ enum uclogic_rdesc_pen_ph_id {
UCLOGIC_RDESC_PH_HEAD, UCLOGIC_RDESC_PEN_PH_ID_##_ID UCLOGIC_RDESC_PH_HEAD, UCLOGIC_RDESC_PEN_PH_ID_##_ID
/* Report ID for v1 pen reports */ /* Report ID for v1 pen reports */
#define UCLOGIC_RDESC_PEN_V1_ID 0x07 #define UCLOGIC_RDESC_V1_PEN_ID 0x07
/* Fixed report descriptor template for (tweaked) v1 pen reports */ /* Fixed report descriptor template for (tweaked) v1 pen reports */
extern const __u8 uclogic_rdesc_pen_v1_template_arr[]; extern const __u8 uclogic_rdesc_v1_pen_template_arr[];
extern const size_t uclogic_rdesc_pen_v1_template_size; extern const size_t uclogic_rdesc_v1_pen_template_size;
/* Report ID for v2 pen reports */ /* Report ID for v2 pen reports */
#define UCLOGIC_RDESC_PEN_V2_ID 0x08 #define UCLOGIC_RDESC_V2_PEN_ID 0x08
/* Fixed report descriptor template for (tweaked) v2 pen reports */ /* Fixed report descriptor template for (tweaked) v2 pen reports */
extern const __u8 uclogic_rdesc_pen_v2_template_arr[]; extern const __u8 uclogic_rdesc_v2_pen_template_arr[];
extern const size_t uclogic_rdesc_pen_v2_template_size; extern const size_t uclogic_rdesc_v2_pen_template_size;
/* Fixed report descriptor for (tweaked) v1 buttonpad reports */ /* Report ID for tweaked v1 frame reports */
extern const __u8 uclogic_rdesc_buttonpad_v1_arr[]; #define UCLOGIC_RDESC_V1_FRAME_ID 0xf7
extern const size_t uclogic_rdesc_buttonpad_v1_size;
/* Report ID for tweaked v1 buttonpad reports */ /* Fixed report descriptor for (tweaked) v1 frame reports */
#define UCLOGIC_RDESC_BUTTONPAD_V1_ID 0xf7 extern const __u8 uclogic_rdesc_v1_frame_arr[];
extern const size_t uclogic_rdesc_v1_frame_size;
/* Fixed report descriptor for (tweaked) v2 buttonpad reports */ /* Report ID for tweaked v2 frame reports */
extern const __u8 uclogic_rdesc_buttonpad_v2_arr[]; #define UCLOGIC_RDESC_V2_FRAME_ID 0xf7
extern const size_t uclogic_rdesc_buttonpad_v2_size;
/* Report ID for tweaked v2 buttonpad reports */ /* Fixed report descriptor for (tweaked) v2 frame reports */
#define UCLOGIC_RDESC_BUTTONPAD_V2_ID 0xf7 extern const __u8 uclogic_rdesc_v2_frame_arr[];
extern const size_t uclogic_rdesc_v2_frame_size;
/* Fixed report descriptor for Ugee EX07 buttonpad */ /* Fixed report descriptor for Ugee EX07 frame */
extern const __u8 uclogic_rdesc_ugee_ex07_buttonpad_arr[]; extern const __u8 uclogic_rdesc_ugee_ex07_frame_arr[];
extern const size_t uclogic_rdesc_ugee_ex07_buttonpad_size; extern const size_t uclogic_rdesc_ugee_ex07_frame_size;
/* Fixed report descriptor for XP-Pen Deco 01 frame controls */ /* Fixed report descriptor for XP-Pen Deco 01 frame controls */
extern const __u8 uclogic_rdesc_xppen_deco01_frame_arr[]; extern const __u8 uclogic_rdesc_xppen_deco01_frame_arr[];
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment