@@ -238,7 +238,7 @@ static int uclogic_params_pen_init_v1(struct uclogic_params_pen *pen,
238238 const int len = 12 ;
239239 s32 resolution ;
240240 /* Pen report descriptor template parameters */
241- s32 desc_params [UCLOGIC_RDESC_PEN_PH_ID_NUM ];
241+ s32 desc_params [UCLOGIC_RDESC_PH_ID_NUM ];
242242 __u8 * desc_ptr = NULL ;
243243
244244 /* Check arguments */
@@ -383,7 +383,7 @@ static int uclogic_params_pen_init_v2(struct uclogic_params_pen *pen,
383383 size_t i ;
384384 s32 resolution ;
385385 /* Pen report descriptor template parameters */
386- s32 desc_params [UCLOGIC_RDESC_PEN_PH_ID_NUM ];
386+ s32 desc_params [UCLOGIC_RDESC_PH_ID_NUM ];
387387 __u8 * desc_ptr = NULL ;
388388
389389 /* Check arguments */
@@ -1006,6 +1006,197 @@ static int uclogic_params_huion_init(struct uclogic_params *params,
10061006 return rc ;
10071007}
10081008
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+
10091200/**
10101201 * uclogic_params_init() - initialize a tablet interface and discover its
10111202 * parameters.
@@ -1241,6 +1432,12 @@ int uclogic_params_init(struct uclogic_params *params,
12411432 uclogic_params_init_invalid (& p );
12421433 }
12431434 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 ;
12441441 case VID_PID (USB_VENDOR_ID_TRUST ,
12451442 USB_DEVICE_ID_TRUST_PANORA_TABLET ):
12461443 case VID_PID (USB_VENDOR_ID_UGEE ,
0 commit comments