}
input_report_abs(input, ABS_PRESSURE, t);
input_report_abs(input, ABS_TILT_X,
- ((data[7] << 1) & 0x7e) | (data[8] >> 7));
- input_report_abs(input, ABS_TILT_Y, data[8] & 0x7f);
+ (((data[7] << 1) & 0x7e) | (data[8] >> 7)) - 64);
+ input_report_abs(input, ABS_TILT_Y, (data[8] & 0x7f) - 64);
input_report_key(input, BTN_STYLUS, data[1] & 2);
input_report_key(input, BTN_STYLUS2, data[1] & 4);
input_report_key(input, BTN_TOUCH, t > 10);
input_report_abs(input, ABS_WHEEL,
(data[6] << 2) | ((data[7] >> 6) & 3));
input_report_abs(input, ABS_TILT_X,
- ((data[7] << 1) & 0x7e) | (data[8] >> 7));
- input_report_abs(input, ABS_TILT_Y, data[8] & 0x7f);
+ (((data[7] << 1) & 0x7e) | (data[8] >> 7)) - 64);
+ input_report_abs(input, ABS_TILT_Y, (data[8] & 0x7f) - 64);
}
}
input_report_key(input, BTN_EXTRA, data[6] & 0x10);
input_report_abs(input, ABS_TILT_X,
- ((data[7] << 1) & 0x7e) | (data[8] >> 7));
- input_report_abs(input, ABS_TILT_Y, data[8] & 0x7f);
+ (((data[7] << 1) & 0x7e) | (data[8] >> 7)) - 64);
+ input_report_abs(input, ABS_TILT_Y, (data[8] & 0x7f) - 64);
} else {
/* 2D mouse packet */
input_report_key(input, BTN_LEFT, data[8] & 0x04);
return 0;
}
+static void wacom_map_usage(struct wacom *wacom, struct hid_usage *usage,
+ struct hid_field *field, __u8 type, __u16 code, int fuzz)
+{
+ struct wacom_wac *wacom_wac = &wacom->wacom_wac;
+ struct input_dev *input = wacom_wac->input;
+ int fmin = field->logical_minimum;
+ int fmax = field->logical_maximum;
+
+ usage->type = type;
+ usage->code = code;
+
+ set_bit(type, input->evbit);
+
+ switch (type) {
+ case EV_ABS:
+ input_set_abs_params(input, code, fmin, fmax, fuzz, 0);
+ input_abs_set_res(input, code,
+ hidinput_calc_abs_res(field, code));
+ break;
+ case EV_KEY:
+ input_set_capability(input, EV_KEY, code);
+ break;
+ case EV_MSC:
+ input_set_capability(input, EV_MSC, code);
+ break;
+ }
+}
+
+static void wacom_wac_pen_usage_mapping(struct hid_device *hdev,
+ struct hid_field *field, struct hid_usage *usage)
+{
+ struct wacom *wacom = hid_get_drvdata(hdev);
+
+ switch (usage->hid) {
+ case HID_GD_X:
+ wacom_map_usage(wacom, usage, field, EV_ABS, ABS_X, 4);
+ break;
+ case HID_GD_Y:
+ wacom_map_usage(wacom, usage, field, EV_ABS, ABS_Y, 4);
+ break;
+ case HID_DG_TIPPRESSURE:
+ wacom_map_usage(wacom, usage, field, EV_ABS, ABS_PRESSURE, 0);
+ break;
+ case HID_DG_INRANGE:
+ wacom_map_usage(wacom, usage, field, EV_KEY, BTN_TOOL_PEN, 0);
+ break;
+ case HID_DG_INVERT:
+ wacom_map_usage(wacom, usage, field, EV_KEY,
+ BTN_TOOL_RUBBER, 0);
+ break;
+ case HID_DG_ERASER:
+ case HID_DG_TIPSWITCH:
+ wacom_map_usage(wacom, usage, field, EV_KEY, BTN_TOUCH, 0);
+ break;
+ case HID_DG_BARRELSWITCH:
+ wacom_map_usage(wacom, usage, field, EV_KEY, BTN_STYLUS, 0);
+ break;
+ case HID_DG_BARRELSWITCH2:
+ wacom_map_usage(wacom, usage, field, EV_KEY, BTN_STYLUS2, 0);
+ break;
+ case HID_DG_TOOLSERIALNUMBER:
+ wacom_map_usage(wacom, usage, field, EV_MSC, MSC_SERIAL, 0);
+ break;
+ }
+}
+
+static int wacom_wac_pen_event(struct hid_device *hdev, struct hid_field *field,
+ struct hid_usage *usage, __s32 value)
+{
+ struct wacom *wacom = hid_get_drvdata(hdev);
+ struct wacom_wac *wacom_wac = &wacom->wacom_wac;
+ struct input_dev *input = wacom_wac->input;
+
+ /* checking which Tool / tip switch to send */
+ switch (usage->hid) {
+ case HID_DG_INRANGE:
+ wacom_wac->hid_data.inrange_state = value;
+ return 0;
+ case HID_DG_INVERT:
+ wacom_wac->hid_data.invert_state = value;
+ return 0;
+ case HID_DG_ERASER:
+ case HID_DG_TIPSWITCH:
+ wacom_wac->hid_data.tipswitch |= value;
+ return 0;
+ }
+
+ /* send pen events only when touch is up or forced out */
+ if (!usage->type || wacom_wac->shared->touch_down)
+ return 0;
+
+ input_event(input, usage->type, usage->code, value);
+
+ return 0;
+}
+
+static void wacom_wac_pen_report(struct hid_device *hdev,
+ struct hid_report *report)
+{
+ struct wacom *wacom = hid_get_drvdata(hdev);
+ struct wacom_wac *wacom_wac = &wacom->wacom_wac;
+ struct input_dev *input = wacom_wac->input;
+ bool prox = wacom_wac->hid_data.inrange_state;
+
+ if (!wacom_wac->shared->stylus_in_proximity) /* first in prox */
+ /* Going into proximity select tool */
+ wacom_wac->tool[0] = wacom_wac->hid_data.invert_state ?
+ BTN_TOOL_RUBBER : BTN_TOOL_PEN;
+
+ /* keep pen state for touch events */
+ wacom_wac->shared->stylus_in_proximity = prox;
+
+ /* send pen events only when touch is up or forced out */
+ if (!wacom_wac->shared->touch_down) {
+ input_report_key(input, BTN_TOUCH,
+ wacom_wac->hid_data.tipswitch);
+ input_report_key(input, wacom_wac->tool[0], prox);
+
+ wacom_wac->hid_data.tipswitch = false;
+
+ input_sync(input);
+ }
+}
+
+static void wacom_wac_finger_usage_mapping(struct hid_device *hdev,
+ struct hid_field *field, struct hid_usage *usage)
+{
+ struct wacom *wacom = hid_get_drvdata(hdev);
+ struct wacom_wac *wacom_wac = &wacom->wacom_wac;
+ struct input_dev *input = wacom_wac->input;
+ unsigned touch_max = wacom_wac->features.touch_max;
+
+ switch (usage->hid) {
+ case HID_GD_X:
+ if (touch_max == 1)
+ wacom_map_usage(wacom, usage, field, EV_ABS, ABS_X, 4);
+ else
+ wacom_map_usage(wacom, usage, field, EV_ABS,
+ ABS_MT_POSITION_X, 4);
+ break;
+ case HID_GD_Y:
+ if (touch_max == 1)
+ wacom_map_usage(wacom, usage, field, EV_ABS, ABS_Y, 4);
+ else
+ wacom_map_usage(wacom, usage, field, EV_ABS,
+ ABS_MT_POSITION_Y, 4);
+ break;
+ case HID_DG_CONTACTID:
+ input_mt_init_slots(input, wacom_wac->features.touch_max,
+ INPUT_MT_DIRECT);
+ break;
+ case HID_DG_INRANGE:
+ break;
+ case HID_DG_INVERT:
+ break;
+ case HID_DG_TIPSWITCH:
+ wacom_map_usage(wacom, usage, field, EV_KEY, BTN_TOUCH, 0);
+ break;
+ }
+}
+
+static int wacom_wac_finger_event(struct hid_device *hdev,
+ struct hid_field *field, struct hid_usage *usage, __s32 value)
+{
+ struct wacom *wacom = hid_get_drvdata(hdev);
+ struct wacom_wac *wacom_wac = &wacom->wacom_wac;
+
+ switch (usage->hid) {
+ case HID_GD_X:
+ wacom_wac->hid_data.x = value;
+ break;
+ case HID_GD_Y:
+ wacom_wac->hid_data.y = value;
+ break;
+ case HID_DG_CONTACTID:
+ wacom_wac->hid_data.id = value;
+ break;
+ case HID_DG_TIPSWITCH:
+ wacom_wac->hid_data.tipswitch = value;
+ break;
+ }
+
+
+ return 0;
+}
+
+static void wacom_wac_finger_mt_report(struct wacom_wac *wacom_wac,
+ struct input_dev *input, bool touch)
+{
+ int slot;
+ struct hid_data *hid_data = &wacom_wac->hid_data;
+
+ slot = input_mt_get_slot_by_key(input, hid_data->id);
+
+ input_mt_slot(input, slot);
+ input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
+ if (touch) {
+ input_report_abs(input, ABS_MT_POSITION_X, hid_data->x);
+ input_report_abs(input, ABS_MT_POSITION_Y, hid_data->y);
+ }
+ input_mt_sync_frame(input);
+}
+
+static void wacom_wac_finger_single_touch_report(struct wacom_wac *wacom_wac,
+ struct input_dev *input, bool touch)
+{
+ struct hid_data *hid_data = &wacom_wac->hid_data;
+
+ if (touch) {
+ input_report_abs(input, ABS_X, hid_data->x);
+ input_report_abs(input, ABS_Y, hid_data->y);
+ }
+ input_report_key(input, BTN_TOUCH, touch);
+}
+
+static void wacom_wac_finger_report(struct hid_device *hdev,
+ struct hid_report *report)
+{
+ struct wacom *wacom = hid_get_drvdata(hdev);
+ struct wacom_wac *wacom_wac = &wacom->wacom_wac;
+ struct input_dev *input = wacom_wac->input;
+ bool touch = wacom_wac->hid_data.tipswitch &&
+ !wacom_wac->shared->stylus_in_proximity;
+ unsigned touch_max = wacom_wac->features.touch_max;
+
+ if (touch_max > 1)
+ wacom_wac_finger_mt_report(wacom_wac, input, touch);
+ else
+ wacom_wac_finger_single_touch_report(wacom_wac, input, touch);
+ input_sync(input);
+
+ /* keep touch state for pen event */
+ wacom_wac->shared->touch_down = touch;
+}
+
+#define WACOM_PEN_FIELD(f) (((f)->logical == HID_DG_STYLUS) || \
+ ((f)->physical == HID_DG_STYLUS) || \
+ ((f)->application == HID_DG_PEN))
+#define WACOM_FINGER_FIELD(f) (((f)->logical == HID_DG_FINGER) || \
+ ((f)->physical == HID_DG_FINGER) || \
+ ((f)->application == HID_DG_TOUCHSCREEN))
+
+void wacom_wac_usage_mapping(struct hid_device *hdev,
+ struct hid_field *field, struct hid_usage *usage)
+{
+ struct wacom *wacom = hid_get_drvdata(hdev);
+ struct wacom_wac *wacom_wac = &wacom->wacom_wac;
+ struct input_dev *input = wacom_wac->input;
+
+ /* currently, only direct devices have proper hid report descriptors */
+ __set_bit(INPUT_PROP_DIRECT, input->propbit);
+
+ if (WACOM_PEN_FIELD(field))
+ return wacom_wac_pen_usage_mapping(hdev, field, usage);
+
+ if (WACOM_FINGER_FIELD(field))
+ return wacom_wac_finger_usage_mapping(hdev, field, usage);
+}
+
+int wacom_wac_event(struct hid_device *hdev, struct hid_field *field,
+ struct hid_usage *usage, __s32 value)
+{
+ struct wacom *wacom = hid_get_drvdata(hdev);
+
+ if (wacom->wacom_wac.features.type != HID_GENERIC)
+ return 0;
+
+ if (WACOM_PEN_FIELD(field))
+ return wacom_wac_pen_event(hdev, field, usage, value);
+
+ if (WACOM_FINGER_FIELD(field))
+ return wacom_wac_finger_event(hdev, field, usage, value);
+
+ return 0;
+}
+
+void wacom_wac_report(struct hid_device *hdev, struct hid_report *report)
+{
+ struct wacom *wacom = hid_get_drvdata(hdev);
+ struct wacom_wac *wacom_wac = &wacom->wacom_wac;
+ struct hid_field *field = report->field[0];
+
+ if (wacom_wac->features.type != HID_GENERIC)
+ return;
+
+ if (WACOM_PEN_FIELD(field))
+ return wacom_wac_pen_report(hdev, report);
+
+ if (WACOM_FINGER_FIELD(field))
+ return wacom_wac_finger_report(hdev, report);
+}
+
static int wacom_bpt_touch(struct wacom_wac *wacom)
{
struct wacom_features *features = &wacom->features;
return 0;
if (data[0] == WACOM_REPORT_USB) {
- if (features->type == INTUOSHT && features->touch_max) {
+ if (features->type == INTUOSHT &&
+ wacom->shared->touch_input &&
+ features->touch_max) {
input_report_switch(wacom->shared->touch_input,
SW_MUTE_DEVICE, data[8] & 0x40);
input_sync(wacom->shared->touch_input);
int pid, battery, ps_connected;
if ((wacom->shared->type == INTUOSHT) &&
- wacom->shared->touch_max) {
+ wacom->shared->touch_input &&
+ wacom->shared->touch_max) {
input_report_switch(wacom->shared->touch_input,
SW_MUTE_DEVICE, data[5] & 0x40);
input_sync(wacom->shared->touch_input);
input_set_abs_params(input_dev, ABS_DISTANCE,
0, wacom_wac->features.distance_max, 0, 0);
input_set_abs_params(input_dev, ABS_WHEEL, 0, 1023, 0, 0);
- input_set_abs_params(input_dev, ABS_TILT_X, 0, 127, 0, 0);
- input_set_abs_params(input_dev, ABS_TILT_Y, 0, 127, 0, 0);
+ input_set_abs_params(input_dev, ABS_TILT_X, -64, 63, 0, 0);
+ input_abs_set_res(input_dev, ABS_TILT_X, 57);
+ input_set_abs_params(input_dev, ABS_TILT_Y, -64, 63, 0, 0);
+ input_abs_set_res(input_dev, ABS_TILT_Y, 57);
}
static void wacom_setup_intuos(struct wacom_wac *wacom_wac)
__set_bit(BTN_TOOL_LENS, input_dev->keybit);
input_set_abs_params(input_dev, ABS_RZ, -900, 899, 0, 0);
+ input_abs_set_res(input_dev, ABS_RZ, 287);
input_set_abs_params(input_dev, ABS_THROTTLE, -1023, 1023, 0, 0);
}
}
}
-int wacom_setup_input_capabilities(struct input_dev *input_dev,
+int wacom_setup_pentouch_input_capabilities(struct input_dev *input_dev,
struct wacom_wac *wacom_wac)
{
struct wacom_features *features = &wacom_wac->features;
input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+ if (features->type == HID_GENERIC)
+ /* setup has already been done */
+ return 0;
+
__set_bit(BTN_TOUCH, input_dev->keybit);
__set_bit(ABS_MISC, input_dev->absbit);
switch (features->type) {
case WACOM_MO:
- input_set_abs_params(input_dev, ABS_WHEEL, 0, 71, 0, 0);
- /* fall through */
-
case WACOM_G4:
/* fall through */
case WACOM_24HD:
input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
+ input_abs_set_res(input_dev, ABS_Z, 287);
input_set_abs_params(input_dev, ABS_THROTTLE, 0, 71, 0, 0);
/* fall through */
case WACOM_BEE:
case CINTIQ:
input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
+ input_abs_set_res(input_dev, ABS_Z, 287);
__set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
case WACOM_13HD:
input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
+ input_abs_set_res(input_dev, ABS_Z, 287);
__set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
wacom_setup_cintiq(wacom_wac);
break;
case INTUOS3L:
case INTUOS3S:
input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
+ input_abs_set_res(input_dev, ABS_Z, 287);
/* fall through */
case INTUOS:
0, 0);
input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
+ input_abs_set_res(input_dev, ABS_Z, 287);
wacom_setup_intuos(wacom_wac);
} else if (features->device_type == BTN_TOOL_FINGER) {
case INTUOS4L:
case INTUOS4S:
input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
+ input_abs_set_res(input_dev, ABS_Z, 287);
wacom_setup_intuos(wacom_wac);
__set_bit(INPUT_PROP_POINTER, input_dev->propbit);
__clear_bit(ABS_X, input_dev->absbit);
__clear_bit(ABS_Y, input_dev->absbit);
__clear_bit(BTN_TOUCH, input_dev->keybit);
+
+ /* PAD is setup by wacom_setup_pad_input_capabilities later */
+ return 1;
}
} else if (features->device_type == BTN_TOOL_PEN) {
__set_bit(INPUT_PROP_POINTER, input_dev->propbit);
case CINTIQ_HYBRID:
input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
+ input_abs_set_res(input_dev, ABS_Z, 287);
__set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
wacom_setup_cintiq(wacom_wac);
input_set_abs_params(input_dev, ABS_X, 0, 1, 0, 0);
input_set_abs_params(input_dev, ABS_Y, 0, 1, 0, 0);
+ /* kept for making udev and libwacom accepting the pad */
+ __set_bit(BTN_STYLUS, input_dev->keybit);
+
switch (features->type) {
case GRAPHIRE_BT:
__set_bit(BTN_0, input_dev->keybit);
case WACOM_G4:
__set_bit(BTN_BACK, input_dev->keybit);
- __set_bit(BTN_LEFT, input_dev->keybit);
__set_bit(BTN_FORWARD, input_dev->keybit);
- __set_bit(BTN_RIGHT, input_dev->keybit);
input_set_capability(input_dev, EV_REL, REL_WHEEL);
break;
case INTUOSPS:
/* touch interface does not have the pad device */
if (features->device_type != BTN_TOOL_PEN)
- return 1;
+ return -ENODEV;
for (i = 0; i < 7; i++)
__set_bit(BTN_0 + i, input_dev->keybit);
case INTUOSHT:
case BAMBOO_PT:
/* pad device is on the touch interface */
- if (features->device_type != BTN_TOOL_FINGER)
- return 1;
+ if ((features->device_type != BTN_TOOL_FINGER) ||
+ /* Bamboo Pen only tablet does not have pad */
+ ((features->type == BAMBOO_PT) && !features->touch_max))
+ return -ENODEV;
__clear_bit(ABS_MISC, input_dev->absbit);
default:
/* no pad supported */
- return 1;
+ return -ENODEV;
}
return 0;
}
{ "Wacom ISDv5 309", .type = WACOM_24HDT, /* Touch */
.oVid = USB_VENDOR_ID_WACOM, .oPid = 0x0307, .touch_max = 10,
.check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
+static const struct wacom_features wacom_features_0x30A =
+ { "Wacom ISDv5 30A", 59352, 33648, 2047, 63,
+ CINTIQ_HYBRID, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 200, 200,
+ .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x30C };
+static const struct wacom_features wacom_features_0x30C =
+ { "Wacom ISDv5 30C", .type = WACOM_24HDT, /* Touch */
+ .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x30A, .touch_max = 10,
+ .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
+static const struct wacom_features wacom_features_0x323 =
+ { "Wacom Intuos P M", 21600, 13500, 1023, 31,
+ INTUOSHT, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
+ .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
+
+static const struct wacom_features wacom_features_HID_ANY_ID =
+ { "Wacom HID", .type = HID_GENERIC };
#define USB_DEVICE_WACOM(prod) \
HID_DEVICE(BUS_USB, HID_GROUP_WACOM, USB_VENDOR_ID_WACOM, prod),\
{ USB_DEVICE_WACOM(0x304) },
{ USB_DEVICE_WACOM(0x307) },
{ USB_DEVICE_WACOM(0x309) },
+ { USB_DEVICE_WACOM(0x30A) },
+ { USB_DEVICE_WACOM(0x30C) },
{ USB_DEVICE_WACOM(0x30E) },
{ USB_DEVICE_WACOM(0x314) },
{ USB_DEVICE_WACOM(0x315) },
{ USB_DEVICE_WACOM(0x317) },
+ { USB_DEVICE_WACOM(0x323) },
{ USB_DEVICE_WACOM(0x4001) },
{ USB_DEVICE_WACOM(0x4004) },
{ USB_DEVICE_WACOM(0x5000) },
{ USB_DEVICE_WACOM(0x5002) },
+
+ { USB_DEVICE_WACOM(HID_ANY_ID) },
{ }
};
MODULE_DEVICE_TABLE(hid, wacom_ids);