aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hid/hid-uclogic-core.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/hid/hid-uclogic-core.c')
-rw-r--r--drivers/hid/hid-uclogic-core.c258
1 files changed, 155 insertions, 103 deletions
diff --git a/drivers/hid/hid-uclogic-core.c b/drivers/hid/hid-uclogic-core.c
index d8ab0139e5cd..05147f2d7564 100644
--- a/drivers/hid/hid-uclogic-core.c
+++ b/drivers/hid/hid-uclogic-core.c
@@ -81,24 +81,6 @@ static __u8 *uclogic_report_fixup(struct hid_device *hdev, __u8 *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,
struct hid_input *hi)
{
@@ -246,100 +228,171 @@ static int uclogic_resume(struct hid_device *hdev)
}
#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,
struct hid_report *report,
u8 *data, int size)
{
+ unsigned int report_id = report->id;
struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev);
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 */
- if (!params->pen_unused &&
- (report->type == HID_INPUT_REPORT) &&
- (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));
- }
- }
+ /* Do not handle anything but input reports */
+ if (report->type != HID_INPUT_REPORT)
+ return 0;
- /* Tweak frame control reports, if necessary */
- if ((report->type == HID_INPUT_REPORT) &&
- (report->id == params->frame.id)) {
- /* If need to, and can, set pad device ID for Wacom drivers */
- if (params->frame.dev_id_byte > 0 &&
- params->frame.dev_id_byte < size) {
- data[params->frame.dev_id_byte] = 0xf;
- }
- /* If need to, and can, read rotary encoder state change */
- if (params->frame.re_lsb > 0 &&
- params->frame.re_lsb / 8 < size) {
- unsigned int byte = params->frame.re_lsb / 8;
- unsigned int bit = params->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;
+ while (true) {
+ /* Tweak pen reports, if necessary */
+ if ((report_id == params->pen.id) && (size >= 2)) {
+ subreport_list_end =
+ params->pen.subreport_list +
+ ARRAY_SIZE(params->pen.subreport_list);
+ /* Try to match a subreport */
+ for (subreport = params->pen.subreport_list;
+ subreport < subreport_list_end; subreport++) {
+ if (subreport->value != 0 &&
+ subreport->value == data[1]) {
+ break;
+ }
+ }
+ /* If a subreport matched */
+ if (subreport < subreport_list_end) {
+ /* Change to subreport ID, and restart */
+ report_id = data[0] = subreport->id;
+ continue;
} 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;
@@ -373,7 +426,7 @@ static const struct hid_device_id uclogic_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_HUION,
USB_DEVICE_ID_HUION_TABLET) },
{ HID_USB_DEVICE(USB_VENDOR_ID_HUION,
- USB_DEVICE_ID_HUION_HS64) },
+ USB_DEVICE_ID_HUION_TABLET2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_TRUST,
USB_DEVICE_ID_TRUST_PANORA_TABLET) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
@@ -415,7 +468,6 @@ static struct hid_driver uclogic_driver = {
.remove = uclogic_remove,
.report_fixup = uclogic_report_fixup,
.raw_event = uclogic_raw_event,
- .input_mapping = uclogic_input_mapping,
.input_configured = uclogic_input_configured,
#ifdef CONFIG_PM
.resume = uclogic_resume,