@@ -238,7 +238,7 @@ static int uclogic_params_pen_init_v1(struct uclogic_params_pen *pen,
238
238
const int len = 12 ;
239
239
s32 resolution ;
240
240
/* Pen report descriptor template parameters */
241
- s32 desc_params [UCLOGIC_RDESC_PEN_PH_ID_NUM ];
241
+ s32 desc_params [UCLOGIC_RDESC_PH_ID_NUM ];
242
242
__u8 * desc_ptr = NULL ;
243
243
244
244
/* Check arguments */
@@ -383,7 +383,7 @@ static int uclogic_params_pen_init_v2(struct uclogic_params_pen *pen,
383
383
size_t i ;
384
384
s32 resolution ;
385
385
/* Pen report descriptor template parameters */
386
- s32 desc_params [UCLOGIC_RDESC_PEN_PH_ID_NUM ];
386
+ s32 desc_params [UCLOGIC_RDESC_PH_ID_NUM ];
387
387
__u8 * desc_ptr = NULL ;
388
388
389
389
/* Check arguments */
@@ -1006,6 +1006,197 @@ static int uclogic_params_huion_init(struct uclogic_params *params,
1006
1006
return rc ;
1007
1007
}
1008
1008
1009
+ /**
1010
+ * uclogic_probe_interface() - some tablets, like the Parblo A610 PLUS V2 or
1011
+ * the XP-PEN Deco Mini 7, need to be initialized by sending them magic data.
1012
+ *
1013
+ * @hdev: The HID device of the tablet interface to initialize and get
1014
+ * parameters from. Cannot be NULL.
1015
+ * @magic_arr: The magic data that should be sent to probe the interface.
1016
+ * Cannot be NULL.
1017
+ * @magic_size: Size of the magic data.
1018
+ * @endpoint: Endpoint where the magic data should be sent.
1019
+ *
1020
+ * Returns:
1021
+ * Zero, if successful. A negative errno code on error.
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
+ * uclogic_params_ugee_v2_init() - initialize a UGEE graphics tablets by
1061
+ * discovering their parameters.
1062
+ *
1063
+ * These tables, internally designed as v2 to differentiate them from older
1064
+ * models, expect a payload of magic data in orther to be switched to the fully
1065
+ * functional mode and expose their parameters in a similar way to the
1066
+ * information present in uclogic_params_pen_init_v1() but with some
1067
+ * differences.
1068
+ *
1069
+ * @params: Parameters to fill in (to be cleaned with
1070
+ * uclogic_params_cleanup()). Not modified in case of error.
1071
+ * Cannot be NULL.
1072
+ * @hdev: The HID device of the tablet interface to initialize and get
1073
+ * parameters from. Cannot be NULL.
1074
+ *
1075
+ * Returns:
1076
+ * Zero, if successful. A negative errno code on error.
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
+ /* The resulting parameters (noop) */
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
+ * Initialize the interface by sending magic data.
1110
+ * The specific data was discovered by sniffing the Windows driver
1111
+ * traffic.
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
+ * Read the string descriptor containing pen and frame parameters.
1121
+ * The specific string descriptor and data were discovered by sniffing
1122
+ * the Windows driver traffic.
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
+ /* Initialize the pen interface */
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
+ /* Initialize the frame interface */
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
+ /* Output parameters */
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
+
1009
1200
/**
1010
1201
* uclogic_params_init() - initialize a tablet interface and discover its
1011
1202
* parameters.
@@ -1241,6 +1432,12 @@ int uclogic_params_init(struct uclogic_params *params,
1241
1432
uclogic_params_init_invalid (& p );
1242
1433
}
1243
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 ;
1244
1441
case VID_PID (USB_VENDOR_ID_TRUST ,
1245
1442
USB_DEVICE_ID_TRUST_PANORA_TABLET ):
1246
1443
case VID_PID (USB_VENDOR_ID_UGEE ,
0 commit comments