#include "wacom.h"
#include <linux/hid.h>
-#define HID_HDESC_USAGE_UNDEFINED 0x00
-#define HID_HDESC_USAGE_PAGE 0x05
-#define HID_HDESC_USAGE 0x09
-#define HID_HDESC_COLLECTION 0xa1
-#define HID_HDESC_COLLECTION_LOGICAL 0x02
-#define HID_HDESC_COLLECTION_END 0xc0
-
#define WAC_MSG_RETRIES 5
#define WAC_CMD_LED_CONTROL 0x20
* This function is little more than hidinput_calc_abs_res stripped down.
*/
static int wacom_calc_hid_res(int logical_extents, int physical_extents,
- unsigned char unit, unsigned char exponent)
+ unsigned unit, int exponent)
{
- int prev, unit_exponent;
+ int prev;
+ int unit_exponent = exponent;
/* Check if the extents are sane */
if (logical_extents <= 0 || physical_extents <= 0)
return 0;
- /* Get signed value of nybble-sized twos-compliment exponent */
- unit_exponent = exponent;
- if (unit_exponent > 7)
- unit_exponent -= 16;
-
/* Convert physical_extents to millimeters */
if (unit == 0x11) { /* If centimeters */
unit_exponent += 1;
return logical_extents / physical_extents;
}
-static int wacom_parse_logical_collection(unsigned char *report,
- struct wacom_features *features)
-{
- int length = 0;
-
- if (features->type == BAMBOO_PT) {
-
- /* Logical collection is only used by 3rd gen Bamboo Touch */
- features->device_type = BTN_TOOL_FINGER;
-
- features->x_max = features->y_max =
- get_unaligned_le16(&report[10]);
-
- length = 11;
- }
- return length;
-}
-
-static void wacom_retrieve_report_data(struct hid_device *hdev,
- struct wacom_features *features)
+static void wacom_feature_mapping(struct hid_device *hdev,
+ struct hid_field *field, struct hid_usage *usage)
{
- int result = 0;
- unsigned char *rep_data;
-
- rep_data = kmalloc(2, GFP_KERNEL);
- if (rep_data) {
-
- rep_data[0] = 12;
- result = wacom_get_report(hdev, HID_FEATURE_REPORT,
- rep_data[0], rep_data, 2,
- WAC_MSG_RETRIES);
-
- if (result >= 0 && rep_data[1] > 2)
- features->touch_max = rep_data[1];
+ struct wacom *wacom = hid_get_drvdata(hdev);
+ struct wacom_features *features = &wacom->wacom_wac.features;
- kfree(rep_data);
+ switch (usage->hid) {
+ case HID_DG_CONTACTMAX:
+ /* leave touch_max as is if predefined */
+ if (!features->touch_max)
+ features->touch_max = field->value[0];
+ break;
}
}
* interfaces haven't supported pressure or distance, this is enough
* information to override invalid values in the wacom_features table.
*
- * 3rd gen Bamboo Touch no longer define a Digitizer-Finger Pysical
- * Collection. Instead they define a Logical Collection with a single
- * Logical Maximum for both X and Y.
- *
- * Intuos5 touch interface does not contain useful data. We deal with
- * this after returning from this function.
+ * Intuos5 touch interface and 3rd gen Bamboo Touch do not contain useful
+ * data. We deal with them after returning from this function.
*/
-static int wacom_parse_hid(struct hid_device *hdev,
- struct wacom_features *features)
+static void wacom_usage_mapping(struct hid_device *hdev,
+ struct hid_field *field, struct hid_usage *usage)
{
- /* result has to be defined as int for some devices */
- int result = 0, touch_max = 0;
- int i = 0, page = 0, finger = 0, pen = 0;
- unsigned char *report = hdev->rdesc;
-
- for (i = 0; i < hdev->rsize; i++) {
-
- switch (report[i]) {
- case HID_HDESC_USAGE_PAGE:
- page = report[i + 1];
- i++;
- break;
-
- case HID_HDESC_USAGE:
- switch (page << 16 | report[i + 1]) {
- case HID_GD_X:
- if (finger) {
- features->device_type = BTN_TOOL_FINGER;
- /* touch device at least supports one touch point */
- touch_max = 1;
-
- switch (features->type) {
- case BAMBOO_PT:
- features->x_phy =
- get_unaligned_le16(&report[i + 5]);
- features->x_max =
- get_unaligned_le16(&report[i + 8]);
- i += 15;
- break;
-
- case WACOM_24HDT:
- features->x_max =
- get_unaligned_le16(&report[i + 3]);
- features->x_phy =
- get_unaligned_le16(&report[i + 8]);
- features->unit = report[i - 1];
- features->unitExpo = report[i - 3];
- i += 12;
- break;
-
- case MTTPC_B:
- features->x_max =
- get_unaligned_le16(&report[i + 3]);
- features->x_phy =
- get_unaligned_le16(&report[i + 6]);
- features->unit = report[i - 5];
- features->unitExpo = report[i - 3];
- i += 9;
- break;
-
- default:
- features->x_max =
- get_unaligned_le16(&report[i + 3]);
- features->x_phy =
- get_unaligned_le16(&report[i + 6]);
- features->unit = report[i + 9];
- features->unitExpo = report[i + 11];
- i += 12;
- break;
- }
- } else if (pen) {
- /* penabled only accepts exact bytes of data */
- features->device_type = BTN_TOOL_PEN;
- features->x_max =
- get_unaligned_le16(&report[i + 3]);
- i += 4;
- }
- break;
-
- case HID_GD_Y:
- if (finger) {
- switch (features->type) {
- case TABLETPC2FG:
- case MTSCREEN:
- case MTTPC:
- features->y_max =
- get_unaligned_le16(&report[i + 3]);
- features->y_phy =
- get_unaligned_le16(&report[i + 6]);
- i += 7;
- break;
-
- case WACOM_24HDT:
- features->y_max =
- get_unaligned_le16(&report[i + 3]);
- features->y_phy =
- get_unaligned_le16(&report[i - 2]);
- i += 7;
- break;
-
- case BAMBOO_PT:
- features->y_phy =
- get_unaligned_le16(&report[i + 3]);
- features->y_max =
- get_unaligned_le16(&report[i + 6]);
- i += 12;
- break;
-
- case MTTPC_B:
- features->y_max =
- get_unaligned_le16(&report[i + 3]);
- features->y_phy =
- get_unaligned_le16(&report[i + 6]);
- i += 9;
- break;
-
- default:
- features->y_max =
- features->x_max;
- features->y_phy =
- get_unaligned_le16(&report[i + 3]);
- i += 4;
- break;
- }
- } else if (pen) {
- features->y_max =
- get_unaligned_le16(&report[i + 3]);
- i += 4;
- }
- break;
-
- case HID_DG_FINGER:
- finger = 1;
- i++;
- break;
-
- /*
- * Requiring Stylus Usage will ignore boot mouse
- * X/Y values and some cases of invalid Digitizer X/Y
- * values commonly reported.
- */
- case HID_DG_STYLUS:
- pen = 1;
- i++;
- break;
-
- case HID_DG_CONTACTMAX:
- /* leave touch_max as is if predefined */
- if (!features->touch_max)
- wacom_retrieve_report_data(hdev, features);
- i++;
- break;
+ struct wacom *wacom = hid_get_drvdata(hdev);
+ struct wacom_features *features = &wacom->wacom_wac.features;
+ bool finger = (field->logical == HID_DG_FINGER) ||
+ (field->physical == HID_DG_FINGER);
+ bool pen = (field->logical == HID_DG_STYLUS) ||
+ (field->physical == HID_DG_STYLUS);
- case HID_DG_TIPPRESSURE:
- if (pen) {
- features->pressure_max =
- get_unaligned_le16(&report[i + 3]);
- i += 4;
- }
- break;
+ /*
+ * Requiring Stylus Usage will ignore boot mouse
+ * X/Y values and some cases of invalid Digitizer X/Y
+ * values commonly reported.
+ */
+ if (!pen && !finger)
+ return;
+
+ if (finger && !features->touch_max)
+ /* touch device at least supports one touch point */
+ features->touch_max = 1;
+
+ switch (usage->hid) {
+ case HID_GD_X:
+ features->x_max = field->logical_maximum;
+ if (finger) {
+ features->device_type = BTN_TOOL_FINGER;
+ features->x_phy = field->physical_maximum;
+ if (features->type != BAMBOO_PT) {
+ features->unit = field->unit;
+ features->unitExpo = field->unit_exponent;
}
- break;
-
- case HID_HDESC_COLLECTION_END:
- /* reset UsagePage and Finger */
- finger = page = 0;
- break;
+ } else {
+ features->device_type = BTN_TOOL_PEN;
+ }
+ break;
+ case HID_GD_Y:
+ features->y_max = field->logical_maximum;
+ if (finger) {
+ features->y_phy = field->physical_maximum;
+ if (features->type != BAMBOO_PT) {
+ features->unit = field->unit;
+ features->unitExpo = field->unit_exponent;
+ }
+ }
+ break;
+ case HID_DG_TIPPRESSURE:
+ if (pen)
+ features->pressure_max = field->logical_maximum;
+ break;
+ }
+}
- case HID_HDESC_COLLECTION:
- i++;
- switch (report[i]) {
- case HID_HDESC_COLLECTION_LOGICAL:
- i += wacom_parse_logical_collection(&report[i],
- features);
- break;
+static void wacom_parse_hid(struct hid_device *hdev,
+ struct wacom_features *features)
+{
+ struct hid_report_enum *rep_enum;
+ struct hid_report *hreport;
+ int i, j;
+
+ /* check features first */
+ rep_enum = &hdev->report_enum[HID_FEATURE_REPORT];
+ list_for_each_entry(hreport, &rep_enum->report_list, list) {
+ for (i = 0; i < hreport->maxfield; i++) {
+ /* Ignore if report count is out of bounds. */
+ if (hreport->field[i]->report_count < 1)
+ continue;
+
+ for (j = 0; j < hreport->field[i]->maxusage; j++) {
+ wacom_feature_mapping(hdev, hreport->field[i],
+ hreport->field[i]->usage + j);
}
- break;
}
}
- if (!features->touch_max && touch_max)
- features->touch_max = touch_max;
- result = 0;
- return result;
+ /* now check the input usages */
+ rep_enum = &hdev->report_enum[HID_INPUT_REPORT];
+ list_for_each_entry(hreport, &rep_enum->report_list, list) {
+
+ if (!hreport->maxfield)
+ continue;
+
+ for (i = 0; i < hreport->maxfield; i++)
+ for (j = 0; j < hreport->field[i]->maxusage; j++)
+ wacom_usage_mapping(hdev, hreport->field[i],
+ hreport->field[i]->usage + j);
+ }
}
static int wacom_set_device_mode(struct hid_device *hdev, int report_id,
return 0;
}
-static int wacom_retrieve_hid_descriptor(struct hid_device *hdev,
+static void wacom_retrieve_hid_descriptor(struct hid_device *hdev,
struct wacom_features *features)
{
- int error = 0;
struct wacom *wacom = hid_get_drvdata(hdev);
struct usb_interface *intf = wacom->intf;
}
/* only devices that support touch need to retrieve the info */
- if (features->type < BAMBOO_PT) {
- goto out;
- }
+ if (features->type < BAMBOO_PT)
+ return;
- error = wacom_parse_hid(hdev, features);
-
- out:
- return error;
+ wacom_parse_hid(hdev, features);
}
struct wacom_hdev_data {
wacom_set_default_phy(features);
/* Retrieve the physical and logical size for touch devices */
- error = wacom_retrieve_hid_descriptor(hdev, features);
- if (error)
- goto fail1;
+ wacom_retrieve_hid_descriptor(hdev, features);
/*
* Intuos5 has no useful data about its touch interface in its
}
}
+ /*
+ * Same thing for Bamboo 3rd gen.
+ */
+ if ((features->type == BAMBOO_PT) &&
+ (features->pktlen == WACOM_PKGLEN_BBTOUCH3) &&
+ (features->device_type == BTN_TOOL_PEN)) {
+ features->device_type = BTN_TOOL_FINGER;
+
+ features->x_max = 4096;
+ features->y_max = 4096;
+ }
+
wacom_setup_device_quirks(features);
/* set unit to "100th of a mm" for devices not reported by HID */
if (!features->unit) {
features->unit = 0x11;
- features->unitExpo = 16 - 3;
+ features->unitExpo = -3;
}
wacom_calculate_res(features);