Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1963518b authored by Ping Cheng's avatar Ping Cheng Committed by Dmitry Torokhov
Browse files

Input: wacom - add 0xE5 (MT device) support



Main part of patch is adding support for a new Wacom MT touch
packet and labels these devices using MTSCREEN type.

Other items of interest:

Delete some duplicate code in HID parsing for Y info since
its already done in X path.

In wacom_query_tablet_data(), only invoke the set report
that requests tablets to send Wacom Touch packets for
Finger interfaces.  Mostly, this is to make code intent clear.

Tested-by: default avatarJason Gerecke <killertofu@gmail.com>
Signed-off-by: default avatarChris Bagwell <chris@cnpbagwell.com>
Signed-off-by: default avatarPing Cheng <pingc@wacom.com>
Signed-off-by: default avatarDmitry Torokhov <dtor@mail.ru>
parent f393ee2b
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -135,6 +135,6 @@ extern const struct usb_device_id wacom_ids[];

void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len);
void wacom_setup_device_quirks(struct wacom_features *features);
void wacom_setup_input_capabilities(struct input_dev *input_dev,
int wacom_setup_input_capabilities(struct input_dev *input_dev,
				   struct wacom_wac *wacom_wac);
#endif
+53 −38
Original line number Diff line number Diff line
@@ -317,6 +317,10 @@ static int wacom_parse_hid(struct usb_interface *intf,
							/* need to reset back */
							features->pktlen = WACOM_PKGLEN_TPC2FG;
						}

						if (features->type == MTSCREEN)
							features->pktlen = WACOM_PKGLEN_MTOUCH;

						if (features->type == BAMBOO_PT) {
							/* need to reset back */
							features->pktlen = WACOM_PKGLEN_BBTOUCH;
@@ -349,18 +353,15 @@ static int wacom_parse_hid(struct usb_interface *intf,
			case HID_USAGE_Y:
				if (usage == WCM_DESKTOP) {
					if (finger) {
						features->device_type = BTN_TOOL_FINGER;
						if (features->type == TABLETPC2FG) {
							/* need to reset back */
							features->pktlen = WACOM_PKGLEN_TPC2FG;
						int type = features->type;

						if (type == TABLETPC2FG || type == MTSCREEN) {
							features->y_max =
								get_unaligned_le16(&report[i + 3]);
							features->y_phy =
								get_unaligned_le16(&report[i + 6]);
							i += 7;
						} else if (features->type == BAMBOO_PT) {
							/* need to reset back */
							features->pktlen = WACOM_PKGLEN_BBTOUCH;
						} else if (type == BAMBOO_PT) {
							features->y_phy =
								get_unaligned_le16(&report[i + 3]);
							features->y_max =
@@ -374,10 +375,6 @@ static int wacom_parse_hid(struct usb_interface *intf,
							i += 4;
						}
					} else if (pen) {
						/* penabled only accepts exact bytes of data */
						if (features->type == TABLETPC2FG)
							features->pktlen = WACOM_PKGLEN_GRAPHIRE;
						features->device_type = BTN_TOOL_PEN;
						features->y_max =
							get_unaligned_le16(&report[i + 3]);
						i += 4;
@@ -440,22 +437,29 @@ static int wacom_query_tablet_data(struct usb_interface *intf, struct wacom_feat
	if (!rep_data)
		return error;

	/* ask to report tablet data if it is MT Tablet PC or
	 * not a Tablet PC */
	if (features->type == TABLETPC2FG) {
	/* ask to report Wacom data */
	if (features->device_type == BTN_TOOL_FINGER) {
		/* if it is an MT Tablet PC touch */
		if (features->type == TABLETPC2FG ||
		    features->type == MTSCREEN) {
			do {
				rep_data[0] = 3;
				rep_data[1] = 4;
				rep_data[2] = 0;
				rep_data[3] = 0;
				report_id = 3;
			error = wacom_set_report(intf, WAC_HID_FEATURE_REPORT,
						 report_id, rep_data, 4, 1);
				error = wacom_set_report(intf,
							 WAC_HID_FEATURE_REPORT,
							 report_id,
							 rep_data, 4, 1);
				if (error >= 0)
					error = wacom_get_report(intf,
							WAC_HID_FEATURE_REPORT,
						report_id, rep_data, 4, 1);
		} while ((error < 0 || rep_data[1] != 4) && limit++ < WAC_MSG_RETRIES);
							report_id,
							rep_data, 4, 1);
			} while ((error < 0 || rep_data[1] != 4) &&
				 limit++ < WAC_MSG_RETRIES);
		}
	} else if (features->type != TABLETPC &&
		   features->type != WIRELESS &&
		   features->device_type == BTN_TOOL_PEN) {
@@ -505,10 +509,13 @@ static int wacom_retrieve_hid_descriptor(struct usb_interface *intf,
		}
	}

	/* only Tablet PCs and Bamboo P&T need to retrieve the info */
	if ((features->type != TABLETPC) && (features->type != TABLETPC2FG) &&
	    (features->type != BAMBOO_PT))
	/* only devices that support touch need to retrieve the info */
	if (features->type != TABLETPC &&
	    features->type != TABLETPC2FG &&
	    features->type != BAMBOO_PT &&
	    features->type != MTSCREEN) {
		goto out;
	}

	if (usb_get_extra_descriptor(interface, HID_DEVICET_HID, &hid_desc)) {
		if (usb_get_extra_descriptor(&interface->endpoint[0],
@@ -978,8 +985,10 @@ static int wacom_register_input(struct wacom *wacom)
	int error;

	input_dev = input_allocate_device();
	if (!input_dev)
		return -ENOMEM;
	if (!input_dev) {
		error = -ENOMEM;
		goto fail1;
	}

	input_dev->name = wacom_wac->name;
	input_dev->dev.parent = &intf->dev;
@@ -989,14 +998,20 @@ static int wacom_register_input(struct wacom *wacom)
	input_set_drvdata(input_dev, wacom);

	wacom_wac->input = input_dev;
	wacom_setup_input_capabilities(input_dev, wacom_wac);
	error = wacom_setup_input_capabilities(input_dev, wacom_wac);
	if (error)
		goto fail1;

	error = input_register_device(input_dev);
	if (error) {
	if (error)
		goto fail2;

	return 0;

fail2:
	input_free_device(input_dev);
	wacom_wac->input = NULL;
	}

fail1:
	return error;
}

+94 −5
Original line number Diff line number Diff line
@@ -768,6 +768,72 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
	return 1;
}

static int find_slot_from_contactid(struct wacom_wac *wacom, int contactid)
{
	int touch_max = wacom->features.touch_max;
	int i;

	if (!wacom->slots)
		return -1;

	for (i = 0; i < touch_max; ++i) {
		if (wacom->slots[i] == contactid)
			return i;
	}
	for (i = 0; i < touch_max; ++i) {
		if (wacom->slots[i] == -1)
			return i;
	}
	return -1;
}

static int wacom_mt_touch(struct wacom_wac *wacom)
{
	struct input_dev *input = wacom->input;
	char *data = wacom->data;
	int i;
	int current_num_contacts = data[2];
	int contacts_to_send = 0;

	/*
	 * First packet resets the counter since only the first
	 * packet in series will have non-zero current_num_contacts.
	 */
	if (current_num_contacts)
		wacom->num_contacts_left = current_num_contacts;

	/* There are at most 5 contacts per packet */
	contacts_to_send = min(5, wacom->num_contacts_left);

	for (i = 0; i < contacts_to_send; i++) {
		int offset = (WACOM_BYTES_PER_MT_PACKET * i) + 3;
		bool touch = data[offset] & 0x1;
		int id = le16_to_cpup((__le16 *)&data[offset + 1]);
		int slot = find_slot_from_contactid(wacom, id);

		if (slot < 0)
			continue;

		input_mt_slot(input, slot);
		input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
		if (touch) {
			int x = le16_to_cpup((__le16 *)&data[offset + 7]);
			int y = le16_to_cpup((__le16 *)&data[offset + 9]);
			input_report_abs(input, ABS_MT_POSITION_X, x);
			input_report_abs(input, ABS_MT_POSITION_Y, y);
		}
		wacom->slots[slot] = touch ? id : -1;
	}

	input_mt_report_pointer_emulation(input, true);

	wacom->num_contacts_left -= contacts_to_send;
	if (wacom->num_contacts_left < 0)
		wacom->num_contacts_left = 0;

	return 1;
}

static int wacom_tpc_mt_touch(struct wacom_wac *wacom)
{
	struct input_dev *input = wacom->input;
@@ -806,6 +872,9 @@ static int wacom_tpc_single_touch(struct wacom_wac *wacom, size_t len)
	bool prox;
	int x = 0, y = 0;

	if (wacom->features.touch_max > 1 || len > WACOM_PKGLEN_TPC2FG)
		return 0;

	if (!wacom->shared->stylus_in_proximity) {
		if (len == WACOM_PKGLEN_TPC1FG) {
			prox = data[0] & 0x01;
@@ -885,6 +954,9 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, size_t len)
		case WACOM_REPORT_TPCST:
			return wacom_tpc_single_touch(wacom, len);

		case WACOM_REPORT_TPCMT:
			return wacom_mt_touch(wacom);

		case WACOM_REPORT_PENABLED:
			return wacom_tpc_pen(wacom);
		}
@@ -1164,6 +1236,7 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)

	case TABLETPC:
	case TABLETPC2FG:
	case MTSCREEN:
		sync = wacom_tpc_irq(wacom_wac, len);
		break;

@@ -1237,7 +1310,8 @@ void wacom_setup_device_quirks(struct wacom_features *features)
	/* these device have multiple inputs */
	if (features->type == TABLETPC || features->type == TABLETPC2FG ||
	    features->type == BAMBOO_PT || features->type == WIRELESS ||
	    (features->type >= INTUOS5S && features->type <= INTUOS5L))
	    (features->type >= INTUOS5S && features->type <= INTUOS5L) ||
	    features->type == MTSCREEN)
		features->quirks |= WACOM_QUIRK_MULTI_INPUT;

	/* quirk for bamboo touch with 2 low res touches */
@@ -1268,7 +1342,7 @@ static unsigned int wacom_calculate_touch_res(unsigned int logical_max,
       return (logical_max * 100) / physical_max;
}

void wacom_setup_input_capabilities(struct input_dev *input_dev,
int wacom_setup_input_capabilities(struct input_dev *input_dev,
				   struct wacom_wac *wacom_wac)
{
	struct wacom_features *features = &wacom_wac->features;
@@ -1465,8 +1539,18 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
		break;

	case TABLETPC2FG:
	case MTSCREEN:
		if (features->device_type == BTN_TOOL_FINGER) {

			wacom_wac->slots = kmalloc(features->touch_max *
							sizeof(int),
						   GFP_KERNEL);
			if (!wacom_wac->slots)
				return -ENOMEM;

			for (i = 0; i < features->touch_max; i++)
				wacom_wac->slots[i] = -1;

			input_mt_init_slots(input_dev, features->touch_max);
			input_set_abs_params(input_dev, ABS_MT_TOOL_TYPE,
					0, MT_TOOL_MAX, 0, 0);
@@ -1552,6 +1636,7 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
		}
		break;
	}
	return 0;
}

static const struct wacom_features wacom_features_0x00 =
@@ -1784,6 +1869,9 @@ static const struct wacom_features wacom_features_0xE3 =
	{ "Wacom ISDv4 E3",       WACOM_PKGLEN_TPC2FG,    26202, 16325,  255,
	  0, TABLETPC2FG, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
	  .touch_max = 2 };
static const struct wacom_features wacom_features_0xE5 =
	{ "Wacom ISDv4 E5",       WACOM_PKGLEN_MTOUCH,    26202, 16325,  255,
	  0, MTSCREEN, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0xE6 =
	{ "Wacom ISDv4 E6",       WACOM_PKGLEN_TPC2FG,    27760, 15694,  255,
	  0, TABLETPC2FG, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
@@ -1962,6 +2050,7 @@ const struct usb_device_id wacom_ids[] = {
	{ USB_DEVICE_WACOM(0x9F) },
	{ USB_DEVICE_WACOM(0xE2) },
	{ USB_DEVICE_WACOM(0xE3) },
	{ USB_DEVICE_WACOM(0xE5) },
	{ USB_DEVICE_WACOM(0xE6) },
	{ USB_DEVICE_WACOM(0xEC) },
	{ USB_DEVICE_WACOM(0x47) },
+8 −0
Original line number Diff line number Diff line
@@ -25,6 +25,10 @@
#define WACOM_PKGLEN_BBTOUCH3	64
#define WACOM_PKGLEN_BBPEN	10
#define WACOM_PKGLEN_WIRELESS	32
#define WACOM_PKGLEN_MTOUCH	62

/* wacom data size per MT contact */
#define WACOM_BYTES_PER_MT_PACKET	11

/* device IDs */
#define STYLUS_DEVICE_ID	0x02
@@ -41,6 +45,7 @@
#define WACOM_REPORT_INTUOS5PAD		3
#define WACOM_REPORT_TPC1FG		6
#define WACOM_REPORT_TPC2FG		13
#define WACOM_REPORT_TPCMT		13
#define WACOM_REPORT_TPCHID		15
#define WACOM_REPORT_TPCST		16

@@ -76,6 +81,7 @@ enum {
	WACOM_MO,
	TABLETPC,
	TABLETPC2FG,
	MTSCREEN,
	MAX_TYPE
};

@@ -118,6 +124,8 @@ struct wacom_wac {
	struct input_dev *input;
	int pid;
	int battery_capacity;
	int num_contacts_left;
	int *slots;
};

#endif