Linux Audio

Check our new training course

Loading...
v5.4
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 *  HID driver for UC-Logic devices not fully compliant with HID standard
   4 *  - tablet initialization and parameter retrieval
   5 *
   6 *  Copyright (c) 2018 Nikolai Kondrashov
   7 */
   8
   9/*
  10 * This program is free software; you can redistribute it and/or modify it
  11 * under the terms of the GNU General Public License as published by the Free
  12 * Software Foundation; either version 2 of the License, or (at your option)
  13 * any later version.
  14 */
  15
  16#include "hid-uclogic-params.h"
  17#include "hid-uclogic-rdesc.h"
  18#include "usbhid/usbhid.h"
  19#include "hid-ids.h"
  20#include <linux/ctype.h>
 
  21#include <asm/unaligned.h>
  22
  23/**
  24 * Convert a pen in-range reporting type to a string.
  25 *
  26 * @inrange:	The in-range reporting type to convert.
  27 *
  28 * Returns:
  29 *	The string representing the type, or NULL if the type is unknown.
 
  30 */
  31const char *uclogic_params_pen_inrange_to_str(
  32			enum uclogic_params_pen_inrange inrange)
  33{
  34	switch (inrange) {
  35	case UCLOGIC_PARAMS_PEN_INRANGE_NORMAL:
  36		return "normal";
  37	case UCLOGIC_PARAMS_PEN_INRANGE_INVERTED:
  38		return "inverted";
  39	case UCLOGIC_PARAMS_PEN_INRANGE_NONE:
  40		return "none";
  41	default:
  42		return NULL;
  43	}
  44}
  45
  46/**
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
  47 * uclogic_params_get_str_desc - retrieve a string descriptor from a HID
  48 * device interface, putting it into a kmalloc-allocated buffer as is, without
  49 * character encoding conversion.
  50 *
  51 * @pbuf:	Location for the kmalloc-allocated buffer pointer containing
  52 *		the retrieved descriptor. Not modified in case of error.
  53 *		Can be NULL to have retrieved descriptor discarded.
  54 * @hdev:	The HID device of the tablet interface to retrieve the string
  55 *		descriptor from. Cannot be NULL.
  56 * @idx:	Index of the string descriptor to request from the device.
  57 * @len:	Length of the buffer to allocate and the data to retrieve.
  58 *
  59 * Returns:
  60 *	number of bytes retrieved (<= len),
  61 *	-EPIPE, if the descriptor was not found, or
  62 *	another negative errno code in case of other error.
  63 */
  64static int uclogic_params_get_str_desc(__u8 **pbuf, struct hid_device *hdev,
  65					__u8 idx, size_t len)
  66{
  67	int rc;
  68	struct usb_device *udev = hid_to_usb_dev(hdev);
  69	__u8 *buf = NULL;
  70
  71	/* Check arguments */
  72	if (hdev == NULL) {
  73		rc = -EINVAL;
  74		goto cleanup;
  75	}
  76
 
 
  77	buf = kmalloc(len, GFP_KERNEL);
  78	if (buf == NULL) {
  79		rc = -ENOMEM;
  80		goto cleanup;
  81	}
  82
  83	rc = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
  84				USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
  85				(USB_DT_STRING << 8) + idx,
  86				0x0409, buf, len,
  87				USB_CTRL_GET_TIMEOUT);
  88	if (rc == -EPIPE) {
  89		hid_dbg(hdev, "string descriptor #%hhu not found\n", idx);
  90		goto cleanup;
  91	} else if (rc < 0) {
  92		hid_err(hdev,
  93			"failed retrieving string descriptor #%hhu: %d\n",
  94			idx, rc);
  95		goto cleanup;
  96	}
  97
  98	if (pbuf != NULL) {
  99		*pbuf = buf;
 100		buf = NULL;
 101	}
 102
 103cleanup:
 104	kfree(buf);
 105	return rc;
 106}
 107
 108/**
 109 * uclogic_params_pen_cleanup - free resources used by struct
 110 * uclogic_params_pen (tablet interface's pen input parameters).
 111 * Can be called repeatedly.
 112 *
 113 * @pen:	Pen input parameters to cleanup. Cannot be NULL.
 114 */
 115static void uclogic_params_pen_cleanup(struct uclogic_params_pen *pen)
 116{
 117	kfree(pen->desc_ptr);
 118	memset(pen, 0, sizeof(*pen));
 119}
 120
 121/**
 122 * uclogic_params_pen_init_v1() - initialize tablet interface pen
 123 * input and retrieve its parameters from the device, using v1 protocol.
 124 *
 125 * @pen:	Pointer to the pen parameters to initialize (to be
 126 *		cleaned up with uclogic_params_pen_cleanup()). Not modified in
 127 *		case of error, or if parameters are not found. Cannot be NULL.
 128 * @pfound:	Location for a flag which is set to true if the parameters
 129 *		were found, and to false if not (e.g. device was
 130 *		incompatible). Not modified in case of error. Cannot be NULL.
 131 * @hdev:	The HID device of the tablet interface to initialize and get
 132 *		parameters from. Cannot be NULL.
 133 *
 134 * Returns:
 135 *	Zero, if successful. A negative errno code on error.
 136 */
 137static int uclogic_params_pen_init_v1(struct uclogic_params_pen *pen,
 138				      bool *pfound,
 139				      struct hid_device *hdev)
 140{
 141	int rc;
 142	bool found = false;
 143	/* Buffer for (part of) the string descriptor */
 144	__u8 *buf = NULL;
 145	/* Minimum descriptor length required, maximum seen so far is 18 */
 146	const int len = 12;
 147	s32 resolution;
 148	/* Pen report descriptor template parameters */
 149	s32 desc_params[UCLOGIC_RDESC_PEN_PH_ID_NUM];
 150	__u8 *desc_ptr = NULL;
 151
 152	/* Check arguments */
 153	if (pen == NULL || pfound == NULL || hdev == NULL) {
 154		rc = -EINVAL;
 155		goto cleanup;
 156	}
 157
 158	/*
 159	 * Read string descriptor containing pen input parameters.
 160	 * The specific string descriptor and data were discovered by sniffing
 161	 * the Windows driver traffic.
 162	 * NOTE: This enables fully-functional tablet mode.
 163	 */
 164	rc = uclogic_params_get_str_desc(&buf, hdev, 100, len);
 165	if (rc == -EPIPE) {
 166		hid_dbg(hdev,
 167			"string descriptor with pen parameters not found, assuming not compatible\n");
 168		goto finish;
 169	} else if (rc < 0) {
 170		hid_err(hdev, "failed retrieving pen parameters: %d\n", rc);
 171		goto cleanup;
 172	} else if (rc != len) {
 173		hid_dbg(hdev,
 174			"string descriptor with pen parameters has invalid length (got %d, expected %d), assuming not compatible\n",
 175			rc, len);
 176		goto finish;
 177	}
 178
 179	/*
 180	 * Fill report descriptor parameters from the string descriptor
 181	 */
 182	desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_LM] =
 183		get_unaligned_le16(buf + 2);
 184	desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] =
 185		get_unaligned_le16(buf + 4);
 186	desc_params[UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM] =
 187		get_unaligned_le16(buf + 8);
 188	resolution = get_unaligned_le16(buf + 10);
 189	if (resolution == 0) {
 190		desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_PM] = 0;
 191		desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM] = 0;
 192	} else {
 193		desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_PM] =
 194			desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_LM] * 1000 /
 195			resolution;
 196		desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM] =
 197			desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] * 1000 /
 198			resolution;
 199	}
 200	kfree(buf);
 201	buf = NULL;
 202
 203	/*
 204	 * Generate pen report descriptor
 205	 */
 206	desc_ptr = uclogic_rdesc_template_apply(
 207				uclogic_rdesc_pen_v1_template_arr,
 208				uclogic_rdesc_pen_v1_template_size,
 209				desc_params, ARRAY_SIZE(desc_params));
 210	if (desc_ptr == NULL) {
 211		rc = -ENOMEM;
 212		goto cleanup;
 213	}
 214
 215	/*
 216	 * Fill-in the parameters
 217	 */
 218	memset(pen, 0, sizeof(*pen));
 219	pen->desc_ptr = desc_ptr;
 220	desc_ptr = NULL;
 221	pen->desc_size = uclogic_rdesc_pen_v1_template_size;
 222	pen->id = UCLOGIC_RDESC_PEN_V1_ID;
 223	pen->inrange = UCLOGIC_PARAMS_PEN_INRANGE_INVERTED;
 224	found = true;
 225finish:
 226	*pfound = found;
 227	rc = 0;
 228cleanup:
 229	kfree(desc_ptr);
 230	kfree(buf);
 231	return rc;
 232}
 233
 234/**
 235 * uclogic_params_get_le24() - get a 24-bit little-endian number from a
 236 * buffer.
 237 *
 238 * @p:	The pointer to the number buffer.
 239 *
 240 * Returns:
 241 *	The retrieved number
 242 */
 243static s32 uclogic_params_get_le24(const void *p)
 244{
 245	const __u8 *b = p;
 246	return b[0] | (b[1] << 8UL) | (b[2] << 16UL);
 247}
 248
 249/**
 250 * uclogic_params_pen_init_v2() - initialize tablet interface pen
 251 * input and retrieve its parameters from the device, using v2 protocol.
 252 *
 253 * @pen:	Pointer to the pen parameters to initialize (to be
 254 *		cleaned up with uclogic_params_pen_cleanup()). Not modified in
 255 *		case of error, or if parameters are not found. Cannot be NULL.
 256 * @pfound:	Location for a flag which is set to true if the parameters
 257 *		were found, and to false if not (e.g. device was
 258 *		incompatible). Not modified in case of error. Cannot be NULL.
 259 * @hdev:	The HID device of the tablet interface to initialize and get
 260 *		parameters from. Cannot be NULL.
 
 
 
 
 
 
 
 
 
 
 261 *
 262 * Returns:
 263 *	Zero, if successful. A negative errno code on error.
 264 */
 265static int uclogic_params_pen_init_v2(struct uclogic_params_pen *pen,
 266					bool *pfound,
 
 
 267					struct hid_device *hdev)
 268{
 269	int rc;
 270	bool found = false;
 271	/* Buffer for (part of) the string descriptor */
 272	__u8 *buf = NULL;
 273	/* Descriptor length required */
 274	const int len = 18;
 
 
 
 
 
 275	s32 resolution;
 276	/* Pen report descriptor template parameters */
 277	s32 desc_params[UCLOGIC_RDESC_PEN_PH_ID_NUM];
 278	__u8 *desc_ptr = NULL;
 279
 280	/* Check arguments */
 281	if (pen == NULL || pfound == NULL || hdev == NULL) {
 282		rc = -EINVAL;
 283		goto cleanup;
 284	}
 285
 286	/*
 287	 * Read string descriptor containing pen input parameters.
 288	 * The specific string descriptor and data were discovered by sniffing
 289	 * the Windows driver traffic.
 290	 * NOTE: This enables fully-functional tablet mode.
 291	 */
 292	rc = uclogic_params_get_str_desc(&buf, hdev, 200, len);
 293	if (rc == -EPIPE) {
 294		hid_dbg(hdev,
 295			"string descriptor with pen parameters not found, assuming not compatible\n");
 296		goto finish;
 297	} else if (rc < 0) {
 298		hid_err(hdev, "failed retrieving pen parameters: %d\n", rc);
 299		goto cleanup;
 300	} else if (rc != len) {
 301		hid_dbg(hdev,
 302			"string descriptor with pen parameters has invalid length (got %d, expected %d), assuming not compatible\n",
 303			rc, len);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 304		goto finish;
 305	} else {
 306		size_t i;
 307		/*
 308		 * Check it's not just a catch-all UTF-16LE-encoded ASCII
 309		 * string (such as the model name) some tablets put into all
 310		 * unknown string descriptors.
 311		 */
 312		for (i = 2;
 313		     i < len &&
 314			(buf[i] >= 0x20 && buf[i] < 0x7f && buf[i + 1] == 0);
 315		     i += 2);
 316		if (i >= len) {
 317			hid_dbg(hdev,
 318				"string descriptor with pen parameters seems to contain only text, assuming not compatible\n");
 319			goto finish;
 320		}
 321	}
 322
 323	/*
 324	 * Fill report descriptor parameters from the string descriptor
 325	 */
 326	desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_LM] =
 327		uclogic_params_get_le24(buf + 2);
 328	desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] =
 329		uclogic_params_get_le24(buf + 5);
 330	desc_params[UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM] =
 331		get_unaligned_le16(buf + 8);
 332	resolution = get_unaligned_le16(buf + 10);
 333	if (resolution == 0) {
 334		desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_PM] = 0;
 335		desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM] = 0;
 336	} else {
 337		desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_PM] =
 338			desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_LM] * 1000 /
 339			resolution;
 340		desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM] =
 341			desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] * 1000 /
 342			resolution;
 343	}
 344	kfree(buf);
 345	buf = NULL;
 346
 347	/*
 348	 * Generate pen report descriptor
 349	 */
 350	desc_ptr = uclogic_rdesc_template_apply(
 351				uclogic_rdesc_pen_v2_template_arr,
 352				uclogic_rdesc_pen_v2_template_size,
 353				desc_params, ARRAY_SIZE(desc_params));
 354	if (desc_ptr == NULL) {
 355		rc = -ENOMEM;
 356		goto cleanup;
 357	}
 358
 359	/*
 360	 * Fill-in the parameters
 361	 */
 362	memset(pen, 0, sizeof(*pen));
 363	pen->desc_ptr = desc_ptr;
 364	desc_ptr = NULL;
 365	pen->desc_size = uclogic_rdesc_pen_v2_template_size;
 366	pen->id = UCLOGIC_RDESC_PEN_V2_ID;
 367	pen->inrange = UCLOGIC_PARAMS_PEN_INRANGE_NONE;
 368	pen->fragmented_hires = true;
 
 369	found = true;
 
 
 
 
 
 
 
 370finish:
 371	*pfound = found;
 372	rc = 0;
 373cleanup:
 374	kfree(desc_ptr);
 375	kfree(buf);
 376	return rc;
 377}
 378
 379/**
 380 * uclogic_params_frame_cleanup - free resources used by struct
 381 * uclogic_params_frame (tablet interface's frame controls input parameters).
 382 * Can be called repeatedly.
 383 *
 384 * @frame:	Frame controls input parameters to cleanup. Cannot be NULL.
 385 */
 386static void uclogic_params_frame_cleanup(struct uclogic_params_frame *frame)
 387{
 388	kfree(frame->desc_ptr);
 389	memset(frame, 0, sizeof(*frame));
 390}
 391
 392/**
 393 * uclogic_params_frame_init_with_desc() - initialize tablet's frame control
 394 * parameters with a static report descriptor.
 395 *
 396 * @frame:	Pointer to the frame parameters to initialize (to be cleaned
 397 *		up with uclogic_params_frame_cleanup()). Not modified in case
 398 *		of error. Cannot be NULL.
 399 * @desc_ptr:	Report descriptor pointer. Can be NULL, if desc_size is zero.
 400 * @desc_size:	Report descriptor size.
 401 * @id:		Report ID used for frame reports, if they should be tweaked,
 402 *		zero if not.
 403 *
 404 * Returns:
 405 *	Zero, if successful. A negative errno code on error.
 406 */
 407static int uclogic_params_frame_init_with_desc(
 408					struct uclogic_params_frame *frame,
 409					const __u8 *desc_ptr,
 410					size_t desc_size,
 411					unsigned int id)
 412{
 413	__u8 *copy_desc_ptr;
 414
 415	if (frame == NULL || (desc_ptr == NULL && desc_size != 0))
 416		return -EINVAL;
 417
 418	copy_desc_ptr = kmemdup(desc_ptr, desc_size, GFP_KERNEL);
 419	if (copy_desc_ptr == NULL)
 420		return -ENOMEM;
 421
 422	memset(frame, 0, sizeof(*frame));
 423	frame->desc_ptr = copy_desc_ptr;
 424	frame->desc_size = desc_size;
 425	frame->id = id;
 426	return 0;
 427}
 428
 429/**
 430 * uclogic_params_frame_init_v1_buttonpad() - initialize abstract buttonpad
 431 * on a v1 tablet interface.
 432 *
 433 * @frame:	Pointer to the frame parameters to initialize (to be cleaned
 434 *		up with uclogic_params_frame_cleanup()). Not modified in case
 435 *		of error, or if parameters are not found. Cannot be NULL.
 436 * @pfound:	Location for a flag which is set to true if the parameters
 437 *		were found, and to false if not (e.g. device was
 438 *		incompatible). Not modified in case of error. Cannot be NULL.
 439 * @hdev:	The HID device of the tablet interface to initialize and get
 440 *		parameters from. Cannot be NULL.
 441 *
 442 * Returns:
 443 *	Zero, if successful. A negative errno code on error.
 444 */
 445static int uclogic_params_frame_init_v1_buttonpad(
 446					struct uclogic_params_frame *frame,
 447					bool *pfound,
 448					struct hid_device *hdev)
 449{
 450	int rc;
 451	bool found = false;
 452	struct usb_device *usb_dev = hid_to_usb_dev(hdev);
 453	char *str_buf = NULL;
 454	const size_t str_len = 16;
 455
 456	/* Check arguments */
 457	if (frame == NULL || pfound == NULL || hdev == NULL) {
 458		rc = -EINVAL;
 459		goto cleanup;
 460	}
 461
 
 
 462	/*
 463	 * Enable generic button mode
 464	 */
 465	str_buf = kzalloc(str_len, GFP_KERNEL);
 466	if (str_buf == NULL) {
 467		rc = -ENOMEM;
 468		goto cleanup;
 469	}
 470
 471	rc = usb_string(usb_dev, 123, str_buf, str_len);
 472	if (rc == -EPIPE) {
 473		hid_dbg(hdev,
 474			"generic button -enabling string descriptor not found\n");
 475	} else if (rc < 0) {
 476		goto cleanup;
 477	} else if (strncmp(str_buf, "HK On", rc) != 0) {
 478		hid_dbg(hdev,
 479			"invalid response to enabling generic buttons: \"%s\"\n",
 480			str_buf);
 481	} else {
 482		hid_dbg(hdev, "generic buttons enabled\n");
 483		rc = uclogic_params_frame_init_with_desc(
 484				frame,
 485				uclogic_rdesc_buttonpad_v1_arr,
 486				uclogic_rdesc_buttonpad_v1_size,
 487				UCLOGIC_RDESC_BUTTONPAD_V1_ID);
 488		if (rc != 0)
 489			goto cleanup;
 490		found = true;
 491	}
 492
 493	*pfound = found;
 494	rc = 0;
 495cleanup:
 496	kfree(str_buf);
 497	return rc;
 498}
 499
 500/**
 501 * uclogic_params_cleanup - free resources used by struct uclogic_params
 502 * (tablet interface's parameters).
 503 * Can be called repeatedly.
 504 *
 505 * @params:	Input parameters to cleanup. Cannot be NULL.
 506 */
 507void uclogic_params_cleanup(struct uclogic_params *params)
 508{
 509	if (!params->invalid) {
 
 510		kfree(params->desc_ptr);
 511		if (!params->pen_unused)
 512			uclogic_params_pen_cleanup(&params->pen);
 513		uclogic_params_frame_cleanup(&params->frame);
 
 514		memset(params, 0, sizeof(*params));
 515	}
 516}
 517
 518/**
 519 * Get a replacement report descriptor for a tablet's interface.
 
 520 *
 521 * @params:	The parameters of a tablet interface to get report
 522 *		descriptor for. Cannot be NULL.
 523 * @pdesc:	Location for the resulting, kmalloc-allocated report
 524 *		descriptor pointer, or for NULL, if there's no replacement
 525 *		report descriptor. Not modified in case of error. Cannot be
 526 *		NULL.
 527 * @psize:	Location for the resulting report descriptor size, not set if
 528 *		there's no replacement report descriptor. Not modified in case
 529 *		of error. Cannot be NULL.
 530 *
 531 * Returns:
 532 *	Zero, if successful.
 533 *	-EINVAL, if invalid arguments are supplied.
 534 *	-ENOMEM, if failed to allocate memory.
 535 */
 536int uclogic_params_get_desc(const struct uclogic_params *params,
 537				__u8 **pdesc,
 538				unsigned int *psize)
 539{
 540	bool common_present;
 541	bool pen_present;
 542	bool frame_present;
 543	unsigned int size;
 544	__u8 *desc = NULL;
 
 545
 546	/* Check arguments */
 547	if (params == NULL || pdesc == NULL || psize == NULL)
 548		return -EINVAL;
 549
 550	size = 0;
 551
 552	common_present = (params->desc_ptr != NULL);
 553	pen_present = (!params->pen_unused && params->pen.desc_ptr != NULL);
 554	frame_present = (params->frame.desc_ptr != NULL);
 555
 556	if (common_present)
 557		size += params->desc_size;
 558	if (pen_present)
 559		size += params->pen.desc_size;
 560	if (frame_present)
 561		size += params->frame.desc_size;
 562
 563	if (common_present || pen_present || frame_present) {
 564		__u8 *p;
 565
 566		desc = kmalloc(size, GFP_KERNEL);
 567		if (desc == NULL)
 568			return -ENOMEM;
 569		p = desc;
 570
 571		if (common_present) {
 572			memcpy(p, params->desc_ptr,
 573				params->desc_size);
 574			p += params->desc_size;
 575		}
 576		if (pen_present) {
 577			memcpy(p, params->pen.desc_ptr,
 578				params->pen.desc_size);
 579			p += params->pen.desc_size;
 580		}
 581		if (frame_present) {
 582			memcpy(p, params->frame.desc_ptr,
 583				params->frame.desc_size);
 584			p += params->frame.desc_size;
 585		}
 586
 587		WARN_ON(p != desc + size);
 588
 
 
 589		*psize = size;
 
 590	}
 591
 592	*pdesc = desc;
 593	return 0;
 
 594}
 595
 596/**
 597 * uclogic_params_init_invalid() - initialize tablet interface parameters,
 598 * specifying the interface is invalid.
 599 *
 600 * @params:		Parameters to initialize (to be cleaned with
 601 *			uclogic_params_cleanup()). Cannot be NULL.
 602 */
 603static void uclogic_params_init_invalid(struct uclogic_params *params)
 604{
 605	params->invalid = true;
 606}
 607
 608/**
 609 * uclogic_params_init_with_opt_desc() - initialize tablet interface
 610 * parameters with an optional replacement report descriptor. Only modify
 611 * report descriptor, if the original report descriptor matches the expected
 612 * size.
 613 *
 614 * @params:		Parameters to initialize (to be cleaned with
 615 *			uclogic_params_cleanup()). Not modified in case of
 616 *			error. Cannot be NULL.
 617 * @hdev:		The HID device of the tablet interface create the
 618 *			parameters for. Cannot be NULL.
 619 * @orig_desc_size:	Expected size of the original report descriptor to
 620 *			be replaced.
 621 * @desc_ptr:		Pointer to the replacement report descriptor.
 622 *			Can be NULL, if desc_size is zero.
 623 * @desc_size:		Size of the replacement report descriptor.
 624 *
 625 * Returns:
 626 *	Zero, if successful. -EINVAL if an invalid argument was passed.
 627 *	-ENOMEM, if failed to allocate memory.
 628 */
 629static int uclogic_params_init_with_opt_desc(struct uclogic_params *params,
 630					     struct hid_device *hdev,
 631					     unsigned int orig_desc_size,
 632					     __u8 *desc_ptr,
 633					     unsigned int desc_size)
 634{
 635	__u8 *desc_copy_ptr = NULL;
 636	unsigned int desc_copy_size;
 637	int rc;
 638
 639	/* Check arguments */
 640	if (params == NULL || hdev == NULL ||
 641	    (desc_ptr == NULL && desc_size != 0)) {
 642		rc = -EINVAL;
 643		goto cleanup;
 644	}
 645
 646	/* Replace report descriptor, if it matches */
 647	if (hdev->dev_rsize == orig_desc_size) {
 648		hid_dbg(hdev,
 649			"device report descriptor matches the expected size, replacing\n");
 650		desc_copy_ptr = kmemdup(desc_ptr, desc_size, GFP_KERNEL);
 651		if (desc_copy_ptr == NULL) {
 652			rc = -ENOMEM;
 653			goto cleanup;
 654		}
 655		desc_copy_size = desc_size;
 656	} else {
 657		hid_dbg(hdev,
 658			"device report descriptor doesn't match the expected size (%u != %u), preserving\n",
 659			hdev->dev_rsize, orig_desc_size);
 660		desc_copy_ptr = NULL;
 661		desc_copy_size = 0;
 662	}
 663
 664	/* Output parameters */
 665	memset(params, 0, sizeof(*params));
 666	params->desc_ptr = desc_copy_ptr;
 667	desc_copy_ptr = NULL;
 668	params->desc_size = desc_copy_size;
 669
 670	rc = 0;
 671cleanup:
 672	kfree(desc_copy_ptr);
 673	return rc;
 674}
 675
 676/**
 677 * uclogic_params_init_with_pen_unused() - initialize tablet interface
 678 * parameters preserving original reports and generic HID processing, but
 679 * disabling pen usage.
 680 *
 681 * @params:		Parameters to initialize (to be cleaned with
 682 *			uclogic_params_cleanup()). Not modified in case of
 683 *			error. Cannot be NULL.
 684 */
 685static void uclogic_params_init_with_pen_unused(struct uclogic_params *params)
 686{
 687	memset(params, 0, sizeof(*params));
 688	params->pen_unused = true;
 689}
 690
 691/**
 692 * uclogic_params_init() - initialize a Huion tablet interface and discover
 693 * its parameters.
 694 *
 695 * @params:	Parameters to fill in (to be cleaned with
 696 *		uclogic_params_cleanup()). Not modified in case of error.
 697 *		Cannot be NULL.
 698 * @hdev:	The HID device of the tablet interface to initialize and get
 699 *		parameters from. Cannot be NULL.
 700 *
 701 * Returns:
 702 *	Zero, if successful. A negative errno code on error.
 703 */
 704static int uclogic_params_huion_init(struct uclogic_params *params,
 705				     struct hid_device *hdev)
 706{
 707	int rc;
 708	struct usb_device *udev = hid_to_usb_dev(hdev);
 709	struct usb_interface *iface = to_usb_interface(hdev->dev.parent);
 710	__u8 bInterfaceNumber = iface->cur_altsetting->desc.bInterfaceNumber;
 711	bool found;
 712	/* The resulting parameters (noop) */
 713	struct uclogic_params p = {0, };
 714	static const char transition_ver[] = "HUION_T153_160607";
 715	char *ver_ptr = NULL;
 716	const size_t ver_len = sizeof(transition_ver) + 1;
 
 
 
 
 
 
 
 
 717
 718	/* Check arguments */
 719	if (params == NULL || hdev == NULL) {
 720		rc = -EINVAL;
 721		goto cleanup;
 722	}
 723
 724	/* If it's not a pen interface */
 725	if (bInterfaceNumber != 0) {
 726		/* TODO: Consider marking the interface invalid */
 727		uclogic_params_init_with_pen_unused(&p);
 
 
 
 
 
 
 
 
 728		goto output;
 729	}
 730
 731	/* Try to get firmware version */
 732	ver_ptr = kzalloc(ver_len, GFP_KERNEL);
 733	if (ver_ptr == NULL) {
 734		rc = -ENOMEM;
 735		goto cleanup;
 736	}
 737	rc = usb_string(udev, 201, ver_ptr, ver_len);
 738	if (rc == -EPIPE) {
 739		*ver_ptr = '\0';
 740	} else if (rc < 0) {
 741		hid_err(hdev,
 742			"failed retrieving Huion firmware version: %d\n", rc);
 743		goto cleanup;
 744	}
 745
 746	/* If this is a transition firmware */
 747	if (strcmp(ver_ptr, transition_ver) == 0) {
 748		hid_dbg(hdev,
 749			"transition firmware detected, not probing pen v2 parameters\n");
 750	} else {
 751		/* Try to probe v2 pen parameters */
 752		rc = uclogic_params_pen_init_v2(&p.pen, &found, hdev);
 
 
 753		if (rc != 0) {
 754			hid_err(hdev,
 755				"failed probing pen v2 parameters: %d\n", rc);
 756			goto cleanup;
 757		} else if (found) {
 758			hid_dbg(hdev, "pen v2 parameters found\n");
 759			/* Create v2 buttonpad parameters */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 760			rc = uclogic_params_frame_init_with_desc(
 761					&p.frame,
 762					uclogic_rdesc_buttonpad_v2_arr,
 763					uclogic_rdesc_buttonpad_v2_size,
 764					UCLOGIC_RDESC_BUTTONPAD_V2_ID);
 765			if (rc != 0) {
 766				hid_err(hdev,
 767					"failed creating v2 buttonpad parameters: %d\n",
 768					rc);
 769				goto cleanup;
 770			}
 771			/* Set bitmask marking frame reports in pen reports */
 772			p.pen_frame_flag = 0x20;
 
 
 
 
 
 
 
 
 773			goto output;
 774		}
 775		hid_dbg(hdev, "pen v2 parameters not found\n");
 776	}
 777
 778	/* Try to probe v1 pen parameters */
 779	rc = uclogic_params_pen_init_v1(&p.pen, &found, hdev);
 780	if (rc != 0) {
 781		hid_err(hdev,
 782			"failed probing pen v1 parameters: %d\n", rc);
 783		goto cleanup;
 784	} else if (found) {
 785		hid_dbg(hdev, "pen v1 parameters found\n");
 786		/* Try to probe v1 buttonpad */
 787		rc = uclogic_params_frame_init_v1_buttonpad(
 788						&p.frame,
 789						&found, hdev);
 790		if (rc != 0) {
 791			hid_err(hdev, "v1 buttonpad probing failed: %d\n", rc);
 792			goto cleanup;
 793		}
 794		hid_dbg(hdev, "buttonpad v1 parameters%s found\n",
 795			(found ? "" : " not"));
 796		if (found) {
 797			/* Set bitmask marking frame reports */
 798			p.pen_frame_flag = 0x20;
 
 
 799		}
 800		goto output;
 801	}
 802	hid_dbg(hdev, "pen v1 parameters not found\n");
 803
 804	uclogic_params_init_invalid(&p);
 805
 806output:
 807	/* Output parameters */
 808	memcpy(params, &p, sizeof(*params));
 809	memset(&p, 0, sizeof(p));
 810	rc = 0;
 811cleanup:
 
 812	kfree(ver_ptr);
 813	uclogic_params_cleanup(&p);
 814	return rc;
 815}
 816
 817/**
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 818 * uclogic_params_init() - initialize a tablet interface and discover its
 819 * parameters.
 820 *
 821 * @params:	Parameters to fill in (to be cleaned with
 822 *		uclogic_params_cleanup()). Not modified in case of error.
 823 *		Cannot be NULL.
 824 * @hdev:	The HID device of the tablet interface to initialize and get
 825 *		parameters from. Cannot be NULL. Must be using the USB low-level
 826 *		driver, i.e. be an actual USB tablet.
 827 *
 828 * Returns:
 829 *	Zero, if successful. A negative errno code on error.
 830 */
 831int uclogic_params_init(struct uclogic_params *params,
 832			struct hid_device *hdev)
 833{
 834	int rc;
 835	struct usb_device *udev = hid_to_usb_dev(hdev);
 836	__u8  bNumInterfaces = udev->config->desc.bNumInterfaces;
 837	struct usb_interface *iface = to_usb_interface(hdev->dev.parent);
 838	__u8 bInterfaceNumber = iface->cur_altsetting->desc.bInterfaceNumber;
 839	bool found;
 840	/* The resulting parameters (noop) */
 841	struct uclogic_params p = {0, };
 842
 843	/* Check arguments */
 844	if (params == NULL || hdev == NULL ||
 845	    !hid_is_using_ll_driver(hdev, &usb_hid_driver)) {
 846		rc = -EINVAL;
 847		goto cleanup;
 848	}
 849
 
 
 
 
 
 850	/*
 851	 * Set replacement report descriptor if the original matches the
 852	 * specified size. Otherwise keep interface unchanged.
 853	 */
 854#define WITH_OPT_DESC(_orig_desc_token, _new_desc_token) \
 855	uclogic_params_init_with_opt_desc(                  \
 856		&p, hdev,                                   \
 857		UCLOGIC_RDESC_##_orig_desc_token##_SIZE,    \
 858		uclogic_rdesc_##_new_desc_token##_arr,      \
 859		uclogic_rdesc_##_new_desc_token##_size)
 860
 861#define VID_PID(_vid, _pid) \
 862	(((__u32)(_vid) << 16) | ((__u32)(_pid) & U16_MAX))
 863
 864	/*
 865	 * Handle specific interfaces for specific tablets.
 866	 *
 867	 * Observe the following logic:
 868	 *
 869	 * If the interface is recognized as producing certain useful input:
 870	 *	Mark interface as valid.
 871	 *	Output interface parameters.
 872	 * Else, if the interface is recognized as *not* producing any useful
 873	 * input:
 874	 *	Mark interface as invalid.
 875	 * Else:
 876	 *	Mark interface as valid.
 877	 *	Output noop parameters.
 878	 *
 879	 * Rule of thumb: it is better to disable a broken interface than let
 880	 *		  it spew garbage input.
 881	 */
 882
 883	switch (VID_PID(hdev->vendor, hdev->product)) {
 884	case VID_PID(USB_VENDOR_ID_UCLOGIC,
 885		     USB_DEVICE_ID_UCLOGIC_TABLET_PF1209):
 886		rc = WITH_OPT_DESC(PF1209_ORIG, pf1209_fixed);
 887		if (rc != 0)
 888			goto cleanup;
 889		break;
 890	case VID_PID(USB_VENDOR_ID_UCLOGIC,
 891		     USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U):
 892		rc = WITH_OPT_DESC(WPXXXXU_ORIG, wp4030u_fixed);
 893		if (rc != 0)
 894			goto cleanup;
 895		break;
 896	case VID_PID(USB_VENDOR_ID_UCLOGIC,
 897		     USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U):
 898		if (hdev->dev_rsize == UCLOGIC_RDESC_WP5540U_V2_ORIG_SIZE) {
 899			if (bInterfaceNumber == 0) {
 900				/* Try to probe v1 pen parameters */
 901				rc = uclogic_params_pen_init_v1(&p.pen,
 902								&found, hdev);
 903				if (rc != 0) {
 904					hid_err(hdev,
 905						"pen probing failed: %d\n",
 906						rc);
 907					goto cleanup;
 908				}
 909				if (!found) {
 910					hid_warn(hdev,
 911						 "pen parameters not found");
 912				}
 913			} else {
 914				uclogic_params_init_invalid(&p);
 915			}
 916		} else {
 917			rc = WITH_OPT_DESC(WPXXXXU_ORIG, wp5540u_fixed);
 918			if (rc != 0)
 919				goto cleanup;
 920		}
 921		break;
 922	case VID_PID(USB_VENDOR_ID_UCLOGIC,
 923		     USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U):
 924		rc = WITH_OPT_DESC(WPXXXXU_ORIG, wp8060u_fixed);
 925		if (rc != 0)
 926			goto cleanup;
 927		break;
 928	case VID_PID(USB_VENDOR_ID_UCLOGIC,
 929		     USB_DEVICE_ID_UCLOGIC_TABLET_WP1062):
 930		rc = WITH_OPT_DESC(WP1062_ORIG, wp1062_fixed);
 931		if (rc != 0)
 932			goto cleanup;
 933		break;
 934	case VID_PID(USB_VENDOR_ID_UCLOGIC,
 935		     USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850):
 936		switch (bInterfaceNumber) {
 937		case 0:
 938			rc = WITH_OPT_DESC(TWHL850_ORIG0, twhl850_fixed0);
 939			if (rc != 0)
 940				goto cleanup;
 941			break;
 942		case 1:
 943			rc = WITH_OPT_DESC(TWHL850_ORIG1, twhl850_fixed1);
 944			if (rc != 0)
 945				goto cleanup;
 946			break;
 947		case 2:
 948			rc = WITH_OPT_DESC(TWHL850_ORIG2, twhl850_fixed2);
 949			if (rc != 0)
 950				goto cleanup;
 951			break;
 952		}
 953		break;
 954	case VID_PID(USB_VENDOR_ID_UCLOGIC,
 955		     USB_DEVICE_ID_UCLOGIC_TABLET_TWHA60):
 956		/*
 957		 * If it is not a three-interface version, which is known to
 958		 * respond to initialization.
 959		 */
 960		if (bNumInterfaces != 3) {
 961			switch (bInterfaceNumber) {
 962			case 0:
 963				rc = WITH_OPT_DESC(TWHA60_ORIG0,
 964							twha60_fixed0);
 965				if (rc != 0)
 966					goto cleanup;
 967				break;
 968			case 1:
 969				rc = WITH_OPT_DESC(TWHA60_ORIG1,
 970							twha60_fixed1);
 971				if (rc != 0)
 972					goto cleanup;
 973				break;
 974			}
 975			break;
 976		}
 977		/* FALL THROUGH */
 978	case VID_PID(USB_VENDOR_ID_HUION,
 979		     USB_DEVICE_ID_HUION_TABLET):
 980	case VID_PID(USB_VENDOR_ID_HUION,
 981		     USB_DEVICE_ID_HUION_HS64):
 982	case VID_PID(USB_VENDOR_ID_UCLOGIC,
 983		     USB_DEVICE_ID_HUION_TABLET):
 984	case VID_PID(USB_VENDOR_ID_UCLOGIC,
 985		     USB_DEVICE_ID_YIYNOVA_TABLET):
 986	case VID_PID(USB_VENDOR_ID_UCLOGIC,
 987		     USB_DEVICE_ID_UCLOGIC_UGEE_TABLET_81):
 988	case VID_PID(USB_VENDOR_ID_UCLOGIC,
 989		     USB_DEVICE_ID_UCLOGIC_DRAWIMAGE_G3):
 990	case VID_PID(USB_VENDOR_ID_UCLOGIC,
 991		     USB_DEVICE_ID_UCLOGIC_UGEE_TABLET_45):
 992	case VID_PID(USB_VENDOR_ID_UCLOGIC,
 993		     USB_DEVICE_ID_UCLOGIC_UGEE_TABLET_47):
 994		rc = uclogic_params_huion_init(&p, hdev);
 995		if (rc != 0)
 996			goto cleanup;
 997		break;
 998	case VID_PID(USB_VENDOR_ID_UGTIZER,
 999		     USB_DEVICE_ID_UGTIZER_TABLET_GP0610):
 
 
1000	case VID_PID(USB_VENDOR_ID_UGEE,
1001		     USB_DEVICE_ID_UGEE_XPPEN_TABLET_G540):
1002	case VID_PID(USB_VENDOR_ID_UGEE,
1003		     USB_DEVICE_ID_UGEE_XPPEN_TABLET_G640):
1004	case VID_PID(USB_VENDOR_ID_UGEE,
 
 
1005		     USB_DEVICE_ID_UGEE_TABLET_RAINBOW_CV720):
1006		/* If this is the pen interface */
1007		if (bInterfaceNumber == 1) {
1008			/* Probe v1 pen parameters */
1009			rc = uclogic_params_pen_init_v1(&p.pen, &found, hdev);
1010			if (rc != 0) {
1011				hid_err(hdev, "pen probing failed: %d\n", rc);
1012				goto cleanup;
1013			}
1014			if (!found) {
1015				hid_warn(hdev, "pen parameters not found");
1016				uclogic_params_init_invalid(&p);
1017			}
1018		} else {
1019			/* TODO: Consider marking the interface invalid */
1020			uclogic_params_init_with_pen_unused(&p);
1021		}
1022		break;
1023	case VID_PID(USB_VENDOR_ID_UGEE,
1024		     USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO01):
1025		/* If this is the pen and frame interface */
1026		if (bInterfaceNumber == 1) {
1027			/* Probe v1 pen parameters */
1028			rc = uclogic_params_pen_init_v1(&p.pen, &found, hdev);
1029			if (rc != 0) {
1030				hid_err(hdev, "pen probing failed: %d\n", rc);
1031				goto cleanup;
1032			}
1033			/* Initialize frame parameters */
1034			rc = uclogic_params_frame_init_with_desc(
1035				&p.frame,
1036				uclogic_rdesc_xppen_deco01_frame_arr,
1037				uclogic_rdesc_xppen_deco01_frame_size,
1038				0);
1039			if (rc != 0)
1040				goto cleanup;
1041		} else {
1042			/* TODO: Consider marking the interface invalid */
1043			uclogic_params_init_with_pen_unused(&p);
1044		}
1045		break;
1046	case VID_PID(USB_VENDOR_ID_UGEE,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1047		     USB_DEVICE_ID_UGEE_TABLET_G5):
1048		/* Ignore non-pen interfaces */
1049		if (bInterfaceNumber != 1) {
1050			uclogic_params_init_invalid(&p);
1051			break;
1052		}
1053
1054		rc = uclogic_params_pen_init_v1(&p.pen, &found, hdev);
1055		if (rc != 0) {
1056			hid_err(hdev, "pen probing failed: %d\n", rc);
1057			goto cleanup;
1058		} else if (found) {
1059			rc = uclogic_params_frame_init_with_desc(
1060				&p.frame,
1061				uclogic_rdesc_ugee_g5_frame_arr,
1062				uclogic_rdesc_ugee_g5_frame_size,
1063				UCLOGIC_RDESC_UGEE_G5_FRAME_ID);
1064			if (rc != 0) {
1065				hid_err(hdev,
1066					"failed creating buttonpad parameters: %d\n",
1067					rc);
1068				goto cleanup;
1069			}
1070			p.frame.re_lsb =
1071				UCLOGIC_RDESC_UGEE_G5_FRAME_RE_LSB;
1072			p.frame.dev_id_byte =
1073				UCLOGIC_RDESC_UGEE_G5_FRAME_DEV_ID_BYTE;
1074		} else {
1075			hid_warn(hdev, "pen parameters not found");
1076			uclogic_params_init_invalid(&p);
1077		}
1078
1079		break;
1080	case VID_PID(USB_VENDOR_ID_UGEE,
1081		     USB_DEVICE_ID_UGEE_TABLET_EX07S):
1082		/* Ignore non-pen interfaces */
1083		if (bInterfaceNumber != 1) {
1084			uclogic_params_init_invalid(&p);
1085			break;
1086		}
1087
1088		rc = uclogic_params_pen_init_v1(&p.pen, &found, hdev);
1089		if (rc != 0) {
1090			hid_err(hdev, "pen probing failed: %d\n", rc);
1091			goto cleanup;
1092		} else if (found) {
1093			rc = uclogic_params_frame_init_with_desc(
1094				&p.frame,
1095				uclogic_rdesc_ugee_ex07_buttonpad_arr,
1096				uclogic_rdesc_ugee_ex07_buttonpad_size,
1097				0);
1098			if (rc != 0) {
1099				hid_err(hdev,
1100					"failed creating buttonpad parameters: %d\n",
1101					rc);
1102				goto cleanup;
1103			}
1104		} else {
1105			hid_warn(hdev, "pen parameters not found");
1106			uclogic_params_init_invalid(&p);
1107		}
1108
1109		break;
1110	}
1111
1112#undef VID_PID
1113#undef WITH_OPT_DESC
1114
1115	/* Output parameters */
1116	memcpy(params, &p, sizeof(*params));
1117	memset(&p, 0, sizeof(p));
1118	rc = 0;
1119cleanup:
1120	uclogic_params_cleanup(&p);
1121	return rc;
1122}
v6.2
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 *  HID driver for UC-Logic devices not fully compliant with HID standard
   4 *  - tablet initialization and parameter retrieval
   5 *
   6 *  Copyright (c) 2018 Nikolai Kondrashov
   7 */
   8
   9/*
  10 * This program is free software; you can redistribute it and/or modify it
  11 * under the terms of the GNU General Public License as published by the Free
  12 * Software Foundation; either version 2 of the License, or (at your option)
  13 * any later version.
  14 */
  15
  16#include "hid-uclogic-params.h"
  17#include "hid-uclogic-rdesc.h"
  18#include "usbhid/usbhid.h"
  19#include "hid-ids.h"
  20#include <linux/ctype.h>
  21#include <linux/string.h>
  22#include <asm/unaligned.h>
  23
  24/**
  25 * uclogic_params_pen_inrange_to_str() - Convert a pen in-range reporting type
  26 *                                       to a string.
  27 * @inrange:	The in-range reporting type to convert.
  28 *
  29 * Return:
  30 * * The string representing the type, or
  31 * * %NULL if the type is unknown.
  32 */
  33static const char *uclogic_params_pen_inrange_to_str(
  34				enum uclogic_params_pen_inrange inrange)
  35{
  36	switch (inrange) {
  37	case UCLOGIC_PARAMS_PEN_INRANGE_NORMAL:
  38		return "normal";
  39	case UCLOGIC_PARAMS_PEN_INRANGE_INVERTED:
  40		return "inverted";
  41	case UCLOGIC_PARAMS_PEN_INRANGE_NONE:
  42		return "none";
  43	default:
  44		return NULL;
  45	}
  46}
  47
  48/**
  49 * uclogic_params_pen_hid_dbg() - Dump tablet interface pen parameters
  50 * @hdev:	The HID device the pen parameters describe.
  51 * @pen:	The pen parameters to dump.
  52 *
  53 * Dump tablet interface pen parameters with hid_dbg(). The dump is indented
  54 * with a tab.
  55 */
  56static void uclogic_params_pen_hid_dbg(const struct hid_device *hdev,
  57					const struct uclogic_params_pen *pen)
  58{
  59	size_t i;
  60
  61	hid_dbg(hdev, "\t.usage_invalid = %s\n",
  62		(pen->usage_invalid ? "true" : "false"));
  63	hid_dbg(hdev, "\t.desc_ptr = %p\n", pen->desc_ptr);
  64	hid_dbg(hdev, "\t.desc_size = %u\n", pen->desc_size);
  65	hid_dbg(hdev, "\t.id = %u\n", pen->id);
  66	hid_dbg(hdev, "\t.subreport_list = {\n");
  67	for (i = 0; i < ARRAY_SIZE(pen->subreport_list); i++) {
  68		hid_dbg(hdev, "\t\t{0x%02hhx, %hhu}%s\n",
  69			pen->subreport_list[i].value,
  70			pen->subreport_list[i].id,
  71			i < (ARRAY_SIZE(pen->subreport_list) - 1) ? "," : "");
  72	}
  73	hid_dbg(hdev, "\t}\n");
  74	hid_dbg(hdev, "\t.inrange = %s\n",
  75		uclogic_params_pen_inrange_to_str(pen->inrange));
  76	hid_dbg(hdev, "\t.fragmented_hires = %s\n",
  77		(pen->fragmented_hires ? "true" : "false"));
  78	hid_dbg(hdev, "\t.tilt_y_flipped = %s\n",
  79		(pen->tilt_y_flipped ? "true" : "false"));
  80}
  81
  82/**
  83 * uclogic_params_frame_hid_dbg() - Dump tablet interface frame parameters
  84 * @hdev:	The HID device the pen parameters describe.
  85 * @frame:	The frame parameters to dump.
  86 *
  87 * Dump tablet interface frame parameters with hid_dbg(). The dump is
  88 * indented with two tabs.
  89 */
  90static void uclogic_params_frame_hid_dbg(
  91				const struct hid_device *hdev,
  92				const struct uclogic_params_frame *frame)
  93{
  94	hid_dbg(hdev, "\t\t.desc_ptr = %p\n", frame->desc_ptr);
  95	hid_dbg(hdev, "\t\t.desc_size = %u\n", frame->desc_size);
  96	hid_dbg(hdev, "\t\t.id = %u\n", frame->id);
  97	hid_dbg(hdev, "\t\t.suffix = %s\n", frame->suffix);
  98	hid_dbg(hdev, "\t\t.re_lsb = %u\n", frame->re_lsb);
  99	hid_dbg(hdev, "\t\t.dev_id_byte = %u\n", frame->dev_id_byte);
 100	hid_dbg(hdev, "\t\t.touch_byte = %u\n", frame->touch_byte);
 101	hid_dbg(hdev, "\t\t.touch_max = %hhd\n", frame->touch_max);
 102	hid_dbg(hdev, "\t\t.touch_flip_at = %hhd\n",
 103		frame->touch_flip_at);
 104	hid_dbg(hdev, "\t\t.bitmap_dial_byte = %u\n",
 105		frame->bitmap_dial_byte);
 106}
 107
 108/**
 109 * uclogic_params_hid_dbg() - Dump tablet interface parameters
 110 * @hdev:	The HID device the parameters describe.
 111 * @params:	The parameters to dump.
 112 *
 113 * Dump tablet interface parameters with hid_dbg().
 114 */
 115void uclogic_params_hid_dbg(const struct hid_device *hdev,
 116				const struct uclogic_params *params)
 117{
 118	size_t i;
 119
 120	hid_dbg(hdev, ".invalid = %s\n",
 121		params->invalid ? "true" : "false");
 122	hid_dbg(hdev, ".desc_ptr = %p\n", params->desc_ptr);
 123	hid_dbg(hdev, ".desc_size = %u\n", params->desc_size);
 124	hid_dbg(hdev, ".pen = {\n");
 125	uclogic_params_pen_hid_dbg(hdev, &params->pen);
 126	hid_dbg(hdev, "\t}\n");
 127	hid_dbg(hdev, ".frame_list = {\n");
 128	for (i = 0; i < ARRAY_SIZE(params->frame_list); i++) {
 129		hid_dbg(hdev, "\t{\n");
 130		uclogic_params_frame_hid_dbg(hdev, &params->frame_list[i]);
 131		hid_dbg(hdev, "\t}%s\n",
 132			i < (ARRAY_SIZE(params->frame_list) - 1) ? "," : "");
 133	}
 134	hid_dbg(hdev, "}\n");
 135}
 136
 137/**
 138 * uclogic_params_get_str_desc - retrieve a string descriptor from a HID
 139 * device interface, putting it into a kmalloc-allocated buffer as is, without
 140 * character encoding conversion.
 141 *
 142 * @pbuf:	Location for the kmalloc-allocated buffer pointer containing
 143 *		the retrieved descriptor. Not modified in case of error.
 144 *		Can be NULL to have retrieved descriptor discarded.
 145 * @hdev:	The HID device of the tablet interface to retrieve the string
 146 *		descriptor from. Cannot be NULL.
 147 * @idx:	Index of the string descriptor to request from the device.
 148 * @len:	Length of the buffer to allocate and the data to retrieve.
 149 *
 150 * Returns:
 151 *	number of bytes retrieved (<= len),
 152 *	-EPIPE, if the descriptor was not found, or
 153 *	another negative errno code in case of other error.
 154 */
 155static int uclogic_params_get_str_desc(__u8 **pbuf, struct hid_device *hdev,
 156					__u8 idx, size_t len)
 157{
 158	int rc;
 159	struct usb_device *udev;
 160	__u8 *buf = NULL;
 161
 162	/* Check arguments */
 163	if (hdev == NULL) {
 164		rc = -EINVAL;
 165		goto cleanup;
 166	}
 167
 168	udev = hid_to_usb_dev(hdev);
 169
 170	buf = kmalloc(len, GFP_KERNEL);
 171	if (buf == NULL) {
 172		rc = -ENOMEM;
 173		goto cleanup;
 174	}
 175
 176	rc = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
 177				USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
 178				(USB_DT_STRING << 8) + idx,
 179				0x0409, buf, len,
 180				USB_CTRL_GET_TIMEOUT);
 181	if (rc == -EPIPE) {
 182		hid_dbg(hdev, "string descriptor #%hhu not found\n", idx);
 183		goto cleanup;
 184	} else if (rc < 0) {
 185		hid_err(hdev,
 186			"failed retrieving string descriptor #%u: %d\n",
 187			idx, rc);
 188		goto cleanup;
 189	}
 190
 191	if (pbuf != NULL) {
 192		*pbuf = buf;
 193		buf = NULL;
 194	}
 195
 196cleanup:
 197	kfree(buf);
 198	return rc;
 199}
 200
 201/**
 202 * uclogic_params_pen_cleanup - free resources used by struct
 203 * uclogic_params_pen (tablet interface's pen input parameters).
 204 * Can be called repeatedly.
 205 *
 206 * @pen:	Pen input parameters to cleanup. Cannot be NULL.
 207 */
 208static void uclogic_params_pen_cleanup(struct uclogic_params_pen *pen)
 209{
 210	kfree(pen->desc_ptr);
 211	memset(pen, 0, sizeof(*pen));
 212}
 213
 214/**
 215 * uclogic_params_pen_init_v1() - initialize tablet interface pen
 216 * input and retrieve its parameters from the device, using v1 protocol.
 217 *
 218 * @pen:	Pointer to the pen parameters to initialize (to be
 219 *		cleaned up with uclogic_params_pen_cleanup()). Not modified in
 220 *		case of error, or if parameters are not found. Cannot be NULL.
 221 * @pfound:	Location for a flag which is set to true if the parameters
 222 *		were found, and to false if not (e.g. device was
 223 *		incompatible). Not modified in case of error. Cannot be NULL.
 224 * @hdev:	The HID device of the tablet interface to initialize and get
 225 *		parameters from. Cannot be NULL.
 226 *
 227 * Returns:
 228 *	Zero, if successful. A negative errno code on error.
 229 */
 230static int uclogic_params_pen_init_v1(struct uclogic_params_pen *pen,
 231				      bool *pfound,
 232				      struct hid_device *hdev)
 233{
 234	int rc;
 235	bool found = false;
 236	/* Buffer for (part of) the string descriptor */
 237	__u8 *buf = NULL;
 238	/* Minimum descriptor length required, maximum seen so far is 18 */
 239	const int len = 12;
 240	s32 resolution;
 241	/* Pen report descriptor template parameters */
 242	s32 desc_params[UCLOGIC_RDESC_PH_ID_NUM];
 243	__u8 *desc_ptr = NULL;
 244
 245	/* Check arguments */
 246	if (pen == NULL || pfound == NULL || hdev == NULL) {
 247		rc = -EINVAL;
 248		goto cleanup;
 249	}
 250
 251	/*
 252	 * Read string descriptor containing pen input parameters.
 253	 * The specific string descriptor and data were discovered by sniffing
 254	 * the Windows driver traffic.
 255	 * NOTE: This enables fully-functional tablet mode.
 256	 */
 257	rc = uclogic_params_get_str_desc(&buf, hdev, 100, len);
 258	if (rc == -EPIPE) {
 259		hid_dbg(hdev,
 260			"string descriptor with pen parameters not found, assuming not compatible\n");
 261		goto finish;
 262	} else if (rc < 0) {
 263		hid_err(hdev, "failed retrieving pen parameters: %d\n", rc);
 264		goto cleanup;
 265	} else if (rc != len) {
 266		hid_dbg(hdev,
 267			"string descriptor with pen parameters has invalid length (got %d, expected %d), assuming not compatible\n",
 268			rc, len);
 269		goto finish;
 270	}
 271
 272	/*
 273	 * Fill report descriptor parameters from the string descriptor
 274	 */
 275	desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_LM] =
 276		get_unaligned_le16(buf + 2);
 277	desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] =
 278		get_unaligned_le16(buf + 4);
 279	desc_params[UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM] =
 280		get_unaligned_le16(buf + 8);
 281	resolution = get_unaligned_le16(buf + 10);
 282	if (resolution == 0) {
 283		desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_PM] = 0;
 284		desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM] = 0;
 285	} else {
 286		desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_PM] =
 287			desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_LM] * 1000 /
 288			resolution;
 289		desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM] =
 290			desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] * 1000 /
 291			resolution;
 292	}
 293	kfree(buf);
 294	buf = NULL;
 295
 296	/*
 297	 * Generate pen report descriptor
 298	 */
 299	desc_ptr = uclogic_rdesc_template_apply(
 300				uclogic_rdesc_v1_pen_template_arr,
 301				uclogic_rdesc_v1_pen_template_size,
 302				desc_params, ARRAY_SIZE(desc_params));
 303	if (desc_ptr == NULL) {
 304		rc = -ENOMEM;
 305		goto cleanup;
 306	}
 307
 308	/*
 309	 * Fill-in the parameters
 310	 */
 311	memset(pen, 0, sizeof(*pen));
 312	pen->desc_ptr = desc_ptr;
 313	desc_ptr = NULL;
 314	pen->desc_size = uclogic_rdesc_v1_pen_template_size;
 315	pen->id = UCLOGIC_RDESC_V1_PEN_ID;
 316	pen->inrange = UCLOGIC_PARAMS_PEN_INRANGE_INVERTED;
 317	found = true;
 318finish:
 319	*pfound = found;
 320	rc = 0;
 321cleanup:
 322	kfree(desc_ptr);
 323	kfree(buf);
 324	return rc;
 325}
 326
 327/**
 328 * uclogic_params_get_le24() - get a 24-bit little-endian number from a
 329 * buffer.
 330 *
 331 * @p:	The pointer to the number buffer.
 332 *
 333 * Returns:
 334 *	The retrieved number
 335 */
 336static s32 uclogic_params_get_le24(const void *p)
 337{
 338	const __u8 *b = p;
 339	return b[0] | (b[1] << 8UL) | (b[2] << 16UL);
 340}
 341
 342/**
 343 * uclogic_params_pen_init_v2() - initialize tablet interface pen
 344 * input and retrieve its parameters from the device, using v2 protocol.
 345 *
 346 * @pen:		Pointer to the pen parameters to initialize (to be
 347 *			cleaned up with uclogic_params_pen_cleanup()). Not
 348 *			modified in case of error, or if parameters are not
 349 *			found. Cannot be NULL.
 350 * @pfound:		Location for a flag which is set to true if the
 351 *			parameters were found, and to false if not (e.g.
 352 *			device was incompatible). Not modified in case of
 353 *			error. Cannot be NULL.
 354 * @pparams_ptr:	Location for a kmalloc'ed pointer to the retrieved raw
 355 *			parameters, which could be used to identify the tablet
 356 *			to some extent. Should be freed with kfree after use.
 357 *			NULL, if not needed. Not modified in case of error.
 358 *			Only set if *pfound is set to true.
 359 * @pparams_len:	Location for the length of the retrieved raw
 360 *			parameters. NULL, if not needed. Not modified in case
 361 *			of error. Only set if *pfound is set to true.
 362 * @hdev:		The HID device of the tablet interface to initialize
 363 *			and get parameters from. Cannot be NULL.
 364 *
 365 * Returns:
 366 *	Zero, if successful. A negative errno code on error.
 367 */
 368static int uclogic_params_pen_init_v2(struct uclogic_params_pen *pen,
 369					bool *pfound,
 370					__u8 **pparams_ptr,
 371					size_t *pparams_len,
 372					struct hid_device *hdev)
 373{
 374	int rc;
 375	bool found = false;
 376	/* Buffer for (part of) the parameter string descriptor */
 377	__u8 *buf = NULL;
 378	/* Parameter string descriptor required length */
 379	const int params_len_min = 18;
 380	/* Parameter string descriptor accepted length */
 381	const int params_len_max = 32;
 382	/* Parameter string descriptor received length */
 383	int params_len;
 384	size_t i;
 385	s32 resolution;
 386	/* Pen report descriptor template parameters */
 387	s32 desc_params[UCLOGIC_RDESC_PH_ID_NUM];
 388	__u8 *desc_ptr = NULL;
 389
 390	/* Check arguments */
 391	if (pen == NULL || pfound == NULL || hdev == NULL) {
 392		rc = -EINVAL;
 393		goto cleanup;
 394	}
 395
 396	/*
 397	 * Read string descriptor containing pen input parameters.
 398	 * The specific string descriptor and data were discovered by sniffing
 399	 * the Windows driver traffic.
 400	 * NOTE: This enables fully-functional tablet mode.
 401	 */
 402	rc = uclogic_params_get_str_desc(&buf, hdev, 200, params_len_max);
 403	if (rc == -EPIPE) {
 404		hid_dbg(hdev,
 405			"string descriptor with pen parameters not found, assuming not compatible\n");
 406		goto finish;
 407	} else if (rc < 0) {
 408		hid_err(hdev, "failed retrieving pen parameters: %d\n", rc);
 409		goto cleanup;
 410	} else if (rc < params_len_min) {
 411		hid_dbg(hdev,
 412			"string descriptor with pen parameters is too short (got %d, expected at least %d), assuming not compatible\n",
 413			rc, params_len_min);
 414		goto finish;
 415	}
 416
 417	params_len = rc;
 418
 419	/*
 420	 * Check it's not just a catch-all UTF-16LE-encoded ASCII
 421	 * string (such as the model name) some tablets put into all
 422	 * unknown string descriptors.
 423	 */
 424	for (i = 2;
 425	     i < params_len &&
 426		(buf[i] >= 0x20 && buf[i] < 0x7f && buf[i + 1] == 0);
 427	     i += 2);
 428	if (i >= params_len) {
 429		hid_dbg(hdev,
 430			"string descriptor with pen parameters seems to contain only text, assuming not compatible\n");
 431		goto finish;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 432	}
 433
 434	/*
 435	 * Fill report descriptor parameters from the string descriptor
 436	 */
 437	desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_LM] =
 438		uclogic_params_get_le24(buf + 2);
 439	desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] =
 440		uclogic_params_get_le24(buf + 5);
 441	desc_params[UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM] =
 442		get_unaligned_le16(buf + 8);
 443	resolution = get_unaligned_le16(buf + 10);
 444	if (resolution == 0) {
 445		desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_PM] = 0;
 446		desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM] = 0;
 447	} else {
 448		desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_PM] =
 449			desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_LM] * 1000 /
 450			resolution;
 451		desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM] =
 452			desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] * 1000 /
 453			resolution;
 454	}
 
 
 455
 456	/*
 457	 * Generate pen report descriptor
 458	 */
 459	desc_ptr = uclogic_rdesc_template_apply(
 460				uclogic_rdesc_v2_pen_template_arr,
 461				uclogic_rdesc_v2_pen_template_size,
 462				desc_params, ARRAY_SIZE(desc_params));
 463	if (desc_ptr == NULL) {
 464		rc = -ENOMEM;
 465		goto cleanup;
 466	}
 467
 468	/*
 469	 * Fill-in the parameters
 470	 */
 471	memset(pen, 0, sizeof(*pen));
 472	pen->desc_ptr = desc_ptr;
 473	desc_ptr = NULL;
 474	pen->desc_size = uclogic_rdesc_v2_pen_template_size;
 475	pen->id = UCLOGIC_RDESC_V2_PEN_ID;
 476	pen->inrange = UCLOGIC_PARAMS_PEN_INRANGE_NONE;
 477	pen->fragmented_hires = true;
 478	pen->tilt_y_flipped = true;
 479	found = true;
 480	if (pparams_ptr != NULL) {
 481		*pparams_ptr = buf;
 482		buf = NULL;
 483	}
 484	if (pparams_len != NULL)
 485		*pparams_len = params_len;
 486
 487finish:
 488	*pfound = found;
 489	rc = 0;
 490cleanup:
 491	kfree(desc_ptr);
 492	kfree(buf);
 493	return rc;
 494}
 495
 496/**
 497 * uclogic_params_frame_cleanup - free resources used by struct
 498 * uclogic_params_frame (tablet interface's frame controls input parameters).
 499 * Can be called repeatedly.
 500 *
 501 * @frame:	Frame controls input parameters to cleanup. Cannot be NULL.
 502 */
 503static void uclogic_params_frame_cleanup(struct uclogic_params_frame *frame)
 504{
 505	kfree(frame->desc_ptr);
 506	memset(frame, 0, sizeof(*frame));
 507}
 508
 509/**
 510 * uclogic_params_frame_init_with_desc() - initialize tablet's frame control
 511 * parameters with a static report descriptor.
 512 *
 513 * @frame:	Pointer to the frame parameters to initialize (to be cleaned
 514 *		up with uclogic_params_frame_cleanup()). Not modified in case
 515 *		of error. Cannot be NULL.
 516 * @desc_ptr:	Report descriptor pointer. Can be NULL, if desc_size is zero.
 517 * @desc_size:	Report descriptor size.
 518 * @id:		Report ID used for frame reports, if they should be tweaked,
 519 *		zero if not.
 520 *
 521 * Returns:
 522 *	Zero, if successful. A negative errno code on error.
 523 */
 524static int uclogic_params_frame_init_with_desc(
 525					struct uclogic_params_frame *frame,
 526					const __u8 *desc_ptr,
 527					size_t desc_size,
 528					unsigned int id)
 529{
 530	__u8 *copy_desc_ptr;
 531
 532	if (frame == NULL || (desc_ptr == NULL && desc_size != 0))
 533		return -EINVAL;
 534
 535	copy_desc_ptr = kmemdup(desc_ptr, desc_size, GFP_KERNEL);
 536	if (copy_desc_ptr == NULL)
 537		return -ENOMEM;
 538
 539	memset(frame, 0, sizeof(*frame));
 540	frame->desc_ptr = copy_desc_ptr;
 541	frame->desc_size = desc_size;
 542	frame->id = id;
 543	return 0;
 544}
 545
 546/**
 547 * uclogic_params_frame_init_v1() - initialize v1 tablet interface frame
 548 * controls.
 549 *
 550 * @frame:	Pointer to the frame parameters to initialize (to be cleaned
 551 *		up with uclogic_params_frame_cleanup()). Not modified in case
 552 *		of error, or if parameters are not found. Cannot be NULL.
 553 * @pfound:	Location for a flag which is set to true if the parameters
 554 *		were found, and to false if not (e.g. device was
 555 *		incompatible). Not modified in case of error. Cannot be NULL.
 556 * @hdev:	The HID device of the tablet interface to initialize and get
 557 *		parameters from. Cannot be NULL.
 558 *
 559 * Returns:
 560 *	Zero, if successful. A negative errno code on error.
 561 */
 562static int uclogic_params_frame_init_v1(struct uclogic_params_frame *frame,
 
 563					bool *pfound,
 564					struct hid_device *hdev)
 565{
 566	int rc;
 567	bool found = false;
 568	struct usb_device *usb_dev;
 569	char *str_buf = NULL;
 570	const size_t str_len = 16;
 571
 572	/* Check arguments */
 573	if (frame == NULL || pfound == NULL || hdev == NULL) {
 574		rc = -EINVAL;
 575		goto cleanup;
 576	}
 577
 578	usb_dev = hid_to_usb_dev(hdev);
 579
 580	/*
 581	 * Enable generic button mode
 582	 */
 583	str_buf = kzalloc(str_len, GFP_KERNEL);
 584	if (str_buf == NULL) {
 585		rc = -ENOMEM;
 586		goto cleanup;
 587	}
 588
 589	rc = usb_string(usb_dev, 123, str_buf, str_len);
 590	if (rc == -EPIPE) {
 591		hid_dbg(hdev,
 592			"generic button -enabling string descriptor not found\n");
 593	} else if (rc < 0) {
 594		goto cleanup;
 595	} else if (strncmp(str_buf, "HK On", rc) != 0) {
 596		hid_dbg(hdev,
 597			"invalid response to enabling generic buttons: \"%s\"\n",
 598			str_buf);
 599	} else {
 600		hid_dbg(hdev, "generic buttons enabled\n");
 601		rc = uclogic_params_frame_init_with_desc(
 602				frame,
 603				uclogic_rdesc_v1_frame_arr,
 604				uclogic_rdesc_v1_frame_size,
 605				UCLOGIC_RDESC_V1_FRAME_ID);
 606		if (rc != 0)
 607			goto cleanup;
 608		found = true;
 609	}
 610
 611	*pfound = found;
 612	rc = 0;
 613cleanup:
 614	kfree(str_buf);
 615	return rc;
 616}
 617
 618/**
 619 * uclogic_params_cleanup - free resources used by struct uclogic_params
 620 * (tablet interface's parameters).
 621 * Can be called repeatedly.
 622 *
 623 * @params:	Input parameters to cleanup. Cannot be NULL.
 624 */
 625void uclogic_params_cleanup(struct uclogic_params *params)
 626{
 627	if (!params->invalid) {
 628		size_t i;
 629		kfree(params->desc_ptr);
 630		uclogic_params_pen_cleanup(&params->pen);
 631		for (i = 0; i < ARRAY_SIZE(params->frame_list); i++)
 632			uclogic_params_frame_cleanup(&params->frame_list[i]);
 633
 634		memset(params, 0, sizeof(*params));
 635	}
 636}
 637
 638/**
 639 * uclogic_params_get_desc() - Get a replacement report descriptor for a
 640 *                             tablet's interface.
 641 *
 642 * @params:	The parameters of a tablet interface to get report
 643 *		descriptor for. Cannot be NULL.
 644 * @pdesc:	Location for the resulting, kmalloc-allocated report
 645 *		descriptor pointer, or for NULL, if there's no replacement
 646 *		report descriptor. Not modified in case of error. Cannot be
 647 *		NULL.
 648 * @psize:	Location for the resulting report descriptor size, not set if
 649 *		there's no replacement report descriptor. Not modified in case
 650 *		of error. Cannot be NULL.
 651 *
 652 * Returns:
 653 *	Zero, if successful.
 654 *	-EINVAL, if invalid arguments are supplied.
 655 *	-ENOMEM, if failed to allocate memory.
 656 */
 657int uclogic_params_get_desc(const struct uclogic_params *params,
 658				__u8 **pdesc,
 659				unsigned int *psize)
 660{
 661	int rc = -ENOMEM;
 662	bool present = false;
 663	unsigned int size = 0;
 
 664	__u8 *desc = NULL;
 665	size_t i;
 666
 667	/* Check arguments */
 668	if (params == NULL || pdesc == NULL || psize == NULL)
 669		return -EINVAL;
 670
 671	/* Concatenate descriptors */
 672#define ADD_DESC(_desc_ptr, _desc_size) \
 673	do {                                                        \
 674		unsigned int new_size;                              \
 675		__u8 *new_desc;                                     \
 676		if ((_desc_ptr) == NULL) {                          \
 677			break;                                      \
 678		}                                                   \
 679		new_size = size + (_desc_size);                     \
 680		new_desc = krealloc(desc, new_size, GFP_KERNEL);    \
 681		if (new_desc == NULL) {                             \
 682			goto cleanup;                               \
 683		}                                                   \
 684		memcpy(new_desc + size, (_desc_ptr), (_desc_size)); \
 685		desc = new_desc;                                    \
 686		size = new_size;                                    \
 687		present = true;                                     \
 688	} while (0)
 689
 690	ADD_DESC(params->desc_ptr, params->desc_size);
 691	ADD_DESC(params->pen.desc_ptr, params->pen.desc_size);
 692	for (i = 0; i < ARRAY_SIZE(params->frame_list); i++) {
 693		ADD_DESC(params->frame_list[i].desc_ptr,
 694				params->frame_list[i].desc_size);
 695	}
 
 
 
 
 
 
 
 
 
 
 
 696
 697#undef ADD_DESC
 698
 699	if (present) {
 700		*pdesc = desc;
 701		*psize = size;
 702		desc = NULL;
 703	}
 704	rc = 0;
 705cleanup:
 706	kfree(desc);
 707	return rc;
 708}
 709
 710/**
 711 * uclogic_params_init_invalid() - initialize tablet interface parameters,
 712 * specifying the interface is invalid.
 713 *
 714 * @params:		Parameters to initialize (to be cleaned with
 715 *			uclogic_params_cleanup()). Cannot be NULL.
 716 */
 717static void uclogic_params_init_invalid(struct uclogic_params *params)
 718{
 719	params->invalid = true;
 720}
 721
 722/**
 723 * uclogic_params_init_with_opt_desc() - initialize tablet interface
 724 * parameters with an optional replacement report descriptor. Only modify
 725 * report descriptor, if the original report descriptor matches the expected
 726 * size.
 727 *
 728 * @params:		Parameters to initialize (to be cleaned with
 729 *			uclogic_params_cleanup()). Not modified in case of
 730 *			error. Cannot be NULL.
 731 * @hdev:		The HID device of the tablet interface create the
 732 *			parameters for. Cannot be NULL.
 733 * @orig_desc_size:	Expected size of the original report descriptor to
 734 *			be replaced.
 735 * @desc_ptr:		Pointer to the replacement report descriptor.
 736 *			Can be NULL, if desc_size is zero.
 737 * @desc_size:		Size of the replacement report descriptor.
 738 *
 739 * Returns:
 740 *	Zero, if successful. -EINVAL if an invalid argument was passed.
 741 *	-ENOMEM, if failed to allocate memory.
 742 */
 743static int uclogic_params_init_with_opt_desc(struct uclogic_params *params,
 744					     struct hid_device *hdev,
 745					     unsigned int orig_desc_size,
 746					     __u8 *desc_ptr,
 747					     unsigned int desc_size)
 748{
 749	__u8 *desc_copy_ptr = NULL;
 750	unsigned int desc_copy_size;
 751	int rc;
 752
 753	/* Check arguments */
 754	if (params == NULL || hdev == NULL ||
 755	    (desc_ptr == NULL && desc_size != 0)) {
 756		rc = -EINVAL;
 757		goto cleanup;
 758	}
 759
 760	/* Replace report descriptor, if it matches */
 761	if (hdev->dev_rsize == orig_desc_size) {
 762		hid_dbg(hdev,
 763			"device report descriptor matches the expected size, replacing\n");
 764		desc_copy_ptr = kmemdup(desc_ptr, desc_size, GFP_KERNEL);
 765		if (desc_copy_ptr == NULL) {
 766			rc = -ENOMEM;
 767			goto cleanup;
 768		}
 769		desc_copy_size = desc_size;
 770	} else {
 771		hid_dbg(hdev,
 772			"device report descriptor doesn't match the expected size (%u != %u), preserving\n",
 773			hdev->dev_rsize, orig_desc_size);
 774		desc_copy_ptr = NULL;
 775		desc_copy_size = 0;
 776	}
 777
 778	/* Output parameters */
 779	memset(params, 0, sizeof(*params));
 780	params->desc_ptr = desc_copy_ptr;
 781	desc_copy_ptr = NULL;
 782	params->desc_size = desc_copy_size;
 783
 784	rc = 0;
 785cleanup:
 786	kfree(desc_copy_ptr);
 787	return rc;
 788}
 789
 790/**
 791 * uclogic_params_huion_init() - initialize a Huion tablet interface and discover
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 792 * its parameters.
 793 *
 794 * @params:	Parameters to fill in (to be cleaned with
 795 *		uclogic_params_cleanup()). Not modified in case of error.
 796 *		Cannot be NULL.
 797 * @hdev:	The HID device of the tablet interface to initialize and get
 798 *		parameters from. Cannot be NULL.
 799 *
 800 * Returns:
 801 *	Zero, if successful. A negative errno code on error.
 802 */
 803static int uclogic_params_huion_init(struct uclogic_params *params,
 804				     struct hid_device *hdev)
 805{
 806	int rc;
 807	struct usb_device *udev;
 808	struct usb_interface *iface;
 809	__u8 bInterfaceNumber;
 810	bool found;
 811	/* The resulting parameters (noop) */
 812	struct uclogic_params p = {0, };
 813	static const char transition_ver[] = "HUION_T153_160607";
 814	char *ver_ptr = NULL;
 815	const size_t ver_len = sizeof(transition_ver) + 1;
 816	__u8 *params_ptr = NULL;
 817	size_t params_len = 0;
 818	/* Parameters string descriptor of a model with touch ring (HS610) */
 819	const __u8 touch_ring_model_params_buf[] = {
 820		0x13, 0x03, 0x70, 0xC6, 0x00, 0x06, 0x7C, 0x00,
 821		0xFF, 0x1F, 0xD8, 0x13, 0x03, 0x0D, 0x10, 0x01,
 822		0x04, 0x3C, 0x3E
 823	};
 824
 825	/* Check arguments */
 826	if (params == NULL || hdev == NULL) {
 827		rc = -EINVAL;
 828		goto cleanup;
 829	}
 830
 831	udev = hid_to_usb_dev(hdev);
 832	iface = to_usb_interface(hdev->dev.parent);
 833	bInterfaceNumber = iface->cur_altsetting->desc.bInterfaceNumber;
 834
 835	/* If it's a custom keyboard interface */
 836	if (bInterfaceNumber == 1) {
 837		/* Keep everything intact, but mark pen usage invalid */
 838		p.pen.usage_invalid = true;
 839		goto output;
 840	/* Else, if it's not a pen interface */
 841	} else if (bInterfaceNumber != 0) {
 842		uclogic_params_init_invalid(&p);
 843		goto output;
 844	}
 845
 846	/* Try to get firmware version */
 847	ver_ptr = kzalloc(ver_len, GFP_KERNEL);
 848	if (ver_ptr == NULL) {
 849		rc = -ENOMEM;
 850		goto cleanup;
 851	}
 852	rc = usb_string(udev, 201, ver_ptr, ver_len);
 853	if (rc == -EPIPE) {
 854		*ver_ptr = '\0';
 855	} else if (rc < 0) {
 856		hid_err(hdev,
 857			"failed retrieving Huion firmware version: %d\n", rc);
 858		goto cleanup;
 859	}
 860
 861	/* If this is a transition firmware */
 862	if (strcmp(ver_ptr, transition_ver) == 0) {
 863		hid_dbg(hdev,
 864			"transition firmware detected, not probing pen v2 parameters\n");
 865	} else {
 866		/* Try to probe v2 pen parameters */
 867		rc = uclogic_params_pen_init_v2(&p.pen, &found,
 868						&params_ptr, &params_len,
 869						hdev);
 870		if (rc != 0) {
 871			hid_err(hdev,
 872				"failed probing pen v2 parameters: %d\n", rc);
 873			goto cleanup;
 874		} else if (found) {
 875			hid_dbg(hdev, "pen v2 parameters found\n");
 876			/* Create v2 frame button parameters */
 877			rc = uclogic_params_frame_init_with_desc(
 878					&p.frame_list[0],
 879					uclogic_rdesc_v2_frame_buttons_arr,
 880					uclogic_rdesc_v2_frame_buttons_size,
 881					UCLOGIC_RDESC_V2_FRAME_BUTTONS_ID);
 882			if (rc != 0) {
 883				hid_err(hdev,
 884					"failed creating v2 frame button parameters: %d\n",
 885					rc);
 886				goto cleanup;
 887			}
 888
 889			/* Link from pen sub-report */
 890			p.pen.subreport_list[0].value = 0xe0;
 891			p.pen.subreport_list[0].id =
 892				UCLOGIC_RDESC_V2_FRAME_BUTTONS_ID;
 893
 894			/* If this is the model with touch ring */
 895			if (params_ptr != NULL &&
 896			    params_len == sizeof(touch_ring_model_params_buf) &&
 897			    memcmp(params_ptr, touch_ring_model_params_buf,
 898				   params_len) == 0) {
 899				/* Create touch ring parameters */
 900				rc = uclogic_params_frame_init_with_desc(
 901					&p.frame_list[1],
 902					uclogic_rdesc_v2_frame_touch_ring_arr,
 903					uclogic_rdesc_v2_frame_touch_ring_size,
 904					UCLOGIC_RDESC_V2_FRAME_TOUCH_ID);
 905				if (rc != 0) {
 906					hid_err(hdev,
 907						"failed creating v2 frame touch ring parameters: %d\n",
 908						rc);
 909					goto cleanup;
 910				}
 911				p.frame_list[1].suffix = "Touch Ring";
 912				p.frame_list[1].dev_id_byte =
 913					UCLOGIC_RDESC_V2_FRAME_TOUCH_DEV_ID_BYTE;
 914				p.frame_list[1].touch_byte = 5;
 915				p.frame_list[1].touch_max = 12;
 916				p.frame_list[1].touch_flip_at = 7;
 917			} else {
 918				/* Create touch strip parameters */
 919				rc = uclogic_params_frame_init_with_desc(
 920					&p.frame_list[1],
 921					uclogic_rdesc_v2_frame_touch_strip_arr,
 922					uclogic_rdesc_v2_frame_touch_strip_size,
 923					UCLOGIC_RDESC_V2_FRAME_TOUCH_ID);
 924				if (rc != 0) {
 925					hid_err(hdev,
 926						"failed creating v2 frame touch strip parameters: %d\n",
 927						rc);
 928					goto cleanup;
 929				}
 930				p.frame_list[1].suffix = "Touch Strip";
 931				p.frame_list[1].dev_id_byte =
 932					UCLOGIC_RDESC_V2_FRAME_TOUCH_DEV_ID_BYTE;
 933				p.frame_list[1].touch_byte = 5;
 934				p.frame_list[1].touch_max = 8;
 935			}
 936
 937			/* Link from pen sub-report */
 938			p.pen.subreport_list[1].value = 0xf0;
 939			p.pen.subreport_list[1].id =
 940				UCLOGIC_RDESC_V2_FRAME_TOUCH_ID;
 941
 942			/* Create v2 frame dial parameters */
 943			rc = uclogic_params_frame_init_with_desc(
 944					&p.frame_list[2],
 945					uclogic_rdesc_v2_frame_dial_arr,
 946					uclogic_rdesc_v2_frame_dial_size,
 947					UCLOGIC_RDESC_V2_FRAME_DIAL_ID);
 948			if (rc != 0) {
 949				hid_err(hdev,
 950					"failed creating v2 frame dial parameters: %d\n",
 951					rc);
 952				goto cleanup;
 953			}
 954			p.frame_list[2].suffix = "Dial";
 955			p.frame_list[2].dev_id_byte =
 956				UCLOGIC_RDESC_V2_FRAME_DIAL_DEV_ID_BYTE;
 957			p.frame_list[2].bitmap_dial_byte = 5;
 958
 959			/* Link from pen sub-report */
 960			p.pen.subreport_list[2].value = 0xf1;
 961			p.pen.subreport_list[2].id =
 962				UCLOGIC_RDESC_V2_FRAME_DIAL_ID;
 963
 964			goto output;
 965		}
 966		hid_dbg(hdev, "pen v2 parameters not found\n");
 967	}
 968
 969	/* Try to probe v1 pen parameters */
 970	rc = uclogic_params_pen_init_v1(&p.pen, &found, hdev);
 971	if (rc != 0) {
 972		hid_err(hdev,
 973			"failed probing pen v1 parameters: %d\n", rc);
 974		goto cleanup;
 975	} else if (found) {
 976		hid_dbg(hdev, "pen v1 parameters found\n");
 977		/* Try to probe v1 frame */
 978		rc = uclogic_params_frame_init_v1(&p.frame_list[0],
 979						  &found, hdev);
 
 980		if (rc != 0) {
 981			hid_err(hdev, "v1 frame probing failed: %d\n", rc);
 982			goto cleanup;
 983		}
 984		hid_dbg(hdev, "frame v1 parameters%s found\n",
 985			(found ? "" : " not"));
 986		if (found) {
 987			/* Link frame button subreports from pen reports */
 988			p.pen.subreport_list[0].value = 0xe0;
 989			p.pen.subreport_list[0].id =
 990				UCLOGIC_RDESC_V1_FRAME_ID;
 991		}
 992		goto output;
 993	}
 994	hid_dbg(hdev, "pen v1 parameters not found\n");
 995
 996	uclogic_params_init_invalid(&p);
 997
 998output:
 999	/* Output parameters */
1000	memcpy(params, &p, sizeof(*params));
1001	memset(&p, 0, sizeof(p));
1002	rc = 0;
1003cleanup:
1004	kfree(params_ptr);
1005	kfree(ver_ptr);
1006	uclogic_params_cleanup(&p);
1007	return rc;
1008}
1009
1010/**
1011 * uclogic_probe_interface() - some tablets, like the Parblo A610 PLUS V2 or
1012 * the XP-PEN Deco Mini 7, need to be initialized by sending them magic data.
1013 *
1014 * @hdev:	The HID device of the tablet interface to initialize and get
1015 *		parameters from. Cannot be NULL.
1016 * @magic_arr:	The magic data that should be sent to probe the interface.
1017 *		Cannot be NULL.
1018 * @magic_size:	Size of the magic data.
1019 * @endpoint:	Endpoint where the magic data should be sent.
1020 *
1021 * Returns:
1022 *	Zero, if successful. A negative errno code on error.
1023 */
1024static int uclogic_probe_interface(struct hid_device *hdev, u8 *magic_arr,
1025				   int magic_size, int endpoint)
1026{
1027	struct usb_device *udev;
1028	unsigned int pipe = 0;
1029	int sent;
1030	u8 *buf = NULL;
1031	int rc = 0;
1032
1033	if (!hdev || !magic_arr) {
1034		rc = -EINVAL;
1035		goto cleanup;
1036	}
1037
1038	buf = kmemdup(magic_arr, magic_size, GFP_KERNEL);
1039	if (!buf) {
1040		rc = -ENOMEM;
1041		goto cleanup;
1042	}
1043
1044	udev = hid_to_usb_dev(hdev);
1045	pipe = usb_sndintpipe(udev, endpoint);
1046
1047	rc = usb_interrupt_msg(udev, pipe, buf, magic_size, &sent, 1000);
1048	if (rc || sent != magic_size) {
1049		hid_err(hdev, "Interface probing failed: %d\n", rc);
1050		rc = -1;
1051		goto cleanup;
1052	}
1053
1054	rc = 0;
1055cleanup:
1056	kfree(buf);
1057	return rc;
1058}
1059
1060/**
1061 * uclogic_params_parse_ugee_v2_desc - parse the string descriptor containing
1062 * pen and frame parameters returned by UGEE v2 devices.
1063 *
1064 * @str_desc:		String descriptor, cannot be NULL.
1065 * @str_desc_size:	Size of the string descriptor.
1066 * @desc_params:	Output description params list.
1067 * @desc_params_size:	Size of the output description params list.
1068 * @frame_type:		Output frame type.
1069 *
1070 * Returns:
1071 *	Zero, if successful. A negative errno code on error.
1072 */
1073static int uclogic_params_parse_ugee_v2_desc(const __u8 *str_desc,
1074					     size_t str_desc_size,
1075					     s32 *desc_params,
1076					     size_t desc_params_size,
1077					     enum uclogic_params_frame_type *frame_type)
1078{
1079	s32 pen_x_lm, pen_y_lm;
1080	s32 pen_x_pm, pen_y_pm;
1081	s32 pen_pressure_lm;
1082	s32 frame_num_buttons;
1083	s32 resolution;
1084
1085	/* Minimum descriptor length required, maximum seen so far is 14 */
1086	const int min_str_desc_size = 12;
1087
1088	if (!str_desc || str_desc_size < min_str_desc_size)
1089		return -EINVAL;
1090
1091	if (desc_params_size != UCLOGIC_RDESC_PH_ID_NUM)
1092		return -EINVAL;
1093
1094	pen_x_lm = get_unaligned_le16(str_desc + 2);
1095	pen_y_lm = get_unaligned_le16(str_desc + 4);
1096	frame_num_buttons = str_desc[6];
1097	*frame_type = str_desc[7];
1098	pen_pressure_lm = get_unaligned_le16(str_desc + 8);
1099
1100	resolution = get_unaligned_le16(str_desc + 10);
1101	if (resolution == 0) {
1102		pen_x_pm = 0;
1103		pen_y_pm = 0;
1104	} else {
1105		pen_x_pm = pen_x_lm * 1000 / resolution;
1106		pen_y_pm = pen_y_lm * 1000 / resolution;
1107	}
1108
1109	desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_LM] = pen_x_lm;
1110	desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_PM] = pen_x_pm;
1111	desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] = pen_y_lm;
1112	desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM] = pen_y_pm;
1113	desc_params[UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM] = pen_pressure_lm;
1114	desc_params[UCLOGIC_RDESC_FRAME_PH_ID_UM] = frame_num_buttons;
1115
1116	return 0;
1117}
1118
1119/**
1120 * uclogic_params_ugee_v2_init_frame_buttons() - initialize a UGEE v2 frame with
1121 * buttons.
1122 * @p:			Parameters to fill in, cannot be NULL.
1123 * @desc_params:	Device description params list.
1124 * @desc_params_size:	Size of the description params list.
1125 *
1126 * Returns:
1127 *	Zero, if successful. A negative errno code on error.
1128 */
1129static int uclogic_params_ugee_v2_init_frame_buttons(struct uclogic_params *p,
1130						     const s32 *desc_params,
1131						     size_t desc_params_size)
1132{
1133	__u8 *rdesc_frame = NULL;
1134	int rc = 0;
1135
1136	if (!p || desc_params_size != UCLOGIC_RDESC_PH_ID_NUM)
1137		return -EINVAL;
1138
1139	rdesc_frame = uclogic_rdesc_template_apply(
1140				uclogic_rdesc_ugee_v2_frame_btn_template_arr,
1141				uclogic_rdesc_ugee_v2_frame_btn_template_size,
1142				desc_params, UCLOGIC_RDESC_PH_ID_NUM);
1143	if (!rdesc_frame)
1144		return -ENOMEM;
1145
1146	rc = uclogic_params_frame_init_with_desc(&p->frame_list[0],
1147						 rdesc_frame,
1148						 uclogic_rdesc_ugee_v2_frame_btn_template_size,
1149						 UCLOGIC_RDESC_V1_FRAME_ID);
1150	kfree(rdesc_frame);
1151	return rc;
1152}
1153
1154/**
1155 * uclogic_params_ugee_v2_init_frame_dial() - initialize a UGEE v2 frame with a
1156 * bitmap dial.
1157 * @p:			Parameters to fill in, cannot be NULL.
1158 * @desc_params:	Device description params list.
1159 * @desc_params_size:	Size of the description params list.
1160 *
1161 * Returns:
1162 *	Zero, if successful. A negative errno code on error.
1163 */
1164static int uclogic_params_ugee_v2_init_frame_dial(struct uclogic_params *p,
1165						  const s32 *desc_params,
1166						  size_t desc_params_size)
1167{
1168	__u8 *rdesc_frame = NULL;
1169	int rc = 0;
1170
1171	if (!p || desc_params_size != UCLOGIC_RDESC_PH_ID_NUM)
1172		return -EINVAL;
1173
1174	rdesc_frame = uclogic_rdesc_template_apply(
1175				uclogic_rdesc_ugee_v2_frame_dial_template_arr,
1176				uclogic_rdesc_ugee_v2_frame_dial_template_size,
1177				desc_params, UCLOGIC_RDESC_PH_ID_NUM);
1178	if (!rdesc_frame)
1179		return -ENOMEM;
1180
1181	rc = uclogic_params_frame_init_with_desc(&p->frame_list[0],
1182						 rdesc_frame,
1183						 uclogic_rdesc_ugee_v2_frame_dial_template_size,
1184						 UCLOGIC_RDESC_V1_FRAME_ID);
1185	kfree(rdesc_frame);
1186	if (rc)
1187		return rc;
1188
1189	p->frame_list[0].bitmap_dial_byte = 7;
1190	return 0;
1191}
1192
1193/**
1194 * uclogic_params_ugee_v2_init_frame_mouse() - initialize a UGEE v2 frame with a
1195 * mouse.
1196 * @p:			Parameters to fill in, cannot be NULL.
1197 *
1198 * Returns:
1199 *	Zero, if successful. A negative errno code on error.
1200 */
1201static int uclogic_params_ugee_v2_init_frame_mouse(struct uclogic_params *p)
1202{
1203	int rc = 0;
1204
1205	if (!p)
1206		return -EINVAL;
1207
1208	rc = uclogic_params_frame_init_with_desc(&p->frame_list[1],
1209						 uclogic_rdesc_ugee_v2_frame_mouse_template_arr,
1210						 uclogic_rdesc_ugee_v2_frame_mouse_template_size,
1211						 UCLOGIC_RDESC_V1_FRAME_ID);
1212	return rc;
1213}
1214
1215/**
1216 * uclogic_params_ugee_v2_has_battery() - check whether a UGEE v2 device has
1217 * battery or not.
1218 * @hdev:	The HID device of the tablet interface.
1219 *
1220 * Returns:
1221 *	True if the device has battery, false otherwise.
1222 */
1223static bool uclogic_params_ugee_v2_has_battery(struct hid_device *hdev)
1224{
1225	/* The XP-PEN Deco LW vendor, product and version are identical to the
1226	 * Deco L. The only difference reported by their firmware is the product
1227	 * name. Add a quirk to support battery reporting on the wireless
1228	 * version.
1229	 */
1230	if (hdev->vendor == USB_VENDOR_ID_UGEE &&
1231	    hdev->product == USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_L) {
1232		struct usb_device *udev = hid_to_usb_dev(hdev);
1233
1234		if (strstarts(udev->product, "Deco LW"))
1235			return true;
1236	}
1237
1238	return false;
1239}
1240
1241/**
1242 * uclogic_params_ugee_v2_init_battery() - initialize UGEE v2 battery reporting.
1243 * @hdev:	The HID device of the tablet interface, cannot be NULL.
1244 * @p:		Parameters to fill in, cannot be NULL.
1245 *
1246 * Returns:
1247 *	Zero, if successful. A negative errno code on error.
1248 */
1249static int uclogic_params_ugee_v2_init_battery(struct hid_device *hdev,
1250					       struct uclogic_params *p)
1251{
1252	int rc = 0;
1253
1254	if (!hdev || !p)
1255		return -EINVAL;
1256
1257	/* Some tablets contain invalid characters in hdev->uniq, throwing a
1258	 * "hwmon: '<name>' is not a valid name attribute, please fix" error.
1259	 * Use the device vendor and product IDs instead.
1260	 */
1261	snprintf(hdev->uniq, sizeof(hdev->uniq), "%x-%x", hdev->vendor,
1262		 hdev->product);
1263
1264	rc = uclogic_params_frame_init_with_desc(&p->frame_list[1],
1265						 uclogic_rdesc_ugee_v2_battery_template_arr,
1266						 uclogic_rdesc_ugee_v2_battery_template_size,
1267						 UCLOGIC_RDESC_UGEE_V2_BATTERY_ID);
1268	if (rc)
1269		return rc;
1270
1271	p->frame_list[1].suffix = "Battery";
1272	p->pen.subreport_list[1].value = 0xf2;
1273	p->pen.subreport_list[1].id = UCLOGIC_RDESC_UGEE_V2_BATTERY_ID;
1274
1275	return rc;
1276}
1277
1278/**
1279 * uclogic_params_ugee_v2_init() - initialize a UGEE graphics tablets by
1280 * discovering their parameters.
1281 *
1282 * These tables, internally designed as v2 to differentiate them from older
1283 * models, expect a payload of magic data in orther to be switched to the fully
1284 * functional mode and expose their parameters in a similar way to the
1285 * information present in uclogic_params_pen_init_v1() but with some
1286 * differences.
1287 *
1288 * @params:	Parameters to fill in (to be cleaned with
1289 *		uclogic_params_cleanup()). Not modified in case of error.
1290 *		Cannot be NULL.
1291 * @hdev:	The HID device of the tablet interface to initialize and get
1292 *		parameters from. Cannot be NULL.
1293 *
1294 * Returns:
1295 *	Zero, if successful. A negative errno code on error.
1296 */
1297static int uclogic_params_ugee_v2_init(struct uclogic_params *params,
1298				       struct hid_device *hdev)
1299{
1300	int rc = 0;
1301	struct usb_interface *iface;
1302	__u8 bInterfaceNumber;
1303	const int str_desc_len = 12;
1304	__u8 *str_desc = NULL;
1305	__u8 *rdesc_pen = NULL;
1306	s32 desc_params[UCLOGIC_RDESC_PH_ID_NUM];
1307	enum uclogic_params_frame_type frame_type;
1308	__u8 magic_arr[] = {
1309		0x02, 0xb0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
1310	};
1311	/* The resulting parameters (noop) */
1312	struct uclogic_params p = {0, };
1313
1314	if (!params || !hdev) {
1315		rc = -EINVAL;
1316		goto cleanup;
1317	}
1318
1319	iface = to_usb_interface(hdev->dev.parent);
1320	bInterfaceNumber = iface->cur_altsetting->desc.bInterfaceNumber;
1321
1322	if (bInterfaceNumber == 0) {
1323		rc = uclogic_params_ugee_v2_init_frame_mouse(&p);
1324		if (rc)
1325			goto cleanup;
1326
1327		goto output;
1328	}
1329
1330	if (bInterfaceNumber != 2) {
1331		uclogic_params_init_invalid(&p);
1332		goto output;
1333	}
1334
1335	/*
1336	 * Initialize the interface by sending magic data.
1337	 * The specific data was discovered by sniffing the Windows driver
1338	 * traffic.
1339	 */
1340	rc = uclogic_probe_interface(hdev, magic_arr, sizeof(magic_arr), 0x03);
1341	if (rc) {
1342		uclogic_params_init_invalid(&p);
1343		goto output;
1344	}
1345
1346	/*
1347	 * Read the string descriptor containing pen and frame parameters.
1348	 * The specific string descriptor and data were discovered by sniffing
1349	 * the Windows driver traffic.
1350	 */
1351	rc = uclogic_params_get_str_desc(&str_desc, hdev, 100, str_desc_len);
1352	if (rc != str_desc_len) {
1353		hid_err(hdev, "failed retrieving pen and frame parameters: %d\n", rc);
1354		uclogic_params_init_invalid(&p);
1355		goto output;
1356	}
1357
1358	rc = uclogic_params_parse_ugee_v2_desc(str_desc, str_desc_len,
1359					       desc_params,
1360					       ARRAY_SIZE(desc_params),
1361					       &frame_type);
1362	if (rc)
1363		goto cleanup;
1364
1365	kfree(str_desc);
1366	str_desc = NULL;
1367
1368	/* Initialize the pen interface */
1369	rdesc_pen = uclogic_rdesc_template_apply(
1370				uclogic_rdesc_ugee_v2_pen_template_arr,
1371				uclogic_rdesc_ugee_v2_pen_template_size,
1372				desc_params, ARRAY_SIZE(desc_params));
1373	if (!rdesc_pen) {
1374		rc = -ENOMEM;
1375		goto cleanup;
1376	}
1377
1378	p.pen.desc_ptr = rdesc_pen;
1379	p.pen.desc_size = uclogic_rdesc_ugee_v2_pen_template_size;
1380	p.pen.id = 0x02;
1381	p.pen.subreport_list[0].value = 0xf0;
1382	p.pen.subreport_list[0].id = UCLOGIC_RDESC_V1_FRAME_ID;
1383
1384	/* Initialize the frame interface */
1385	switch (frame_type) {
1386	case UCLOGIC_PARAMS_FRAME_DIAL:
1387	case UCLOGIC_PARAMS_FRAME_MOUSE:
1388		rc = uclogic_params_ugee_v2_init_frame_dial(&p, desc_params,
1389							    ARRAY_SIZE(desc_params));
1390		break;
1391	case UCLOGIC_PARAMS_FRAME_BUTTONS:
1392	default:
1393		rc = uclogic_params_ugee_v2_init_frame_buttons(&p, desc_params,
1394							       ARRAY_SIZE(desc_params));
1395		break;
1396	}
1397
1398	if (rc)
1399		goto cleanup;
1400
1401	/* Initialize the battery interface*/
1402	if (uclogic_params_ugee_v2_has_battery(hdev)) {
1403		rc = uclogic_params_ugee_v2_init_battery(hdev, &p);
1404		if (rc) {
1405			hid_err(hdev, "error initializing battery: %d\n", rc);
1406			goto cleanup;
1407		}
1408	}
1409
1410output:
1411	/* Output parameters */
1412	memcpy(params, &p, sizeof(*params));
1413	memset(&p, 0, sizeof(p));
1414	rc = 0;
1415cleanup:
1416	kfree(str_desc);
1417	uclogic_params_cleanup(&p);
1418	return rc;
1419}
1420
1421/**
1422 * uclogic_params_init() - initialize a tablet interface and discover its
1423 * parameters.
1424 *
1425 * @params:	Parameters to fill in (to be cleaned with
1426 *		uclogic_params_cleanup()). Not modified in case of error.
1427 *		Cannot be NULL.
1428 * @hdev:	The HID device of the tablet interface to initialize and get
1429 *		parameters from. Cannot be NULL. Must be using the USB low-level
1430 *		driver, i.e. be an actual USB tablet.
1431 *
1432 * Returns:
1433 *	Zero, if successful. A negative errno code on error.
1434 */
1435int uclogic_params_init(struct uclogic_params *params,
1436			struct hid_device *hdev)
1437{
1438	int rc;
1439	struct usb_device *udev;
1440	__u8  bNumInterfaces;
1441	struct usb_interface *iface;
1442	__u8 bInterfaceNumber;
1443	bool found;
1444	/* The resulting parameters (noop) */
1445	struct uclogic_params p = {0, };
1446
1447	/* Check arguments */
1448	if (params == NULL || hdev == NULL || !hid_is_usb(hdev)) {
 
1449		rc = -EINVAL;
1450		goto cleanup;
1451	}
1452
1453	udev = hid_to_usb_dev(hdev);
1454	bNumInterfaces = udev->config->desc.bNumInterfaces;
1455	iface = to_usb_interface(hdev->dev.parent);
1456	bInterfaceNumber = iface->cur_altsetting->desc.bInterfaceNumber;
1457
1458	/*
1459	 * Set replacement report descriptor if the original matches the
1460	 * specified size. Otherwise keep interface unchanged.
1461	 */
1462#define WITH_OPT_DESC(_orig_desc_token, _new_desc_token) \
1463	uclogic_params_init_with_opt_desc(                  \
1464		&p, hdev,                                   \
1465		UCLOGIC_RDESC_##_orig_desc_token##_SIZE,    \
1466		uclogic_rdesc_##_new_desc_token##_arr,      \
1467		uclogic_rdesc_##_new_desc_token##_size)
1468
1469#define VID_PID(_vid, _pid) \
1470	(((__u32)(_vid) << 16) | ((__u32)(_pid) & U16_MAX))
1471
1472	/*
1473	 * Handle specific interfaces for specific tablets.
1474	 *
1475	 * Observe the following logic:
1476	 *
1477	 * If the interface is recognized as producing certain useful input:
1478	 *	Mark interface as valid.
1479	 *	Output interface parameters.
1480	 * Else, if the interface is recognized as *not* producing any useful
1481	 * input:
1482	 *	Mark interface as invalid.
1483	 * Else:
1484	 *	Mark interface as valid.
1485	 *	Output noop parameters.
1486	 *
1487	 * Rule of thumb: it is better to disable a broken interface than let
1488	 *		  it spew garbage input.
1489	 */
1490
1491	switch (VID_PID(hdev->vendor, hdev->product)) {
1492	case VID_PID(USB_VENDOR_ID_UCLOGIC,
1493		     USB_DEVICE_ID_UCLOGIC_TABLET_PF1209):
1494		rc = WITH_OPT_DESC(PF1209_ORIG, pf1209_fixed);
1495		if (rc != 0)
1496			goto cleanup;
1497		break;
1498	case VID_PID(USB_VENDOR_ID_UCLOGIC,
1499		     USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U):
1500		rc = WITH_OPT_DESC(WPXXXXU_ORIG, wp4030u_fixed);
1501		if (rc != 0)
1502			goto cleanup;
1503		break;
1504	case VID_PID(USB_VENDOR_ID_UCLOGIC,
1505		     USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U):
1506		if (hdev->dev_rsize == UCLOGIC_RDESC_WP5540U_V2_ORIG_SIZE) {
1507			if (bInterfaceNumber == 0) {
1508				/* Try to probe v1 pen parameters */
1509				rc = uclogic_params_pen_init_v1(&p.pen,
1510								&found, hdev);
1511				if (rc != 0) {
1512					hid_err(hdev,
1513						"pen probing failed: %d\n",
1514						rc);
1515					goto cleanup;
1516				}
1517				if (!found) {
1518					hid_warn(hdev,
1519						 "pen parameters not found");
1520				}
1521			} else {
1522				uclogic_params_init_invalid(&p);
1523			}
1524		} else {
1525			rc = WITH_OPT_DESC(WPXXXXU_ORIG, wp5540u_fixed);
1526			if (rc != 0)
1527				goto cleanup;
1528		}
1529		break;
1530	case VID_PID(USB_VENDOR_ID_UCLOGIC,
1531		     USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U):
1532		rc = WITH_OPT_DESC(WPXXXXU_ORIG, wp8060u_fixed);
1533		if (rc != 0)
1534			goto cleanup;
1535		break;
1536	case VID_PID(USB_VENDOR_ID_UCLOGIC,
1537		     USB_DEVICE_ID_UCLOGIC_TABLET_WP1062):
1538		rc = WITH_OPT_DESC(WP1062_ORIG, wp1062_fixed);
1539		if (rc != 0)
1540			goto cleanup;
1541		break;
1542	case VID_PID(USB_VENDOR_ID_UCLOGIC,
1543		     USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850):
1544		switch (bInterfaceNumber) {
1545		case 0:
1546			rc = WITH_OPT_DESC(TWHL850_ORIG0, twhl850_fixed0);
1547			if (rc != 0)
1548				goto cleanup;
1549			break;
1550		case 1:
1551			rc = WITH_OPT_DESC(TWHL850_ORIG1, twhl850_fixed1);
1552			if (rc != 0)
1553				goto cleanup;
1554			break;
1555		case 2:
1556			rc = WITH_OPT_DESC(TWHL850_ORIG2, twhl850_fixed2);
1557			if (rc != 0)
1558				goto cleanup;
1559			break;
1560		}
1561		break;
1562	case VID_PID(USB_VENDOR_ID_UCLOGIC,
1563		     USB_DEVICE_ID_UCLOGIC_TABLET_TWHA60):
1564		/*
1565		 * If it is not a three-interface version, which is known to
1566		 * respond to initialization.
1567		 */
1568		if (bNumInterfaces != 3) {
1569			switch (bInterfaceNumber) {
1570			case 0:
1571				rc = WITH_OPT_DESC(TWHA60_ORIG0,
1572							twha60_fixed0);
1573				if (rc != 0)
1574					goto cleanup;
1575				break;
1576			case 1:
1577				rc = WITH_OPT_DESC(TWHA60_ORIG1,
1578							twha60_fixed1);
1579				if (rc != 0)
1580					goto cleanup;
1581				break;
1582			}
1583			break;
1584		}
1585		fallthrough;
1586	case VID_PID(USB_VENDOR_ID_HUION,
1587		     USB_DEVICE_ID_HUION_TABLET):
1588	case VID_PID(USB_VENDOR_ID_HUION,
1589		     USB_DEVICE_ID_HUION_TABLET2):
1590	case VID_PID(USB_VENDOR_ID_UCLOGIC,
1591		     USB_DEVICE_ID_HUION_TABLET):
1592	case VID_PID(USB_VENDOR_ID_UCLOGIC,
1593		     USB_DEVICE_ID_YIYNOVA_TABLET):
1594	case VID_PID(USB_VENDOR_ID_UCLOGIC,
1595		     USB_DEVICE_ID_UCLOGIC_UGEE_TABLET_81):
1596	case VID_PID(USB_VENDOR_ID_UCLOGIC,
1597		     USB_DEVICE_ID_UCLOGIC_DRAWIMAGE_G3):
1598	case VID_PID(USB_VENDOR_ID_UCLOGIC,
1599		     USB_DEVICE_ID_UCLOGIC_UGEE_TABLET_45):
1600	case VID_PID(USB_VENDOR_ID_UCLOGIC,
1601		     USB_DEVICE_ID_UCLOGIC_UGEE_TABLET_47):
1602		rc = uclogic_params_huion_init(&p, hdev);
1603		if (rc != 0)
1604			goto cleanup;
1605		break;
1606	case VID_PID(USB_VENDOR_ID_UGTIZER,
1607		     USB_DEVICE_ID_UGTIZER_TABLET_GP0610):
1608	case VID_PID(USB_VENDOR_ID_UGTIZER,
1609		     USB_DEVICE_ID_UGTIZER_TABLET_GT5040):
1610	case VID_PID(USB_VENDOR_ID_UGEE,
1611		     USB_DEVICE_ID_UGEE_XPPEN_TABLET_G540):
1612	case VID_PID(USB_VENDOR_ID_UGEE,
1613		     USB_DEVICE_ID_UGEE_XPPEN_TABLET_G640):
1614	case VID_PID(USB_VENDOR_ID_UGEE,
1615		     USB_DEVICE_ID_UGEE_XPPEN_TABLET_STAR06):
1616	case VID_PID(USB_VENDOR_ID_UGEE,
1617		     USB_DEVICE_ID_UGEE_TABLET_RAINBOW_CV720):
1618		/* If this is the pen interface */
1619		if (bInterfaceNumber == 1) {
1620			/* Probe v1 pen parameters */
1621			rc = uclogic_params_pen_init_v1(&p.pen, &found, hdev);
1622			if (rc != 0) {
1623				hid_err(hdev, "pen probing failed: %d\n", rc);
1624				goto cleanup;
1625			}
1626			if (!found) {
1627				hid_warn(hdev, "pen parameters not found");
1628				uclogic_params_init_invalid(&p);
1629			}
1630		} else {
1631			uclogic_params_init_invalid(&p);
 
1632		}
1633		break;
1634	case VID_PID(USB_VENDOR_ID_UGEE,
1635		     USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO01):
1636		/* If this is the pen and frame interface */
1637		if (bInterfaceNumber == 1) {
1638			/* Probe v1 pen parameters */
1639			rc = uclogic_params_pen_init_v1(&p.pen, &found, hdev);
1640			if (rc != 0) {
1641				hid_err(hdev, "pen probing failed: %d\n", rc);
1642				goto cleanup;
1643			}
1644			/* Initialize frame parameters */
1645			rc = uclogic_params_frame_init_with_desc(
1646				&p.frame_list[0],
1647				uclogic_rdesc_xppen_deco01_frame_arr,
1648				uclogic_rdesc_xppen_deco01_frame_size,
1649				0);
1650			if (rc != 0)
1651				goto cleanup;
1652		} else {
1653			uclogic_params_init_invalid(&p);
 
1654		}
1655		break;
1656	case VID_PID(USB_VENDOR_ID_UGEE,
1657		     USB_DEVICE_ID_UGEE_PARBLO_A610_PRO):
1658	case VID_PID(USB_VENDOR_ID_UGEE,
1659		     USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO01_V2):
1660	case VID_PID(USB_VENDOR_ID_UGEE,
1661		     USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_L):
1662	case VID_PID(USB_VENDOR_ID_UGEE,
1663		     USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_S):
1664		rc = uclogic_params_ugee_v2_init(&p, hdev);
1665		if (rc != 0)
1666			goto cleanup;
1667		break;
1668	case VID_PID(USB_VENDOR_ID_TRUST,
1669		     USB_DEVICE_ID_TRUST_PANORA_TABLET):
1670	case VID_PID(USB_VENDOR_ID_UGEE,
1671		     USB_DEVICE_ID_UGEE_TABLET_G5):
1672		/* Ignore non-pen interfaces */
1673		if (bInterfaceNumber != 1) {
1674			uclogic_params_init_invalid(&p);
1675			break;
1676		}
1677
1678		rc = uclogic_params_pen_init_v1(&p.pen, &found, hdev);
1679		if (rc != 0) {
1680			hid_err(hdev, "pen probing failed: %d\n", rc);
1681			goto cleanup;
1682		} else if (found) {
1683			rc = uclogic_params_frame_init_with_desc(
1684				&p.frame_list[0],
1685				uclogic_rdesc_ugee_g5_frame_arr,
1686				uclogic_rdesc_ugee_g5_frame_size,
1687				UCLOGIC_RDESC_UGEE_G5_FRAME_ID);
1688			if (rc != 0) {
1689				hid_err(hdev,
1690					"failed creating frame parameters: %d\n",
1691					rc);
1692				goto cleanup;
1693			}
1694			p.frame_list[0].re_lsb =
1695				UCLOGIC_RDESC_UGEE_G5_FRAME_RE_LSB;
1696			p.frame_list[0].dev_id_byte =
1697				UCLOGIC_RDESC_UGEE_G5_FRAME_DEV_ID_BYTE;
1698		} else {
1699			hid_warn(hdev, "pen parameters not found");
1700			uclogic_params_init_invalid(&p);
1701		}
1702
1703		break;
1704	case VID_PID(USB_VENDOR_ID_UGEE,
1705		     USB_DEVICE_ID_UGEE_TABLET_EX07S):
1706		/* Ignore non-pen interfaces */
1707		if (bInterfaceNumber != 1) {
1708			uclogic_params_init_invalid(&p);
1709			break;
1710		}
1711
1712		rc = uclogic_params_pen_init_v1(&p.pen, &found, hdev);
1713		if (rc != 0) {
1714			hid_err(hdev, "pen probing failed: %d\n", rc);
1715			goto cleanup;
1716		} else if (found) {
1717			rc = uclogic_params_frame_init_with_desc(
1718				&p.frame_list[0],
1719				uclogic_rdesc_ugee_ex07_frame_arr,
1720				uclogic_rdesc_ugee_ex07_frame_size,
1721				0);
1722			if (rc != 0) {
1723				hid_err(hdev,
1724					"failed creating frame parameters: %d\n",
1725					rc);
1726				goto cleanup;
1727			}
1728		} else {
1729			hid_warn(hdev, "pen parameters not found");
1730			uclogic_params_init_invalid(&p);
1731		}
1732
1733		break;
1734	}
1735
1736#undef VID_PID
1737#undef WITH_OPT_DESC
1738
1739	/* Output parameters */
1740	memcpy(params, &p, sizeof(*params));
1741	memset(&p, 0, sizeof(p));
1742	rc = 0;
1743cleanup:
1744	uclogic_params_cleanup(&p);
1745	return rc;
1746}
1747
1748#ifdef CONFIG_HID_KUNIT_TEST
1749#include "hid-uclogic-params-test.c"
1750#endif