0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016 #include "hid-uclogic-params.h"
0017 #include "hid-uclogic-rdesc.h"
0018 #include "usbhid/usbhid.h"
0019 #include "hid-ids.h"
0020 #include <linux/ctype.h>
0021 #include <asm/unaligned.h>
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032 static const char *uclogic_params_pen_inrange_to_str(
0033 enum uclogic_params_pen_inrange inrange)
0034 {
0035 switch (inrange) {
0036 case UCLOGIC_PARAMS_PEN_INRANGE_NORMAL:
0037 return "normal";
0038 case UCLOGIC_PARAMS_PEN_INRANGE_INVERTED:
0039 return "inverted";
0040 case UCLOGIC_PARAMS_PEN_INRANGE_NONE:
0041 return "none";
0042 default:
0043 return NULL;
0044 }
0045 }
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055 static void uclogic_params_pen_hid_dbg(const struct hid_device *hdev,
0056 const struct uclogic_params_pen *pen)
0057 {
0058 size_t i;
0059
0060 hid_dbg(hdev, "\t.usage_invalid = %s\n",
0061 (pen->usage_invalid ? "true" : "false"));
0062 hid_dbg(hdev, "\t.desc_ptr = %p\n", pen->desc_ptr);
0063 hid_dbg(hdev, "\t.desc_size = %u\n", pen->desc_size);
0064 hid_dbg(hdev, "\t.id = %u\n", pen->id);
0065 hid_dbg(hdev, "\t.subreport_list = {\n");
0066 for (i = 0; i < ARRAY_SIZE(pen->subreport_list); i++) {
0067 hid_dbg(hdev, "\t\t{0x%02hhx, %hhu}%s\n",
0068 pen->subreport_list[i].value,
0069 pen->subreport_list[i].id,
0070 i < (ARRAY_SIZE(pen->subreport_list) - 1) ? "," : "");
0071 }
0072 hid_dbg(hdev, "\t}\n");
0073 hid_dbg(hdev, "\t.inrange = %s\n",
0074 uclogic_params_pen_inrange_to_str(pen->inrange));
0075 hid_dbg(hdev, "\t.fragmented_hires = %s\n",
0076 (pen->fragmented_hires ? "true" : "false"));
0077 hid_dbg(hdev, "\t.tilt_y_flipped = %s\n",
0078 (pen->tilt_y_flipped ? "true" : "false"));
0079 }
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089 static void uclogic_params_frame_hid_dbg(
0090 const struct hid_device *hdev,
0091 const struct uclogic_params_frame *frame)
0092 {
0093 hid_dbg(hdev, "\t\t.desc_ptr = %p\n", frame->desc_ptr);
0094 hid_dbg(hdev, "\t\t.desc_size = %u\n", frame->desc_size);
0095 hid_dbg(hdev, "\t\t.id = %u\n", frame->id);
0096 hid_dbg(hdev, "\t\t.suffix = %s\n", frame->suffix);
0097 hid_dbg(hdev, "\t\t.re_lsb = %u\n", frame->re_lsb);
0098 hid_dbg(hdev, "\t\t.dev_id_byte = %u\n", frame->dev_id_byte);
0099 hid_dbg(hdev, "\t\t.touch_byte = %u\n", frame->touch_byte);
0100 hid_dbg(hdev, "\t\t.touch_max = %hhd\n", frame->touch_max);
0101 hid_dbg(hdev, "\t\t.touch_flip_at = %hhd\n",
0102 frame->touch_flip_at);
0103 hid_dbg(hdev, "\t\t.bitmap_dial_byte = %u\n",
0104 frame->bitmap_dial_byte);
0105 }
0106
0107
0108
0109
0110
0111
0112
0113
0114 void uclogic_params_hid_dbg(const struct hid_device *hdev,
0115 const struct uclogic_params *params)
0116 {
0117 size_t i;
0118
0119 hid_dbg(hdev, ".invalid = %s\n",
0120 params->invalid ? "true" : "false");
0121 hid_dbg(hdev, ".desc_ptr = %p\n", params->desc_ptr);
0122 hid_dbg(hdev, ".desc_size = %u\n", params->desc_size);
0123 hid_dbg(hdev, ".pen = {\n");
0124 uclogic_params_pen_hid_dbg(hdev, ¶ms->pen);
0125 hid_dbg(hdev, "\t}\n");
0126 hid_dbg(hdev, ".frame_list = {\n");
0127 for (i = 0; i < ARRAY_SIZE(params->frame_list); i++) {
0128 hid_dbg(hdev, "\t{\n");
0129 uclogic_params_frame_hid_dbg(hdev, ¶ms->frame_list[i]);
0130 hid_dbg(hdev, "\t}%s\n",
0131 i < (ARRAY_SIZE(params->frame_list) - 1) ? "," : "");
0132 }
0133 hid_dbg(hdev, "}\n");
0134 }
0135
0136
0137
0138
0139
0140
0141
0142
0143
0144
0145
0146
0147
0148
0149
0150
0151
0152
0153
0154 static int uclogic_params_get_str_desc(__u8 **pbuf, struct hid_device *hdev,
0155 __u8 idx, size_t len)
0156 {
0157 int rc;
0158 struct usb_device *udev;
0159 __u8 *buf = NULL;
0160
0161
0162 if (hdev == NULL) {
0163 rc = -EINVAL;
0164 goto cleanup;
0165 }
0166
0167 udev = hid_to_usb_dev(hdev);
0168
0169 buf = kmalloc(len, GFP_KERNEL);
0170 if (buf == NULL) {
0171 rc = -ENOMEM;
0172 goto cleanup;
0173 }
0174
0175 rc = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
0176 USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
0177 (USB_DT_STRING << 8) + idx,
0178 0x0409, buf, len,
0179 USB_CTRL_GET_TIMEOUT);
0180 if (rc == -EPIPE) {
0181 hid_dbg(hdev, "string descriptor #%hhu not found\n", idx);
0182 goto cleanup;
0183 } else if (rc < 0) {
0184 hid_err(hdev,
0185 "failed retrieving string descriptor #%u: %d\n",
0186 idx, rc);
0187 goto cleanup;
0188 }
0189
0190 if (pbuf != NULL) {
0191 *pbuf = buf;
0192 buf = NULL;
0193 }
0194
0195 cleanup:
0196 kfree(buf);
0197 return rc;
0198 }
0199
0200
0201
0202
0203
0204
0205
0206
0207 static void uclogic_params_pen_cleanup(struct uclogic_params_pen *pen)
0208 {
0209 kfree(pen->desc_ptr);
0210 memset(pen, 0, sizeof(*pen));
0211 }
0212
0213
0214
0215
0216
0217
0218
0219
0220
0221
0222
0223
0224
0225
0226
0227
0228
0229 static int uclogic_params_pen_init_v1(struct uclogic_params_pen *pen,
0230 bool *pfound,
0231 struct hid_device *hdev)
0232 {
0233 int rc;
0234 bool found = false;
0235
0236 __u8 *buf = NULL;
0237
0238 const int len = 12;
0239 s32 resolution;
0240
0241 s32 desc_params[UCLOGIC_RDESC_PH_ID_NUM];
0242 __u8 *desc_ptr = NULL;
0243
0244
0245 if (pen == NULL || pfound == NULL || hdev == NULL) {
0246 rc = -EINVAL;
0247 goto cleanup;
0248 }
0249
0250
0251
0252
0253
0254
0255
0256 rc = uclogic_params_get_str_desc(&buf, hdev, 100, len);
0257 if (rc == -EPIPE) {
0258 hid_dbg(hdev,
0259 "string descriptor with pen parameters not found, assuming not compatible\n");
0260 goto finish;
0261 } else if (rc < 0) {
0262 hid_err(hdev, "failed retrieving pen parameters: %d\n", rc);
0263 goto cleanup;
0264 } else if (rc != len) {
0265 hid_dbg(hdev,
0266 "string descriptor with pen parameters has invalid length (got %d, expected %d), assuming not compatible\n",
0267 rc, len);
0268 goto finish;
0269 }
0270
0271
0272
0273
0274 desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_LM] =
0275 get_unaligned_le16(buf + 2);
0276 desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] =
0277 get_unaligned_le16(buf + 4);
0278 desc_params[UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM] =
0279 get_unaligned_le16(buf + 8);
0280 resolution = get_unaligned_le16(buf + 10);
0281 if (resolution == 0) {
0282 desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_PM] = 0;
0283 desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM] = 0;
0284 } else {
0285 desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_PM] =
0286 desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_LM] * 1000 /
0287 resolution;
0288 desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM] =
0289 desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] * 1000 /
0290 resolution;
0291 }
0292 kfree(buf);
0293 buf = NULL;
0294
0295
0296
0297
0298 desc_ptr = uclogic_rdesc_template_apply(
0299 uclogic_rdesc_v1_pen_template_arr,
0300 uclogic_rdesc_v1_pen_template_size,
0301 desc_params, ARRAY_SIZE(desc_params));
0302 if (desc_ptr == NULL) {
0303 rc = -ENOMEM;
0304 goto cleanup;
0305 }
0306
0307
0308
0309
0310 memset(pen, 0, sizeof(*pen));
0311 pen->desc_ptr = desc_ptr;
0312 desc_ptr = NULL;
0313 pen->desc_size = uclogic_rdesc_v1_pen_template_size;
0314 pen->id = UCLOGIC_RDESC_V1_PEN_ID;
0315 pen->inrange = UCLOGIC_PARAMS_PEN_INRANGE_INVERTED;
0316 found = true;
0317 finish:
0318 *pfound = found;
0319 rc = 0;
0320 cleanup:
0321 kfree(desc_ptr);
0322 kfree(buf);
0323 return rc;
0324 }
0325
0326
0327
0328
0329
0330
0331
0332
0333
0334
0335 static s32 uclogic_params_get_le24(const void *p)
0336 {
0337 const __u8 *b = p;
0338 return b[0] | (b[1] << 8UL) | (b[2] << 16UL);
0339 }
0340
0341
0342
0343
0344
0345
0346
0347
0348
0349
0350
0351
0352
0353
0354
0355
0356
0357
0358
0359
0360
0361
0362
0363
0364
0365
0366
0367 static int uclogic_params_pen_init_v2(struct uclogic_params_pen *pen,
0368 bool *pfound,
0369 __u8 **pparams_ptr,
0370 size_t *pparams_len,
0371 struct hid_device *hdev)
0372 {
0373 int rc;
0374 bool found = false;
0375
0376 __u8 *buf = NULL;
0377
0378 const int params_len_min = 18;
0379
0380 const int params_len_max = 32;
0381
0382 int params_len;
0383 size_t i;
0384 s32 resolution;
0385
0386 s32 desc_params[UCLOGIC_RDESC_PH_ID_NUM];
0387 __u8 *desc_ptr = NULL;
0388
0389
0390 if (pen == NULL || pfound == NULL || hdev == NULL) {
0391 rc = -EINVAL;
0392 goto cleanup;
0393 }
0394
0395
0396
0397
0398
0399
0400
0401 rc = uclogic_params_get_str_desc(&buf, hdev, 200, params_len_max);
0402 if (rc == -EPIPE) {
0403 hid_dbg(hdev,
0404 "string descriptor with pen parameters not found, assuming not compatible\n");
0405 goto finish;
0406 } else if (rc < 0) {
0407 hid_err(hdev, "failed retrieving pen parameters: %d\n", rc);
0408 goto cleanup;
0409 } else if (rc < params_len_min) {
0410 hid_dbg(hdev,
0411 "string descriptor with pen parameters is too short (got %d, expected at least %d), assuming not compatible\n",
0412 rc, params_len_min);
0413 goto finish;
0414 }
0415
0416 params_len = rc;
0417
0418
0419
0420
0421
0422
0423 for (i = 2;
0424 i < params_len &&
0425 (buf[i] >= 0x20 && buf[i] < 0x7f && buf[i + 1] == 0);
0426 i += 2);
0427 if (i >= params_len) {
0428 hid_dbg(hdev,
0429 "string descriptor with pen parameters seems to contain only text, assuming not compatible\n");
0430 goto finish;
0431 }
0432
0433
0434
0435
0436 desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_LM] =
0437 uclogic_params_get_le24(buf + 2);
0438 desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] =
0439 uclogic_params_get_le24(buf + 5);
0440 desc_params[UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM] =
0441 get_unaligned_le16(buf + 8);
0442 resolution = get_unaligned_le16(buf + 10);
0443 if (resolution == 0) {
0444 desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_PM] = 0;
0445 desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM] = 0;
0446 } else {
0447 desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_PM] =
0448 desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_LM] * 1000 /
0449 resolution;
0450 desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM] =
0451 desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] * 1000 /
0452 resolution;
0453 }
0454
0455
0456
0457
0458 desc_ptr = uclogic_rdesc_template_apply(
0459 uclogic_rdesc_v2_pen_template_arr,
0460 uclogic_rdesc_v2_pen_template_size,
0461 desc_params, ARRAY_SIZE(desc_params));
0462 if (desc_ptr == NULL) {
0463 rc = -ENOMEM;
0464 goto cleanup;
0465 }
0466
0467
0468
0469
0470 memset(pen, 0, sizeof(*pen));
0471 pen->desc_ptr = desc_ptr;
0472 desc_ptr = NULL;
0473 pen->desc_size = uclogic_rdesc_v2_pen_template_size;
0474 pen->id = UCLOGIC_RDESC_V2_PEN_ID;
0475 pen->inrange = UCLOGIC_PARAMS_PEN_INRANGE_NONE;
0476 pen->fragmented_hires = true;
0477 pen->tilt_y_flipped = true;
0478 found = true;
0479 if (pparams_ptr != NULL) {
0480 *pparams_ptr = buf;
0481 buf = NULL;
0482 }
0483 if (pparams_len != NULL)
0484 *pparams_len = params_len;
0485
0486 finish:
0487 *pfound = found;
0488 rc = 0;
0489 cleanup:
0490 kfree(desc_ptr);
0491 kfree(buf);
0492 return rc;
0493 }
0494
0495
0496
0497
0498
0499
0500
0501
0502 static void uclogic_params_frame_cleanup(struct uclogic_params_frame *frame)
0503 {
0504 kfree(frame->desc_ptr);
0505 memset(frame, 0, sizeof(*frame));
0506 }
0507
0508
0509
0510
0511
0512
0513
0514
0515
0516
0517
0518
0519
0520
0521
0522
0523 static int uclogic_params_frame_init_with_desc(
0524 struct uclogic_params_frame *frame,
0525 const __u8 *desc_ptr,
0526 size_t desc_size,
0527 unsigned int id)
0528 {
0529 __u8 *copy_desc_ptr;
0530
0531 if (frame == NULL || (desc_ptr == NULL && desc_size != 0))
0532 return -EINVAL;
0533
0534 copy_desc_ptr = kmemdup(desc_ptr, desc_size, GFP_KERNEL);
0535 if (copy_desc_ptr == NULL)
0536 return -ENOMEM;
0537
0538 memset(frame, 0, sizeof(*frame));
0539 frame->desc_ptr = copy_desc_ptr;
0540 frame->desc_size = desc_size;
0541 frame->id = id;
0542 return 0;
0543 }
0544
0545
0546
0547
0548
0549
0550
0551
0552
0553
0554
0555
0556
0557
0558
0559
0560
0561 static int uclogic_params_frame_init_v1(struct uclogic_params_frame *frame,
0562 bool *pfound,
0563 struct hid_device *hdev)
0564 {
0565 int rc;
0566 bool found = false;
0567 struct usb_device *usb_dev;
0568 char *str_buf = NULL;
0569 const size_t str_len = 16;
0570
0571
0572 if (frame == NULL || pfound == NULL || hdev == NULL) {
0573 rc = -EINVAL;
0574 goto cleanup;
0575 }
0576
0577 usb_dev = hid_to_usb_dev(hdev);
0578
0579
0580
0581
0582 str_buf = kzalloc(str_len, GFP_KERNEL);
0583 if (str_buf == NULL) {
0584 rc = -ENOMEM;
0585 goto cleanup;
0586 }
0587
0588 rc = usb_string(usb_dev, 123, str_buf, str_len);
0589 if (rc == -EPIPE) {
0590 hid_dbg(hdev,
0591 "generic button -enabling string descriptor not found\n");
0592 } else if (rc < 0) {
0593 goto cleanup;
0594 } else if (strncmp(str_buf, "HK On", rc) != 0) {
0595 hid_dbg(hdev,
0596 "invalid response to enabling generic buttons: \"%s\"\n",
0597 str_buf);
0598 } else {
0599 hid_dbg(hdev, "generic buttons enabled\n");
0600 rc = uclogic_params_frame_init_with_desc(
0601 frame,
0602 uclogic_rdesc_v1_frame_arr,
0603 uclogic_rdesc_v1_frame_size,
0604 UCLOGIC_RDESC_V1_FRAME_ID);
0605 if (rc != 0)
0606 goto cleanup;
0607 found = true;
0608 }
0609
0610 *pfound = found;
0611 rc = 0;
0612 cleanup:
0613 kfree(str_buf);
0614 return rc;
0615 }
0616
0617
0618
0619
0620
0621
0622
0623
0624 void uclogic_params_cleanup(struct uclogic_params *params)
0625 {
0626 if (!params->invalid) {
0627 size_t i;
0628 kfree(params->desc_ptr);
0629 uclogic_params_pen_cleanup(¶ms->pen);
0630 for (i = 0; i < ARRAY_SIZE(params->frame_list); i++)
0631 uclogic_params_frame_cleanup(¶ms->frame_list[i]);
0632
0633 memset(params, 0, sizeof(*params));
0634 }
0635 }
0636
0637
0638
0639
0640
0641
0642
0643
0644
0645
0646
0647
0648
0649
0650
0651
0652
0653
0654
0655
0656 int uclogic_params_get_desc(const struct uclogic_params *params,
0657 __u8 **pdesc,
0658 unsigned int *psize)
0659 {
0660 int rc = -ENOMEM;
0661 bool present = false;
0662 unsigned int size = 0;
0663 __u8 *desc = NULL;
0664 size_t i;
0665
0666
0667 if (params == NULL || pdesc == NULL || psize == NULL)
0668 return -EINVAL;
0669
0670
0671 #define ADD_DESC(_desc_ptr, _desc_size) \
0672 do { \
0673 unsigned int new_size; \
0674 __u8 *new_desc; \
0675 if ((_desc_ptr) == NULL) { \
0676 break; \
0677 } \
0678 new_size = size + (_desc_size); \
0679 new_desc = krealloc(desc, new_size, GFP_KERNEL); \
0680 if (new_desc == NULL) { \
0681 goto cleanup; \
0682 } \
0683 memcpy(new_desc + size, (_desc_ptr), (_desc_size)); \
0684 desc = new_desc; \
0685 size = new_size; \
0686 present = true; \
0687 } while (0)
0688
0689 ADD_DESC(params->desc_ptr, params->desc_size);
0690 ADD_DESC(params->pen.desc_ptr, params->pen.desc_size);
0691 for (i = 0; i < ARRAY_SIZE(params->frame_list); i++) {
0692 ADD_DESC(params->frame_list[i].desc_ptr,
0693 params->frame_list[i].desc_size);
0694 }
0695
0696 #undef ADD_DESC
0697
0698 if (present) {
0699 *pdesc = desc;
0700 *psize = size;
0701 desc = NULL;
0702 }
0703 rc = 0;
0704 cleanup:
0705 kfree(desc);
0706 return rc;
0707 }
0708
0709
0710
0711
0712
0713
0714
0715
0716 static void uclogic_params_init_invalid(struct uclogic_params *params)
0717 {
0718 params->invalid = true;
0719 }
0720
0721
0722
0723
0724
0725
0726
0727
0728
0729
0730
0731
0732
0733
0734
0735
0736
0737
0738
0739
0740
0741
0742 static int uclogic_params_init_with_opt_desc(struct uclogic_params *params,
0743 struct hid_device *hdev,
0744 unsigned int orig_desc_size,
0745 __u8 *desc_ptr,
0746 unsigned int desc_size)
0747 {
0748 __u8 *desc_copy_ptr = NULL;
0749 unsigned int desc_copy_size;
0750 int rc;
0751
0752
0753 if (params == NULL || hdev == NULL ||
0754 (desc_ptr == NULL && desc_size != 0)) {
0755 rc = -EINVAL;
0756 goto cleanup;
0757 }
0758
0759
0760 if (hdev->dev_rsize == orig_desc_size) {
0761 hid_dbg(hdev,
0762 "device report descriptor matches the expected size, replacing\n");
0763 desc_copy_ptr = kmemdup(desc_ptr, desc_size, GFP_KERNEL);
0764 if (desc_copy_ptr == NULL) {
0765 rc = -ENOMEM;
0766 goto cleanup;
0767 }
0768 desc_copy_size = desc_size;
0769 } else {
0770 hid_dbg(hdev,
0771 "device report descriptor doesn't match the expected size (%u != %u), preserving\n",
0772 hdev->dev_rsize, orig_desc_size);
0773 desc_copy_ptr = NULL;
0774 desc_copy_size = 0;
0775 }
0776
0777
0778 memset(params, 0, sizeof(*params));
0779 params->desc_ptr = desc_copy_ptr;
0780 desc_copy_ptr = NULL;
0781 params->desc_size = desc_copy_size;
0782
0783 rc = 0;
0784 cleanup:
0785 kfree(desc_copy_ptr);
0786 return rc;
0787 }
0788
0789
0790
0791
0792
0793
0794
0795
0796
0797
0798
0799
0800
0801
0802 static int uclogic_params_huion_init(struct uclogic_params *params,
0803 struct hid_device *hdev)
0804 {
0805 int rc;
0806 struct usb_device *udev;
0807 struct usb_interface *iface;
0808 __u8 bInterfaceNumber;
0809 bool found;
0810
0811 struct uclogic_params p = {0, };
0812 static const char transition_ver[] = "HUION_T153_160607";
0813 char *ver_ptr = NULL;
0814 const size_t ver_len = sizeof(transition_ver) + 1;
0815 __u8 *params_ptr = NULL;
0816 size_t params_len = 0;
0817
0818 const __u8 touch_ring_model_params_buf[] = {
0819 0x13, 0x03, 0x70, 0xC6, 0x00, 0x06, 0x7C, 0x00,
0820 0xFF, 0x1F, 0xD8, 0x13, 0x03, 0x0D, 0x10, 0x01,
0821 0x04, 0x3C, 0x3E
0822 };
0823
0824
0825 if (params == NULL || hdev == NULL) {
0826 rc = -EINVAL;
0827 goto cleanup;
0828 }
0829
0830 udev = hid_to_usb_dev(hdev);
0831 iface = to_usb_interface(hdev->dev.parent);
0832 bInterfaceNumber = iface->cur_altsetting->desc.bInterfaceNumber;
0833
0834
0835 if (bInterfaceNumber == 1) {
0836
0837 p.pen.usage_invalid = true;
0838 goto output;
0839
0840 } else if (bInterfaceNumber != 0) {
0841 uclogic_params_init_invalid(&p);
0842 goto output;
0843 }
0844
0845
0846 ver_ptr = kzalloc(ver_len, GFP_KERNEL);
0847 if (ver_ptr == NULL) {
0848 rc = -ENOMEM;
0849 goto cleanup;
0850 }
0851 rc = usb_string(udev, 201, ver_ptr, ver_len);
0852 if (rc == -EPIPE) {
0853 *ver_ptr = '\0';
0854 } else if (rc < 0) {
0855 hid_err(hdev,
0856 "failed retrieving Huion firmware version: %d\n", rc);
0857 goto cleanup;
0858 }
0859
0860
0861 if (strcmp(ver_ptr, transition_ver) == 0) {
0862 hid_dbg(hdev,
0863 "transition firmware detected, not probing pen v2 parameters\n");
0864 } else {
0865
0866 rc = uclogic_params_pen_init_v2(&p.pen, &found,
0867 ¶ms_ptr, ¶ms_len,
0868 hdev);
0869 if (rc != 0) {
0870 hid_err(hdev,
0871 "failed probing pen v2 parameters: %d\n", rc);
0872 goto cleanup;
0873 } else if (found) {
0874 hid_dbg(hdev, "pen v2 parameters found\n");
0875
0876 rc = uclogic_params_frame_init_with_desc(
0877 &p.frame_list[0],
0878 uclogic_rdesc_v2_frame_buttons_arr,
0879 uclogic_rdesc_v2_frame_buttons_size,
0880 UCLOGIC_RDESC_V2_FRAME_BUTTONS_ID);
0881 if (rc != 0) {
0882 hid_err(hdev,
0883 "failed creating v2 frame button parameters: %d\n",
0884 rc);
0885 goto cleanup;
0886 }
0887
0888
0889 p.pen.subreport_list[0].value = 0xe0;
0890 p.pen.subreport_list[0].id =
0891 UCLOGIC_RDESC_V2_FRAME_BUTTONS_ID;
0892
0893
0894 if (params_ptr != NULL &&
0895 params_len == sizeof(touch_ring_model_params_buf) &&
0896 memcmp(params_ptr, touch_ring_model_params_buf,
0897 params_len) == 0) {
0898
0899 rc = uclogic_params_frame_init_with_desc(
0900 &p.frame_list[1],
0901 uclogic_rdesc_v2_frame_touch_ring_arr,
0902 uclogic_rdesc_v2_frame_touch_ring_size,
0903 UCLOGIC_RDESC_V2_FRAME_TOUCH_ID);
0904 if (rc != 0) {
0905 hid_err(hdev,
0906 "failed creating v2 frame touch ring parameters: %d\n",
0907 rc);
0908 goto cleanup;
0909 }
0910 p.frame_list[1].suffix = "Touch Ring";
0911 p.frame_list[1].dev_id_byte =
0912 UCLOGIC_RDESC_V2_FRAME_TOUCH_DEV_ID_BYTE;
0913 p.frame_list[1].touch_byte = 5;
0914 p.frame_list[1].touch_max = 12;
0915 p.frame_list[1].touch_flip_at = 7;
0916 } else {
0917
0918 rc = uclogic_params_frame_init_with_desc(
0919 &p.frame_list[1],
0920 uclogic_rdesc_v2_frame_touch_strip_arr,
0921 uclogic_rdesc_v2_frame_touch_strip_size,
0922 UCLOGIC_RDESC_V2_FRAME_TOUCH_ID);
0923 if (rc != 0) {
0924 hid_err(hdev,
0925 "failed creating v2 frame touch strip parameters: %d\n",
0926 rc);
0927 goto cleanup;
0928 }
0929 p.frame_list[1].suffix = "Touch Strip";
0930 p.frame_list[1].dev_id_byte =
0931 UCLOGIC_RDESC_V2_FRAME_TOUCH_DEV_ID_BYTE;
0932 p.frame_list[1].touch_byte = 5;
0933 p.frame_list[1].touch_max = 8;
0934 }
0935
0936
0937 p.pen.subreport_list[1].value = 0xf0;
0938 p.pen.subreport_list[1].id =
0939 UCLOGIC_RDESC_V2_FRAME_TOUCH_ID;
0940
0941
0942 rc = uclogic_params_frame_init_with_desc(
0943 &p.frame_list[2],
0944 uclogic_rdesc_v2_frame_dial_arr,
0945 uclogic_rdesc_v2_frame_dial_size,
0946 UCLOGIC_RDESC_V2_FRAME_DIAL_ID);
0947 if (rc != 0) {
0948 hid_err(hdev,
0949 "failed creating v2 frame dial parameters: %d\n",
0950 rc);
0951 goto cleanup;
0952 }
0953 p.frame_list[2].suffix = "Dial";
0954 p.frame_list[2].dev_id_byte =
0955 UCLOGIC_RDESC_V2_FRAME_DIAL_DEV_ID_BYTE;
0956 p.frame_list[2].bitmap_dial_byte = 5;
0957
0958
0959 p.pen.subreport_list[2].value = 0xf1;
0960 p.pen.subreport_list[2].id =
0961 UCLOGIC_RDESC_V2_FRAME_DIAL_ID;
0962
0963 goto output;
0964 }
0965 hid_dbg(hdev, "pen v2 parameters not found\n");
0966 }
0967
0968
0969 rc = uclogic_params_pen_init_v1(&p.pen, &found, hdev);
0970 if (rc != 0) {
0971 hid_err(hdev,
0972 "failed probing pen v1 parameters: %d\n", rc);
0973 goto cleanup;
0974 } else if (found) {
0975 hid_dbg(hdev, "pen v1 parameters found\n");
0976
0977 rc = uclogic_params_frame_init_v1(&p.frame_list[0],
0978 &found, hdev);
0979 if (rc != 0) {
0980 hid_err(hdev, "v1 frame probing failed: %d\n", rc);
0981 goto cleanup;
0982 }
0983 hid_dbg(hdev, "frame v1 parameters%s found\n",
0984 (found ? "" : " not"));
0985 if (found) {
0986
0987 p.pen.subreport_list[0].value = 0xe0;
0988 p.pen.subreport_list[0].id =
0989 UCLOGIC_RDESC_V1_FRAME_ID;
0990 }
0991 goto output;
0992 }
0993 hid_dbg(hdev, "pen v1 parameters not found\n");
0994
0995 uclogic_params_init_invalid(&p);
0996
0997 output:
0998
0999 memcpy(params, &p, sizeof(*params));
1000 memset(&p, 0, sizeof(p));
1001 rc = 0;
1002 cleanup:
1003 kfree(params_ptr);
1004 kfree(ver_ptr);
1005 uclogic_params_cleanup(&p);
1006 return rc;
1007 }
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023 static int uclogic_probe_interface(struct hid_device *hdev, u8 *magic_arr,
1024 int magic_size, int endpoint)
1025 {
1026 struct usb_device *udev;
1027 unsigned int pipe = 0;
1028 int sent;
1029 u8 *buf = NULL;
1030 int rc = 0;
1031
1032 if (!hdev || !magic_arr) {
1033 rc = -EINVAL;
1034 goto cleanup;
1035 }
1036
1037 buf = kmemdup(magic_arr, magic_size, GFP_KERNEL);
1038 if (!buf) {
1039 rc = -ENOMEM;
1040 goto cleanup;
1041 }
1042
1043 udev = hid_to_usb_dev(hdev);
1044 pipe = usb_sndintpipe(udev, endpoint);
1045
1046 rc = usb_interrupt_msg(udev, pipe, buf, magic_size, &sent, 1000);
1047 if (rc || sent != magic_size) {
1048 hid_err(hdev, "Interface probing failed: %d\n", rc);
1049 rc = -1;
1050 goto cleanup;
1051 }
1052
1053 rc = 0;
1054 cleanup:
1055 kfree(buf);
1056 return rc;
1057 }
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078 static int uclogic_params_ugee_v2_init(struct uclogic_params *params,
1079 struct hid_device *hdev)
1080 {
1081 int rc = 0;
1082 struct usb_interface *iface;
1083 __u8 bInterfaceNumber;
1084 const int str_desc_len = 12;
1085 __u8 *str_desc = NULL;
1086 __u8 *rdesc_pen = NULL;
1087 __u8 *rdesc_frame = NULL;
1088 s32 desc_params[UCLOGIC_RDESC_PH_ID_NUM];
1089 s32 resolution;
1090 __u8 magic_arr[] = {
1091 0x02, 0xb0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
1092 };
1093
1094 struct uclogic_params p = {0, };
1095
1096 if (!params || !hdev) {
1097 rc = -EINVAL;
1098 goto cleanup;
1099 }
1100
1101 iface = to_usb_interface(hdev->dev.parent);
1102 bInterfaceNumber = iface->cur_altsetting->desc.bInterfaceNumber;
1103 if (bInterfaceNumber != 2) {
1104 uclogic_params_init_invalid(&p);
1105 goto output;
1106 }
1107
1108
1109
1110
1111
1112
1113 rc = uclogic_probe_interface(hdev, magic_arr, sizeof(magic_arr), 0x03);
1114 if (rc) {
1115 uclogic_params_init_invalid(&p);
1116 goto output;
1117 }
1118
1119
1120
1121
1122
1123
1124 rc = uclogic_params_get_str_desc(&str_desc, hdev, 100, str_desc_len);
1125 if (rc != str_desc_len) {
1126 hid_err(hdev, "failed retrieving pen and frame parameters: %d\n", rc);
1127 uclogic_params_init_invalid(&p);
1128 goto output;
1129 }
1130
1131 desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_LM] =
1132 get_unaligned_le16(str_desc + 2);
1133 desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] =
1134 get_unaligned_le16(str_desc + 4);
1135 desc_params[UCLOGIC_RDESC_FRAME_PH_ID_UM] = str_desc[6];
1136 desc_params[UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM] =
1137 get_unaligned_le16(str_desc + 8);
1138 resolution = get_unaligned_le16(str_desc + 10);
1139 if (resolution == 0) {
1140 desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_PM] = 0;
1141 desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM] = 0;
1142 } else {
1143 desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_PM] =
1144 desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_LM] * 1000 /
1145 resolution;
1146 desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM] =
1147 desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] * 1000 /
1148 resolution;
1149 }
1150 kfree(str_desc);
1151 str_desc = NULL;
1152
1153
1154 rdesc_pen = uclogic_rdesc_template_apply(
1155 uclogic_rdesc_ugee_v2_pen_template_arr,
1156 uclogic_rdesc_ugee_v2_pen_template_size,
1157 desc_params, ARRAY_SIZE(desc_params));
1158 if (!rdesc_pen) {
1159 rc = -ENOMEM;
1160 goto cleanup;
1161 }
1162
1163 p.pen.desc_ptr = rdesc_pen;
1164 p.pen.desc_size = uclogic_rdesc_ugee_v2_pen_template_size;
1165 p.pen.id = 0x02;
1166 p.pen.subreport_list[0].value = 0xf0;
1167 p.pen.subreport_list[0].id = UCLOGIC_RDESC_V1_FRAME_ID;
1168
1169
1170 rdesc_frame = uclogic_rdesc_template_apply(
1171 uclogic_rdesc_ugee_v2_frame_btn_template_arr,
1172 uclogic_rdesc_ugee_v2_frame_btn_template_size,
1173 desc_params, ARRAY_SIZE(desc_params));
1174 if (!rdesc_frame) {
1175 rc = -ENOMEM;
1176 goto cleanup;
1177 }
1178
1179 rc = uclogic_params_frame_init_with_desc(&p.frame_list[0],
1180 rdesc_frame,
1181 uclogic_rdesc_ugee_v2_frame_btn_template_size,
1182 UCLOGIC_RDESC_V1_FRAME_ID);
1183 kfree(rdesc_frame);
1184 if (rc) {
1185 uclogic_params_init_invalid(&p);
1186 goto output;
1187 }
1188
1189 output:
1190
1191 memcpy(params, &p, sizeof(*params));
1192 memset(&p, 0, sizeof(p));
1193 rc = 0;
1194 cleanup:
1195 kfree(str_desc);
1196 uclogic_params_cleanup(&p);
1197 return rc;
1198 }
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214 int uclogic_params_init(struct uclogic_params *params,
1215 struct hid_device *hdev)
1216 {
1217 int rc;
1218 struct usb_device *udev;
1219 __u8 bNumInterfaces;
1220 struct usb_interface *iface;
1221 __u8 bInterfaceNumber;
1222 bool found;
1223
1224 struct uclogic_params p = {0, };
1225
1226
1227 if (params == NULL || hdev == NULL || !hid_is_usb(hdev)) {
1228 rc = -EINVAL;
1229 goto cleanup;
1230 }
1231
1232 udev = hid_to_usb_dev(hdev);
1233 bNumInterfaces = udev->config->desc.bNumInterfaces;
1234 iface = to_usb_interface(hdev->dev.parent);
1235 bInterfaceNumber = iface->cur_altsetting->desc.bInterfaceNumber;
1236
1237
1238
1239
1240
1241 #define WITH_OPT_DESC(_orig_desc_token, _new_desc_token) \
1242 uclogic_params_init_with_opt_desc( \
1243 &p, hdev, \
1244 UCLOGIC_RDESC_##_orig_desc_token##_SIZE, \
1245 uclogic_rdesc_##_new_desc_token##_arr, \
1246 uclogic_rdesc_##_new_desc_token##_size)
1247
1248 #define VID_PID(_vid, _pid) \
1249 (((__u32)(_vid) << 16) | ((__u32)(_pid) & U16_MAX))
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270 switch (VID_PID(hdev->vendor, hdev->product)) {
1271 case VID_PID(USB_VENDOR_ID_UCLOGIC,
1272 USB_DEVICE_ID_UCLOGIC_TABLET_PF1209):
1273 rc = WITH_OPT_DESC(PF1209_ORIG, pf1209_fixed);
1274 if (rc != 0)
1275 goto cleanup;
1276 break;
1277 case VID_PID(USB_VENDOR_ID_UCLOGIC,
1278 USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U):
1279 rc = WITH_OPT_DESC(WPXXXXU_ORIG, wp4030u_fixed);
1280 if (rc != 0)
1281 goto cleanup;
1282 break;
1283 case VID_PID(USB_VENDOR_ID_UCLOGIC,
1284 USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U):
1285 if (hdev->dev_rsize == UCLOGIC_RDESC_WP5540U_V2_ORIG_SIZE) {
1286 if (bInterfaceNumber == 0) {
1287
1288 rc = uclogic_params_pen_init_v1(&p.pen,
1289 &found, hdev);
1290 if (rc != 0) {
1291 hid_err(hdev,
1292 "pen probing failed: %d\n",
1293 rc);
1294 goto cleanup;
1295 }
1296 if (!found) {
1297 hid_warn(hdev,
1298 "pen parameters not found");
1299 }
1300 } else {
1301 uclogic_params_init_invalid(&p);
1302 }
1303 } else {
1304 rc = WITH_OPT_DESC(WPXXXXU_ORIG, wp5540u_fixed);
1305 if (rc != 0)
1306 goto cleanup;
1307 }
1308 break;
1309 case VID_PID(USB_VENDOR_ID_UCLOGIC,
1310 USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U):
1311 rc = WITH_OPT_DESC(WPXXXXU_ORIG, wp8060u_fixed);
1312 if (rc != 0)
1313 goto cleanup;
1314 break;
1315 case VID_PID(USB_VENDOR_ID_UCLOGIC,
1316 USB_DEVICE_ID_UCLOGIC_TABLET_WP1062):
1317 rc = WITH_OPT_DESC(WP1062_ORIG, wp1062_fixed);
1318 if (rc != 0)
1319 goto cleanup;
1320 break;
1321 case VID_PID(USB_VENDOR_ID_UCLOGIC,
1322 USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850):
1323 switch (bInterfaceNumber) {
1324 case 0:
1325 rc = WITH_OPT_DESC(TWHL850_ORIG0, twhl850_fixed0);
1326 if (rc != 0)
1327 goto cleanup;
1328 break;
1329 case 1:
1330 rc = WITH_OPT_DESC(TWHL850_ORIG1, twhl850_fixed1);
1331 if (rc != 0)
1332 goto cleanup;
1333 break;
1334 case 2:
1335 rc = WITH_OPT_DESC(TWHL850_ORIG2, twhl850_fixed2);
1336 if (rc != 0)
1337 goto cleanup;
1338 break;
1339 }
1340 break;
1341 case VID_PID(USB_VENDOR_ID_UCLOGIC,
1342 USB_DEVICE_ID_UCLOGIC_TABLET_TWHA60):
1343
1344
1345
1346
1347 if (bNumInterfaces != 3) {
1348 switch (bInterfaceNumber) {
1349 case 0:
1350 rc = WITH_OPT_DESC(TWHA60_ORIG0,
1351 twha60_fixed0);
1352 if (rc != 0)
1353 goto cleanup;
1354 break;
1355 case 1:
1356 rc = WITH_OPT_DESC(TWHA60_ORIG1,
1357 twha60_fixed1);
1358 if (rc != 0)
1359 goto cleanup;
1360 break;
1361 }
1362 break;
1363 }
1364 fallthrough;
1365 case VID_PID(USB_VENDOR_ID_HUION,
1366 USB_DEVICE_ID_HUION_TABLET):
1367 case VID_PID(USB_VENDOR_ID_HUION,
1368 USB_DEVICE_ID_HUION_TABLET2):
1369 case VID_PID(USB_VENDOR_ID_UCLOGIC,
1370 USB_DEVICE_ID_HUION_TABLET):
1371 case VID_PID(USB_VENDOR_ID_UCLOGIC,
1372 USB_DEVICE_ID_YIYNOVA_TABLET):
1373 case VID_PID(USB_VENDOR_ID_UCLOGIC,
1374 USB_DEVICE_ID_UCLOGIC_UGEE_TABLET_81):
1375 case VID_PID(USB_VENDOR_ID_UCLOGIC,
1376 USB_DEVICE_ID_UCLOGIC_DRAWIMAGE_G3):
1377 case VID_PID(USB_VENDOR_ID_UCLOGIC,
1378 USB_DEVICE_ID_UCLOGIC_UGEE_TABLET_45):
1379 case VID_PID(USB_VENDOR_ID_UCLOGIC,
1380 USB_DEVICE_ID_UCLOGIC_UGEE_TABLET_47):
1381 rc = uclogic_params_huion_init(&p, hdev);
1382 if (rc != 0)
1383 goto cleanup;
1384 break;
1385 case VID_PID(USB_VENDOR_ID_UGTIZER,
1386 USB_DEVICE_ID_UGTIZER_TABLET_GP0610):
1387 case VID_PID(USB_VENDOR_ID_UGTIZER,
1388 USB_DEVICE_ID_UGTIZER_TABLET_GT5040):
1389 case VID_PID(USB_VENDOR_ID_UGEE,
1390 USB_DEVICE_ID_UGEE_XPPEN_TABLET_G540):
1391 case VID_PID(USB_VENDOR_ID_UGEE,
1392 USB_DEVICE_ID_UGEE_XPPEN_TABLET_G640):
1393 case VID_PID(USB_VENDOR_ID_UGEE,
1394 USB_DEVICE_ID_UGEE_XPPEN_TABLET_STAR06):
1395 case VID_PID(USB_VENDOR_ID_UGEE,
1396 USB_DEVICE_ID_UGEE_TABLET_RAINBOW_CV720):
1397
1398 if (bInterfaceNumber == 1) {
1399
1400 rc = uclogic_params_pen_init_v1(&p.pen, &found, hdev);
1401 if (rc != 0) {
1402 hid_err(hdev, "pen probing failed: %d\n", rc);
1403 goto cleanup;
1404 }
1405 if (!found) {
1406 hid_warn(hdev, "pen parameters not found");
1407 uclogic_params_init_invalid(&p);
1408 }
1409 } else {
1410 uclogic_params_init_invalid(&p);
1411 }
1412 break;
1413 case VID_PID(USB_VENDOR_ID_UGEE,
1414 USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO01):
1415
1416 if (bInterfaceNumber == 1) {
1417
1418 rc = uclogic_params_pen_init_v1(&p.pen, &found, hdev);
1419 if (rc != 0) {
1420 hid_err(hdev, "pen probing failed: %d\n", rc);
1421 goto cleanup;
1422 }
1423
1424 rc = uclogic_params_frame_init_with_desc(
1425 &p.frame_list[0],
1426 uclogic_rdesc_xppen_deco01_frame_arr,
1427 uclogic_rdesc_xppen_deco01_frame_size,
1428 0);
1429 if (rc != 0)
1430 goto cleanup;
1431 } else {
1432 uclogic_params_init_invalid(&p);
1433 }
1434 break;
1435 case VID_PID(USB_VENDOR_ID_UGEE,
1436 USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_L):
1437 rc = uclogic_params_ugee_v2_init(&p, hdev);
1438 if (rc != 0)
1439 goto cleanup;
1440 break;
1441 case VID_PID(USB_VENDOR_ID_TRUST,
1442 USB_DEVICE_ID_TRUST_PANORA_TABLET):
1443 case VID_PID(USB_VENDOR_ID_UGEE,
1444 USB_DEVICE_ID_UGEE_TABLET_G5):
1445
1446 if (bInterfaceNumber != 1) {
1447 uclogic_params_init_invalid(&p);
1448 break;
1449 }
1450
1451 rc = uclogic_params_pen_init_v1(&p.pen, &found, hdev);
1452 if (rc != 0) {
1453 hid_err(hdev, "pen probing failed: %d\n", rc);
1454 goto cleanup;
1455 } else if (found) {
1456 rc = uclogic_params_frame_init_with_desc(
1457 &p.frame_list[0],
1458 uclogic_rdesc_ugee_g5_frame_arr,
1459 uclogic_rdesc_ugee_g5_frame_size,
1460 UCLOGIC_RDESC_UGEE_G5_FRAME_ID);
1461 if (rc != 0) {
1462 hid_err(hdev,
1463 "failed creating frame parameters: %d\n",
1464 rc);
1465 goto cleanup;
1466 }
1467 p.frame_list[0].re_lsb =
1468 UCLOGIC_RDESC_UGEE_G5_FRAME_RE_LSB;
1469 p.frame_list[0].dev_id_byte =
1470 UCLOGIC_RDESC_UGEE_G5_FRAME_DEV_ID_BYTE;
1471 } else {
1472 hid_warn(hdev, "pen parameters not found");
1473 uclogic_params_init_invalid(&p);
1474 }
1475
1476 break;
1477 case VID_PID(USB_VENDOR_ID_UGEE,
1478 USB_DEVICE_ID_UGEE_TABLET_EX07S):
1479
1480 if (bInterfaceNumber != 1) {
1481 uclogic_params_init_invalid(&p);
1482 break;
1483 }
1484
1485 rc = uclogic_params_pen_init_v1(&p.pen, &found, hdev);
1486 if (rc != 0) {
1487 hid_err(hdev, "pen probing failed: %d\n", rc);
1488 goto cleanup;
1489 } else if (found) {
1490 rc = uclogic_params_frame_init_with_desc(
1491 &p.frame_list[0],
1492 uclogic_rdesc_ugee_ex07_frame_arr,
1493 uclogic_rdesc_ugee_ex07_frame_size,
1494 0);
1495 if (rc != 0) {
1496 hid_err(hdev,
1497 "failed creating frame parameters: %d\n",
1498 rc);
1499 goto cleanup;
1500 }
1501 } else {
1502 hid_warn(hdev, "pen parameters not found");
1503 uclogic_params_init_invalid(&p);
1504 }
1505
1506 break;
1507 }
1508
1509 #undef VID_PID
1510 #undef WITH_OPT_DESC
1511
1512
1513 memcpy(params, &p, sizeof(*params));
1514 memset(&p, 0, sizeof(p));
1515 rc = 0;
1516 cleanup:
1517 uclogic_params_cleanup(&p);
1518 return rc;
1519 }