while (kfifo_avail(fifo) < size) { if (!warned)
hid_warn(hdev, "%s: kfifo has filled, starting to drop events\n", __func__);
warned = true;
kfifo_skip(fifo);
}
kfifo_in(fifo, raw_data, size);
}
staticvoid wacom_wac_queue_flush(struct hid_device *hdev, struct kfifo_rec_ptr_2 *fifo)
{ while (!kfifo_is_empty(fifo)) { int size = kfifo_peek_len(fifo);
u8 *buf; unsignedint count; int err;
buf = kzalloc(size, GFP_KERNEL); if (!buf) {
kfifo_skip(fifo); continue;
}
count = kfifo_out(fifo, buf, size); if (count != size) { // Hard to say what is the "right" action in this // circumstance. Skipping the entry and continuing // to flush seems reasonable enough, however.
hid_warn(hdev, "%s: removed fifo entry with unexpected size\n",
__func__);
kfree(buf); continue;
}
err = hid_report_raw_event(hdev, HID_INPUT_REPORT, buf, size, false); if (err) {
hid_warn(hdev, "%s: unable to flush event due to error %d\n",
__func__, err);
}
if (wacom_wac->serial[0] || !(features->quirks & WACOM_QUIRK_TOOLSERIAL)) return 0;
/* Queue events which have invalid tool type or serial number */ for (i = 0; i < report->maxfield; i++) { for (j = 0; j < report->field[i]->maxusage; j++) { struct hid_field *field = report->field[i]; struct hid_usage *usage = &field->usage[j]; unsignedint equivalent_usage = wacom_equivalent_usage(usage->hid); unsignedint offset; unsignedint size; unsignedint value;
/* * wacom->hdev should never be null, but surprisingly, I had the case * once while unplugging the Wacom Wireless Receiver.
*/ if (wacom->hdev)
hid_hw_close(wacom->hdev);
}
/* * Calculate the resolution of the X or Y axis using hidinput_calc_abs_res.
*/ staticint wacom_calc_hid_res(int logical_extents, int physical_extents, unsigned unit, int exponent)
{ struct hid_field field = {
.logical_maximum = logical_extents,
.physical_maximum = physical_extents,
.unit = unit,
.unit_exponent = exponent,
};
/* * The Dell Canvas 27 needs to be switched to its vendor-defined * report to provide the best resolution.
*/ if (hdev->vendor == USB_VENDOR_ID_WACOM &&
hdev->product == 0x4200 &&
field->application == HID_UP_MSVENDOR) {
wacom->wacom_wac.mode_report = field->report->id;
wacom->wacom_wac.mode_value = 2;
}
/* * ISDv4 devices which predate HID's adoption of the * HID_DG_BARELSWITCH2 usage use 0x000D0000 in its * position instead. We can accurately detect if a * usage with that value should be HID_DG_BARRELSWITCH2 * based on the surrounding usages, which have remained * constant across generations.
*/ if (features->type == HID_GENERIC &&
usage->hid == 0x000D0000 &&
field->application == HID_DG_PEN &&
field->physical == HID_DG_STYLUS) { int i = usage->usage_index;
/* * Wacom's AES devices use different vendor-defined usages to * report serial number information compared to their branded * hardware. The usages are also sometimes ill-defined and do * not have the correct logical min/max values set. Lets patch * the descriptor to use the branded usage convention and fix * the errors.
*/ if (usage->hid == WACOM_HID_WT_SERIALNUMBER &&
field->report_size == 16 &&
field->index + 2 < field->report->maxfield) { struct hid_field *a = field->report->field[field->index + 1]; struct hid_field *b = field->report->field[field->index + 2];
/* 2nd-generation Intuos Pro Large has incorrect Y maximum */ if (hdev->vendor == USB_VENDOR_ID_WACOM &&
hdev->product == 0x0358 &&
WACOM_PEN_FIELD(field) &&
equivalent_usage == HID_GD_Y) {
field->logical_maximum = 43200;
}
}
switch (equivalent_usage) { case WACOM_HID_WD_TOUCH_RING_SETTING:
wacom->generic_has_leds = true; break; case HID_DG_CONTACTMAX: /* leave touch_max as is if predefined */ if (!features->touch_max) { /* read manually */
n = hid_report_len(field->report);
data = hid_alloc_report_buf(field->report, GFP_KERNEL); if (!data) break;
data[0] = field->report->id;
ret = wacom_get_report(hdev, HID_FEATURE_REPORT,
data, n, WAC_CMD_RETRIES); if (ret == n && features->type == HID_GENERIC) {
ret = hid_report_raw_event(hdev,
HID_FEATURE_REPORT, data, n, 0);
} elseif (ret == 2 && features->type != HID_GENERIC) {
features->touch_max = data[1];
} else {
features->touch_max = 16;
hid_warn(hdev, "wacom_feature_mapping: " "could not get HID_DG_CONTACTMAX, " "defaulting to %d\n",
features->touch_max);
}
kfree(data);
} break; case HID_DG_INPUTMODE: /* Ignore if value index is out of bounds. */ if (usage->usage_index >= field->report_count) {
dev_err(&hdev->dev, "HID_DG_INPUTMODE out of range\n"); break;
}
case WACOM_HID_WD_DATAMODE:
wacom->wacom_wac.mode_report = field->report->id;
wacom->wacom_wac.mode_value = 2; break;
case WACOM_HID_UP_G9: case WACOM_HID_UP_G11: if (field->report->id == 0x03 &&
(field->application == WACOM_HID_G9_TOUCHSCREEN ||
field->application == WACOM_HID_G11_TOUCHSCREEN)) {
wacom->wacom_wac.mode_report = field->report->id;
wacom->wacom_wac.mode_value = 0;
} break; case WACOM_HID_WD_OFFSETLEFT: case WACOM_HID_WD_OFFSETTOP: case WACOM_HID_WD_OFFSETRIGHT: case WACOM_HID_WD_OFFSETBOTTOM: /* read manually */
n = hid_report_len(field->report);
data = hid_alloc_report_buf(field->report, GFP_KERNEL); if (!data) break;
data[0] = field->report->id;
ret = wacom_get_report(hdev, HID_FEATURE_REPORT,
data, n, WAC_CMD_RETRIES); if (ret == n) {
ret = hid_report_raw_event(hdev, HID_FEATURE_REPORT,
data, n, 0);
} else {
hid_warn(hdev, "%s: could not retrieve sensor offsets\n",
__func__);
}
kfree(data); break;
}
}
/* * Interface Descriptor of wacom devices can be incomplete and * inconsistent so wacom_features table is used to store stylus * device's packet lengths, various maximum values, and tablet * resolution based on product ID's. * * For devices that contain 2 interfaces, wacom_features table is * inaccurate for the touch interface. Since the Interface Descriptor * for touch interfaces has pretty complete data, this function exists * to query tablet for this missing information instead of hard coding in * an additional table. * * A typical Interface Descriptor for a stylus will contain a * boot mouse application collection that is not of interest and this * function will ignore it. * * It also contains a digitizer application collection that also is not * of interest since any information it contains would be duplicate * of what is in wacom_features. Usually it defines a report of an array * of bytes that could be used as max length of the stylus packet returned. * If it happens to define a Digitizer-Stylus Physical Collection then * the X and Y logical values contain valid data but it is ignored. * * A typical Interface Descriptor for a touch interface will contain a * Digitizer-Finger Physical Collection which will define both logical * X/Y maximum as well as the physical size of tablet. Since touch * interfaces haven't supported pressure or distance, this is enough * information to override invalid values in the wacom_features table. * * Intuos5 touch interface and 3rd gen Bamboo Touch do not contain useful * data. We deal with them after returning from this function.
*/ staticvoid wacom_usage_mapping(struct hid_device *hdev, struct hid_field *field, struct hid_usage *usage)
{ struct wacom *wacom = hid_get_drvdata(hdev); struct wacom_features *features = &wacom->wacom_wac.features; bool finger = WACOM_FINGER_FIELD(field); bool pen = WACOM_PEN_FIELD(field); unsigned equivalent_usage = wacom_equivalent_usage(usage->hid);
/* * Requiring Stylus Usage will ignore boot mouse * X/Y values and some cases of invalid Digitizer X/Y * values commonly reported.
*/ if (pen)
features->device_type |= WACOM_DEVICETYPE_PEN; elseif (finger)
features->device_type |= WACOM_DEVICETYPE_TOUCH; else return;
wacom_hid_usage_quirk(hdev, field, usage);
switch (equivalent_usage) { case HID_GD_X:
features->x_max = field->logical_maximum; if (finger) {
features->x_phy = field->physical_maximum; if ((features->type != BAMBOO_PT) &&
(features->type != BAMBOO_TOUCH)) {
features->unit = field->unit;
features->unitExpo = field->unit_exponent;
}
} 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->type != BAMBOO_TOUCH)) {
features->unit = field->unit;
features->unitExpo = field->unit_exponent;
}
} break; case HID_DG_TIPPRESSURE: if (pen)
features->pressure_max = field->logical_maximum; break;
}
if (features->type == HID_GENERIC)
wacom_wac_usage_mapping(hdev, field, usage);
}
if (features->type == HID_GENERIC) { /* Any last-minute generic device setup */ if (wacom_wac->has_mode_change) { if (wacom_wac->is_direct_mode)
features->device_type |= WACOM_DEVICETYPE_DIRECT; else
features->device_type &= ~WACOM_DEVICETYPE_DIRECT;
}
if (features->touch_max > 1) { if (features->device_type & WACOM_DEVICETYPE_DIRECT)
input_mt_init_slots(wacom_wac->touch_input,
wacom_wac->features.touch_max,
INPUT_MT_DIRECT); else
input_mt_init_slots(wacom_wac->touch_input,
wacom_wac->features.touch_max,
INPUT_MT_POINTER);
}
}
}
staticvoid 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;
/* * Note that if the raw queries fail, it's not a hard failure * and it is safe to continue
*/
hid_warn(hdev, "failed to poke device, command %d, err %d\n",
rep_data[0], ret); break; case INTUOS4WL: if (speed == 1)
wacom->wacom_wac.bt_features &= ~0x20; else
wacom->wacom_wac.bt_features |= 0x20;
ret = wacom_set_report(hdev, HID_FEATURE_REPORT, rep_data, 2,
1); if (ret >= 0)
wacom->wacom_wac.bt_high_speed = speed; break;
}
return 0;
}
/* * Switch the tablet into its most-capable mode. Wacom tablets are * typically configured to power-up in a mode which sends mouse-like * reports to the OS. To get absolute position, pressure data, etc. * from the tablet, it is necessary to switch the tablet out of this * mode and into one which sends the full range of tablet data.
*/ staticint _wacom_query_tablet_data(struct wacom *wacom)
{ struct hid_device *hdev = wacom->hdev; struct wacom_wac *wacom_wac = &wacom->wacom_wac; struct wacom_features *features = &wacom_wac->features;
if (hdev->bus == BUS_BLUETOOTH) return wacom_bt_query_tablet_data(hdev, 1, features);
/* * The wireless device HID is basic and layout conflicts with * other tablets (monitor and touch interface can look like pen). * Skip the query for this type and modify defaults based on * interface number.
*/ if (features->type == WIRELESS && intf) { if (intf->cur_altsetting->desc.bInterfaceNumber == 0)
features->device_type = WACOM_DEVICETYPE_WL_MONITOR; else
features->device_type = WACOM_DEVICETYPE_NONE; return;
}
/* The defined oVid/oPid must match that of the sibling */ if (features->oVid != HID_ANY_ID && sibling->vendor != oVid) returnfalse; if (features->oPid != HID_ANY_ID && sibling->product != oPid) returnfalse;
/* * Devices with the same VID/PID must share the same physical * device path, while those with different VID/PID must share * the same physical parent device path.
*/ if (hdev->vendor == sibling->vendor && hdev->product == sibling->product) { if (!hid_compare_device_paths(hdev, sibling, '/')) returnfalse;
} else { if (!hid_compare_device_paths(hdev, sibling, '.')) returnfalse;
}
/* Skip the remaining heuristics unless you are a HID_GENERIC device */ if (features->type != HID_GENERIC) returntrue;
/* * Direct-input devices may not be siblings of indirect-input * devices.
*/ if ((features->device_type & WACOM_DEVICETYPE_DIRECT) &&
!(sibling_features->device_type & WACOM_DEVICETYPE_DIRECT)) returnfalse;
/* * Indirect-input devices may not be siblings of direct-input * devices.
*/ if (!(features->device_type & WACOM_DEVICETYPE_DIRECT) &&
(sibling_features->device_type & WACOM_DEVICETYPE_DIRECT)) returnfalse;
/* Pen devices may only be siblings of touch devices */ if ((features->device_type & WACOM_DEVICETYPE_PEN) &&
!(sibling_features->device_type & WACOM_DEVICETYPE_TOUCH)) returnfalse;
/* Touch devices may only be siblings of pen devices */ if ((features->device_type & WACOM_DEVICETYPE_TOUCH) &&
!(sibling_features->device_type & WACOM_DEVICETYPE_PEN)) returnfalse;
/* * No reason could be found for these two devices to NOT be * siblings, so there's a good chance they ARE siblings
*/ returntrue;
}
/* Try to find an already-probed interface from the same device */
list_for_each_entry(data, &wacom_udev_list, list) { if (hid_compare_device_paths(hdev, data->dev, '/')) {
kref_get(&data->kref); return data;
}
}
/* Fallback to finding devices that appear to be "siblings" */
list_for_each_entry(data, &wacom_udev_list, list) { if (wacom_are_sibling(hdev, data->dev)) {
kref_get(&data->kref); return data;
}
}
data = wacom_get_hdev_data(hdev); if (!data) {
data = kzalloc(sizeof(struct wacom_hdev_data), GFP_KERNEL); if (!data) {
mutex_unlock(&wacom_udev_list_lock); return -ENOMEM;
}
staticint wacom_led_putimage(struct wacom *wacom, int button_id, u8 xfer_id, constunsigned len, constvoid *img)
{ unsignedchar *buf; int i, retval; constunsigned chunk_len = len / 4; /* 4 chunks are needed to be sent */
staticint wacom_led_groups_alloc_and_register_one(struct device *dev, struct wacom *wacom, int group_id, int count, bool read_only)
{ struct wacom_led *leds; int i, error;
if (group_id >= wacom->led.count || count <= 0) return -EINVAL;
if (!devres_open_group(dev, &wacom->led.groups[group_id], GFP_KERNEL)) return -ENOMEM;
/* * There is a bug (?) in devm_led_classdev_register() in which its * increments the refcount of the parent. If the parent is an input * device, that means the ref count never reaches 0 when * devm_input_device_release() gets called. * This means that the LEDs are still there after disconnect. * Manually force the release of the group so that the leds are released * once we are done using them.
*/
error = devm_add_action_or_reset(&wacom->hdev->dev,
wacom_led_groups_release_one,
&wacom->led.groups[group_id]); if (error) return error;
/* * wacom_led_next: gives the next available led with a wacom trigger. * * returns the next available struct wacom_led which has its default trigger * or the current one if none is available.
*/ struct wacom_led *wacom_led_next(struct wacom *wacom, struct wacom_led *cur)
{ struct wacom_led *next_led; int group, next;
if (!wacom || !cur) return NULL;
group = cur->group;
next = cur->id;
do {
next_led = wacom_led_find(wacom, group, ++next); if (!next_led || next_led == cur) return next_led;
} while (next_led->cdev.trigger != &next_led->trigger);
staticint wacom_leds_alloc_and_register(struct wacom *wacom, int group_count, int led_per_group, bool read_only)
{ struct device *dev; int i, error;
if (!wacom->wacom_wac.pad_input) return -EINVAL;
dev = &wacom->wacom_wac.pad_input->dev;
error = wacom_led_groups_allocate(wacom, group_count); if (error) return error;
for (i = 0; i < group_count; i++) {
error = wacom_led_groups_alloc_and_register_one(dev, wacom, i,
led_per_group,
read_only); if (error) return error;
}
return 0;
}
int wacom_initialize_leds(struct wacom *wacom)
{ int error;
if (!(wacom->wacom_wac.features.device_type & WACOM_DEVICETYPE_PAD)) return 0;
/* Initialize default values */ switch (wacom->wacom_wac.features.type) { case HID_GENERIC: if (!wacom->generic_has_leds) return 0;
wacom->led.llv = 100;
wacom->led.max_llv = 100;
if (!pen_input_dev || !touch_input_dev || !pad_input_dev) return -EINVAL;
error = wacom_setup_pen_input_capabilities(pen_input_dev, wacom_wac); if (error) { /* no pen in use on this interface */
input_free_device(pen_input_dev);
wacom_wac->pen_input = NULL;
pen_input_dev = NULL;
}
error = wacom_setup_touch_input_capabilities(touch_input_dev, wacom_wac); if (error) { /* no touch in use on this interface */
input_free_device(touch_input_dev);
wacom_wac->touch_input = NULL;
touch_input_dev = NULL;
}
error = wacom_setup_pad_input_capabilities(pad_input_dev, wacom_wac); if (error) { /* no pad events using this interface */
input_free_device(pad_input_dev);
wacom_wac->pad_input = NULL;
pad_input_dev = NULL;
}
/* * Not all devices report physical dimensions from HID. * Compute the default from hardcoded logical dimension * and resolution before driver overwrites them.
*/ staticvoid wacom_set_default_phy(struct wacom_features *features)
{ if (features->x_resolution) {
features->x_phy = (features->x_max * 100) /
features->x_resolution;
features->y_phy = (features->y_max * 100) /
features->y_resolution;
}
}
staticvoid wacom_calculate_res(struct wacom_features *features)
{ /* set unit to "100th of a mm" for devices not reported by HID */ if (!features->unit) {
features->unit = 0x11;
features->unitExpo = -3;
}
if (wacom_wac->has_mute_touch_switch) {
wacom_wac->shared->has_mute_touch_switch = true; /* Hardware touch switch may be off. Wait until * we know the switch state to decide is_touch_on. * Softkey state should be initialized to "on" to * match historic default.
*/ if (wacom_wac->is_soft_touch_switch)
wacom_wac->shared->is_touch_on = true;
}
features->pktlen = wacom_compute_pktlen(hdev); if (!features->pktlen) return -ENODEV;
if (!devres_open_group(&hdev->dev, wacom, GFP_KERNEL)) return -ENOMEM;
error = wacom_devm_kfifo_alloc(wacom); if (error) goto fail;
wacom->resources = true;
error = wacom_allocate_inputs(wacom); if (error) goto fail;
/* * Bamboo Pad has a generic hid handling for the Pen, and we switch it * into debug mode for the touch part. * We ignore the other interfaces.
*/ if (features->type == BAMBOO_PAD) { if (features->pktlen == WACOM_PKGLEN_PENABLED) {
features->type = HID_GENERIC;
} elseif ((features->pktlen != WACOM_PKGLEN_BPAD_TOUCH) &&
(features->pktlen != WACOM_PKGLEN_BPAD_TOUCH_USB)) {
error = -ENODEV; goto fail;
}
}
/* set the default size in case we do not get them from hid */
wacom_set_default_phy(features);
/* Retrieve the physical and logical size for touch devices */
wacom_retrieve_hid_descriptor(hdev, features);
wacom_setup_device_quirks(wacom);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.