* [PATCH v4 07/12] HID: input: enable Totem on the Dell Canvas 27
From: Benjamin Tissoires @ 2018-07-13 14:13 UTC (permalink / raw)
To: Jiri Kosina, Dmitry Torokhov
Cc: Mario.Limonciello, Peter Hutterer, linux-input, linux-kernel,
Benjamin Tissoires
In-Reply-To: <20180713141354.7286-1-benjamin.tissoires@redhat.com>
The Dell Canvas 27 has a tool that can be put on the surface and acts
as a dial. The firmware processes the detection of the tool and forward
regular HID reports with X, Y, Azimuth, rotation, width/height.
The firmware also exports Contact ID, Countact Count which may hint that
several totems can be used at the same time (the FW only supports one).
We can tell that MT_TOOL_DIAL will be reported by setting the min/max
of ABS_MT_TOOL_TYPE to MT_TOOL_DIAL.
This tool is aimed at being used by the system and not the applications,
so the user space processing should not go through the regular touch
inputs.
We set INPUT_PROP_DIRECT which applies ID_INPUT_TOUCHSCREEN to this new
type of devices, but we will counter this for the time being with the
special udev hwdb entry mentioned above.
Link: https://bugzilla.redhat.com/show_bug.cgi?id=1511846
Acked-by: Peter Hutterer <peter.hutterer@who-t.net>
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
---
no changes in v4
no changes in v3
changes in v2:
- manually declare ABS_MT_TOOL_TYPE and set its min/max to MT_TOOL_DIAL
to explain which tool it will set
---
drivers/hid/hid-input.c | 3 +++
drivers/hid/hid-multitouch.c | 48 +++++++++++++++++++++++++++++++-------------
include/linux/hid.h | 6 ++++++
3 files changed, 43 insertions(+), 14 deletions(-)
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index ab93dd5927c3..4e94ea3e280a 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -1550,6 +1550,9 @@ static struct hid_input *hidinput_allocate(struct hid_device *hid,
case HID_GD_WIRELESS_RADIO_CTLS:
suffix = "Wireless Radio Control";
break;
+ case HID_GD_SYSTEM_MULTIAXIS:
+ suffix = "System Multi Axis";
+ break;
default:
break;
}
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index 346e9caef6f3..a4a274ebfbef 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -665,7 +665,8 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
/*
* Model touchscreens providing buttons as touchpads.
*/
- if ((usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON) {
+ if (field->application == HID_DG_TOUCHSCREEN &&
+ (usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON) {
app->mt_flags |= INPUT_MT_POINTER;
td->inputmode_value = MT_INPUTMODE_TOUCHPAD;
}
@@ -692,6 +693,19 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
set_abs(hi->input, code, field, cls->sn_move);
+ /*
+ * A system multi-axis that exports X and Y has a high
+ * chance of being used directly on a surface
+ */
+ if (field->application == HID_GD_SYSTEM_MULTIAXIS) {
+ __set_bit(INPUT_PROP_DIRECT,
+ hi->input->propbit);
+ input_set_abs_params(hi->input,
+ ABS_MT_TOOL_TYPE,
+ MT_TOOL_DIAL,
+ MT_TOOL_DIAL, 0, 0);
+ }
+
return 1;
case HID_GD_Y:
if (prev_usage && (prev_usage->hid == usage->hid)) {
@@ -725,7 +739,9 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
MT_STORE_FIELD(confidence_state);
return 1;
case HID_DG_TIPSWITCH:
- input_set_capability(hi->input, EV_KEY, BTN_TOUCH);
+ if (field->application != HID_GD_SYSTEM_MULTIAXIS)
+ input_set_capability(hi->input,
+ EV_KEY, BTN_TOUCH);
MT_STORE_FIELD(tip_state);
return 1;
case HID_DG_CONTACTID:
@@ -802,6 +818,10 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
field->application == HID_DG_TOUCHPAD &&
(usage->hid & HID_USAGE) > 1)
code--;
+
+ if (field->application == HID_GD_SYSTEM_MULTIAXIS)
+ code = BTN_0 + ((usage->hid - 1) & HID_USAGE);
+
hid_map_usage(hi, usage, bit, max, EV_KEY, code);
input_set_capability(hi->input, EV_KEY, code);
return 1;
@@ -899,6 +919,7 @@ static int mt_process_slot(struct mt_device *td, struct input_dev *input,
bool inrange_state = false;
int active;
int slotnum;
+ int tool = MT_TOOL_FINGER;
if (!slot)
return -EINVAL;
@@ -939,8 +960,11 @@ static int mt_process_slot(struct mt_device *td, struct input_dev *input,
active = (*slot->tip_state || inrange_state) && confidence_state;
+ if (app->application == HID_GD_SYSTEM_MULTIAXIS)
+ tool = MT_TOOL_DIAL;
+
input_mt_slot(input, slotnum);
- input_mt_report_slot_state(input, MT_TOOL_FINGER, active);
+ input_mt_report_slot_state(input, tool, active);
if (active) {
/* this finger is in proximity of the sensor */
int wide = (*slot->w > *slot->h);
@@ -1203,6 +1227,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
field->application != HID_GD_SYSTEM_CONTROL &&
field->application != HID_CP_CONSUMER_CONTROL &&
field->application != HID_GD_WIRELESS_RADIO_CTLS &&
+ field->application != HID_GD_SYSTEM_MULTIAXIS &&
!(field->application == HID_VD_ASUS_CUSTOM_MEDIA_KEYS &&
application->quirks & MT_QUIRK_ASUS_CUSTOM_UP))
return -1;
@@ -1230,9 +1255,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
return 1;
}
- if (rdata->is_mt_collection &&
- (field->application == HID_DG_TOUCHSCREEN ||
- field->application == HID_DG_TOUCHPAD))
+ if (rdata->is_mt_collection)
return mt_touch_input_mapping(hdev, hi, field, usage, bit, max,
application);
@@ -1244,15 +1267,11 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi,
struct hid_field *field, struct hid_usage *usage,
unsigned long **bit, int *max)
{
- /*
- * some egalax touchscreens have "application == HID_DG_TOUCHSCREEN"
- * for the stylus.
- */
- if (field->physical == HID_DG_STYLUS)
- return 0;
+ struct mt_device *td = hid_get_drvdata(hdev);
+ struct mt_report_data *rdata;
- if (field->application == HID_DG_TOUCHSCREEN ||
- field->application == HID_DG_TOUCHPAD) {
+ rdata = mt_find_report_data(td, field->report);
+ if (rdata && rdata->is_mt_collection) {
/* We own these mappings, tell hid-input to ignore them */
return -1;
}
@@ -1460,6 +1479,7 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi)
case HID_GD_SYSTEM_CONTROL:
case HID_CP_CONSUMER_CONTROL:
case HID_GD_WIRELESS_RADIO_CTLS:
+ case HID_GD_SYSTEM_MULTIAXIS:
/* already handled by hid core */
break;
case HID_DG_TOUCHSCREEN:
diff --git a/include/linux/hid.h b/include/linux/hid.h
index 773bcb1d4044..2e4498d52a2f 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -190,6 +190,12 @@ struct hid_item {
* http://www.usb.org/developers/hidpage/HUTRR40RadioHIDUsagesFinal.pdf
*/
#define HID_GD_WIRELESS_RADIO_CTLS 0x0001000c
+/*
+ * System Multi-Axis, see:
+ * http://www.usb.org/developers/hidpage/HUTRR62_-_Generic_Desktop_CA_for_System_Multi-Axis_Controllers.txt
+ */
+#define HID_GD_SYSTEM_MULTIAXIS 0x0001000e
+
#define HID_GD_X 0x00010030
#define HID_GD_Y 0x00010031
#define HID_GD_Z 0x00010032
--
2.14.3
^ permalink raw reply related
* [PATCH v4 06/12] HID: multitouch: remove one copy of values
From: Benjamin Tissoires @ 2018-07-13 14:13 UTC (permalink / raw)
To: Jiri Kosina, Dmitry Torokhov
Cc: Mario.Limonciello, Peter Hutterer, linux-input, linux-kernel,
Benjamin Tissoires
In-Reply-To: <20180713141354.7286-1-benjamin.tissoires@redhat.com>
The current way of handling multitouch data is not very straightforward:
- in mt_event() we do nothing
- in mt_report() we:
- do some gym to fetch the scantime and the contact count
- then iterate over the input fields where we copy the data to a
temporary place
- when we see the last field in a slot, we then use this data to emit
the input data
A more streamlined way is to first get all of the address in the report
of all fields, and then just pick the fields we are interested in in
mt_report()
Acked-by: Peter Hutterer <peter.hutterer@who-t.net>
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
---
no changes in v4
no changes in v3
no changes in v2
---
drivers/hid/hid-multitouch.c | 545 +++++++++++++++++++++----------------------
1 file changed, 264 insertions(+), 281 deletions(-)
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index a2c10fc62ef2..346e9caef6f3 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -87,30 +87,34 @@ enum latency_mode {
#define MT_IO_FLAGS_ACTIVE_SLOTS 1
#define MT_IO_FLAGS_PENDING_SLOTS 2
-struct mt_slot {
- __s32 x, y, cx, cy, p, w, h, a;
- __s32 contactid; /* the device ContactID assigned to this slot */
- bool touch_state; /* is the touch valid? */
- bool inrange_state; /* is the finger in proximity of the sensor? */
- bool confidence_state; /* is the touch made by a finger? */
- bool has_azimuth; /* the contact reports azimuth */
+static const bool mtrue = true; /* default for true */
+static const bool mfalse; /* default for false */
+static const __s32 mzero; /* default for 0 */
+
+#define DEFAULT_TRUE ((void *)&mtrue)
+#define DEFAULT_FALSE ((void *)&mfalse)
+#define DEFAULT_ZERO ((void *)&mzero)
+
+struct mt_usages {
+ struct list_head list;
+ __s32 *x, *y, *cx, *cy, *p, *w, *h, *a;
+ __s32 *contactid; /* the device ContactID assigned to this slot */
+ bool *tip_state; /* is the touch valid? */
+ bool *inrange_state; /* is the finger in proximity of the sensor? */
+ bool *confidence_state; /* is the touch made by a finger? */
};
struct mt_application {
struct list_head list;
unsigned int application;
+ struct list_head mt_usages; /* mt usages list */
__s32 quirks;
- struct mt_slot curdata; /* placeholder of incoming data */
-
- int cc_index; /* contact count field index in the report */
- int cc_value_index; /* contact count value index in the field */
- int scantime_index; /* scantime field index in the report */
- int scantime_val_index; /* scantime value index in the field */
- unsigned int last_slot_field; /* the last field of a slot */
- bool curvalid; /* is the current contact valid? */
+ __s32 *scantime; /* scantime reported */
+ __s32 scantime_logical_max; /* max value for raw scantime */
+ __s32 *raw_cc; /* contact count in the report */
int left_button_state; /* left button state */
unsigned int mt_flags; /* flags to pass to input-mt */
@@ -142,11 +146,6 @@ struct mt_class {
bool export_all_inputs; /* do not ignore mouse, keyboards, etc... */
};
-struct mt_fields {
- unsigned usages[HID_MAX_FIELDS];
- unsigned int length;
-};
-
struct mt_report_data {
struct list_head list;
struct hid_report *report;
@@ -158,8 +157,6 @@ struct mt_device {
struct mt_class mtclass; /* our mt device class */
struct timer_list release_timer; /* to release sticky fingers */
struct hid_device *hdev; /* hid_device we're attached to */
- struct mt_fields *fields; /* temporary placeholder for storing the
- multitouch fields */
unsigned long mt_io_flags; /* mt flags (MT_IO_FLAGS_*) */
__u8 inputmode_value; /* InputMode HID feature value */
__u8 maxcontacts;
@@ -225,10 +222,11 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app);
* to a valid contact that was just read.
*/
-static int cypress_compute_slot(struct mt_application *app)
+static int cypress_compute_slot(struct mt_application *application,
+ struct mt_usages *slot)
{
- if (app->curdata.contactid != 0 || app->num_received == 0)
- return app->curdata.contactid;
+ if (*slot->contactid != 0 || application->num_received == 0)
+ return *slot->contactid;
else
return -1;
}
@@ -483,6 +481,34 @@ static void set_abs(struct input_dev *input, unsigned int code,
input_abs_set_res(input, code, hidinput_calc_abs_res(field, code));
}
+static struct mt_usages *mt_allocate_usage(struct hid_device *hdev,
+ struct mt_application *application)
+{
+ struct mt_usages *usage;
+
+ usage = devm_kzalloc(&hdev->dev, sizeof(*usage), GFP_KERNEL);
+ if (!usage)
+ return NULL;
+
+ /* set some defaults so we do not need to check for null pointers */
+ usage->x = DEFAULT_ZERO;
+ usage->y = DEFAULT_ZERO;
+ usage->cx = DEFAULT_ZERO;
+ usage->cy = DEFAULT_ZERO;
+ usage->p = DEFAULT_ZERO;
+ usage->w = DEFAULT_ZERO;
+ usage->h = DEFAULT_ZERO;
+ usage->a = DEFAULT_ZERO;
+ usage->contactid = DEFAULT_ZERO;
+ usage->tip_state = DEFAULT_FALSE;
+ usage->inrange_state = DEFAULT_FALSE;
+ usage->confidence_state = DEFAULT_TRUE;
+
+ list_add_tail(&usage->list, &application->mt_usages);
+
+ return usage;
+}
+
static struct mt_application *mt_allocate_application(struct mt_device *td,
unsigned int application)
{
@@ -494,6 +520,7 @@ static struct mt_application *mt_allocate_application(struct mt_device *td,
return NULL;
mt_application->application = application;
+ INIT_LIST_HEAD(&mt_application->mt_usages);
if (application == HID_DG_TOUCHSCREEN)
mt_application->mt_flags |= INPUT_MT_DIRECT;
@@ -506,8 +533,8 @@ static struct mt_application *mt_allocate_application(struct mt_device *td,
td->inputmode_value = MT_INPUTMODE_TOUCHPAD;
}
- mt_application->cc_index = -1;
- mt_application->scantime_index = -1;
+ mt_application->scantime = DEFAULT_ZERO;
+ mt_application->raw_cc = DEFAULT_ZERO;
mt_application->quirks = td->mtclass.quirks;
list_add_tail(&mt_application->list, &td->applications);
@@ -587,17 +614,45 @@ static struct mt_report_data *mt_find_report_data(struct mt_device *td,
return rdata;
}
-static void mt_store_field(struct hid_usage *usage, struct mt_device *td,
- struct hid_input *hi)
+static void mt_store_field(struct hid_device *hdev,
+ struct mt_application *application,
+ __s32 *value,
+ size_t offset)
{
- struct mt_fields *f = td->fields;
+ struct mt_usages *usage;
+ __s32 **target;
+
+ if (list_empty(&application->mt_usages))
+ usage = mt_allocate_usage(hdev, application);
+ else
+ usage = list_last_entry(&application->mt_usages,
+ struct mt_usages,
+ list);
- if (f->length >= HID_MAX_FIELDS)
+ if (!usage)
return;
- f->usages[f->length++] = usage->hid;
+ target = (__s32 **)((char *)usage + offset);
+
+ /* the value has already been filled, create a new slot */
+ if (*target != DEFAULT_TRUE &&
+ *target != DEFAULT_FALSE &&
+ *target != DEFAULT_ZERO) {
+ usage = mt_allocate_usage(hdev, application);
+ if (!usage)
+ return;
+
+ target = (__s32 **)((char *)usage + offset);
+ }
+
+ *target = value;
}
+#define MT_STORE_FIELD(__name) \
+ mt_store_field(hdev, app, \
+ &field->value[usage->usage_index], \
+ offsetof(struct mt_usages, __name))
+
static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
struct hid_field *field, struct hid_usage *usage,
unsigned long **bit, int *max, struct mt_application *app)
@@ -627,24 +682,28 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
case HID_UP_GENDESK:
switch (usage->hid) {
case HID_GD_X:
- if (prev_usage && (prev_usage->hid == usage->hid))
+ if (prev_usage && (prev_usage->hid == usage->hid)) {
code = ABS_MT_TOOL_X;
- else
+ MT_STORE_FIELD(cx);
+ } else {
code = ABS_MT_POSITION_X;
+ MT_STORE_FIELD(x);
+ }
- hid_map_usage(hi, usage, bit, max, EV_ABS, code);
set_abs(hi->input, code, field, cls->sn_move);
- mt_store_field(usage, td, hi);
+
return 1;
case HID_GD_Y:
- if (prev_usage && (prev_usage->hid == usage->hid))
+ if (prev_usage && (prev_usage->hid == usage->hid)) {
code = ABS_MT_TOOL_Y;
- else
+ MT_STORE_FIELD(cy);
+ } else {
code = ABS_MT_POSITION_Y;
+ MT_STORE_FIELD(y);
+ }
- hid_map_usage(hi, usage, bit, max, EV_ABS, code);
set_abs(hi->input, code, field, cls->sn_move);
- mt_store_field(usage, td, hi);
+
return 1;
}
return 0;
@@ -653,40 +712,33 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
switch (usage->hid) {
case HID_DG_INRANGE:
if (app->quirks & MT_QUIRK_HOVERING) {
- hid_map_usage(hi, usage, bit, max,
- EV_ABS, ABS_MT_DISTANCE);
input_set_abs_params(hi->input,
ABS_MT_DISTANCE, 0, 1, 0, 0);
}
- mt_store_field(usage, td, hi);
+ MT_STORE_FIELD(inrange_state);
return 1;
case HID_DG_CONFIDENCE:
if ((cls->name == MT_CLS_WIN_8 ||
cls->name == MT_CLS_WIN_8_DUAL) &&
field->application == HID_DG_TOUCHPAD)
app->quirks |= MT_QUIRK_CONFIDENCE;
- mt_store_field(usage, td, hi);
+ MT_STORE_FIELD(confidence_state);
return 1;
case HID_DG_TIPSWITCH:
- hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH);
input_set_capability(hi->input, EV_KEY, BTN_TOUCH);
- mt_store_field(usage, td, hi);
+ MT_STORE_FIELD(tip_state);
return 1;
case HID_DG_CONTACTID:
- mt_store_field(usage, td, hi);
+ MT_STORE_FIELD(contactid);
app->touches_by_report++;
return 1;
case HID_DG_WIDTH:
- hid_map_usage(hi, usage, bit, max,
- EV_ABS, ABS_MT_TOUCH_MAJOR);
if (!(app->quirks & MT_QUIRK_NO_AREA))
set_abs(hi->input, ABS_MT_TOUCH_MAJOR, field,
cls->sn_width);
- mt_store_field(usage, td, hi);
+ MT_STORE_FIELD(w);
return 1;
case HID_DG_HEIGHT:
- hid_map_usage(hi, usage, bit, max,
- EV_ABS, ABS_MT_TOUCH_MINOR);
if (!(app->quirks & MT_QUIRK_NO_AREA)) {
set_abs(hi->input, ABS_MT_TOUCH_MINOR, field,
cls->sn_height);
@@ -700,37 +752,23 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
input_set_abs_params(hi->input,
ABS_MT_ORIENTATION, 0, 1, 0, 0);
}
- mt_store_field(usage, td, hi);
+ MT_STORE_FIELD(h);
return 1;
case HID_DG_TIPPRESSURE:
- hid_map_usage(hi, usage, bit, max,
- EV_ABS, ABS_MT_PRESSURE);
set_abs(hi->input, ABS_MT_PRESSURE, field,
cls->sn_pressure);
- mt_store_field(usage, td, hi);
+ MT_STORE_FIELD(p);
return 1;
case HID_DG_SCANTIME:
- hid_map_usage(hi, usage, bit, max,
- EV_MSC, MSC_TIMESTAMP);
input_set_capability(hi->input, EV_MSC, MSC_TIMESTAMP);
- /* Ignore if indexes are out of bounds. */
- if (field->index >= field->report->maxfield ||
- usage->usage_index >= field->report_count)
- return 1;
- app->scantime_index = field->index;
- app->scantime_val_index = usage->usage_index;
+ app->scantime = &field->value[usage->usage_index];
+ app->scantime_logical_max = field->logical_maximum;
return 1;
case HID_DG_CONTACTCOUNT:
- /* Ignore if indexes are out of bounds. */
- if (field->index >= field->report->maxfield ||
- usage->usage_index >= field->report_count)
- return 1;
- app->cc_index = field->index;
- app->cc_value_index = usage->usage_index;
+ app->have_contact_count = true;
+ app->raw_cc = &field->value[usage->usage_index];
return 1;
case HID_DG_AZIMUTH:
- hid_map_usage(hi, usage, bit, max,
- EV_ABS, ABS_MT_ORIENTATION);
/*
* Azimuth has the range of [0, MAX) representing a full
* revolution. Set ABS_MT_ORIENTATION to a quarter of
@@ -741,11 +779,10 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
field->logical_maximum / 4,
cls->sn_move ?
field->logical_maximum / cls->sn_move : 0, 0);
- mt_store_field(usage, td, hi);
+ MT_STORE_FIELD(a);
return 1;
case HID_DG_CONTACTMAX:
- /* we don't set td->last_slot_field as contactcount and
- * contact max are global to the report */
+ /* contact max are global to the report */
return -1;
case HID_DG_TOUCH:
/* Legacy devices use TIPSWITCH and not TOUCH.
@@ -778,95 +815,24 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
}
static int mt_compute_slot(struct mt_device *td, struct mt_application *app,
+ struct mt_usages *slot,
struct input_dev *input)
{
__s32 quirks = app->quirks;
if (quirks & MT_QUIRK_SLOT_IS_CONTACTID)
- return app->curdata.contactid;
+ return *slot->contactid;
if (quirks & MT_QUIRK_CYPRESS)
- return cypress_compute_slot(app);
+ return cypress_compute_slot(app, slot);
if (quirks & MT_QUIRK_SLOT_IS_CONTACTNUMBER)
return app->num_received;
if (quirks & MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE)
- return app->curdata.contactid - 1;
+ return *slot->contactid - 1;
- return input_mt_get_slot_by_key(input, app->curdata.contactid);
-}
-
-/*
- * this function is called when a whole contact has been processed,
- * so that it can assign it to a slot and store the data there
- */
-static void mt_complete_slot(struct mt_device *td, struct mt_application *app,
- struct input_dev *input)
-{
- if ((app->quirks & MT_QUIRK_CONTACT_CNT_ACCURATE) &&
- app->num_received >= app->num_expected)
- return;
-
- if (app->curvalid || (app->quirks & MT_QUIRK_ALWAYS_VALID)) {
- int active;
- int slotnum = mt_compute_slot(td, app, input);
- struct mt_slot *s = &app->curdata;
- struct input_mt *mt = input->mt;
-
- if (slotnum < 0 || slotnum >= td->maxcontacts)
- return;
-
- if ((app->quirks & MT_QUIRK_IGNORE_DUPLICATES) && mt) {
- struct input_mt_slot *slot = &mt->slots[slotnum];
- if (input_mt_is_active(slot) &&
- input_mt_is_used(mt, slot))
- return;
- }
-
- if (!(app->quirks & MT_QUIRK_CONFIDENCE))
- s->confidence_state = true;
- active = (s->touch_state || s->inrange_state) &&
- s->confidence_state;
-
- input_mt_slot(input, slotnum);
- input_mt_report_slot_state(input, MT_TOOL_FINGER, active);
- if (active) {
- /* this finger is in proximity of the sensor */
- int wide = (s->w > s->h);
- int major = max(s->w, s->h);
- int minor = min(s->w, s->h);
- int orientation = wide;
-
- if (s->has_azimuth)
- orientation = s->a;
-
- /*
- * divided by two to match visual scale of touch
- * for devices with this quirk
- */
- if (app->quirks & MT_QUIRK_TOUCH_SIZE_SCALING) {
- major = major >> 1;
- minor = minor >> 1;
- }
-
- input_event(input, EV_ABS, ABS_MT_POSITION_X, s->x);
- input_event(input, EV_ABS, ABS_MT_POSITION_Y, s->y);
- input_event(input, EV_ABS, ABS_MT_TOOL_X, s->cx);
- input_event(input, EV_ABS, ABS_MT_TOOL_Y, s->cy);
- input_event(input, EV_ABS, ABS_MT_DISTANCE,
- !s->touch_state);
- input_event(input, EV_ABS, ABS_MT_ORIENTATION,
- orientation);
- input_event(input, EV_ABS, ABS_MT_PRESSURE, s->p);
- input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, major);
- input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, minor);
-
- set_bit(MT_IO_FLAGS_ACTIVE_SLOTS, &td->mt_io_flags);
- }
- }
-
- app->num_received++;
+ return input_mt_get_slot_by_key(input, *slot->contactid);
}
/*
@@ -892,8 +858,7 @@ static void mt_sync_frame(struct mt_device *td, struct mt_application *app,
clear_bit(MT_IO_FLAGS_ACTIVE_SLOTS, &td->mt_io_flags);
}
-static int mt_compute_timestamp(struct mt_application *app,
- struct hid_field *field, __s32 value)
+static int mt_compute_timestamp(struct mt_application *app, __s32 value)
{
long delta = value - app->prev_scantime;
unsigned long jdelta = jiffies_to_usecs(jiffies - app->jiffies);
@@ -901,7 +866,7 @@ static int mt_compute_timestamp(struct mt_application *app,
app->jiffies = jiffies;
if (delta < 0)
- delta += field->logical_maximum;
+ delta += app->scantime_logical_max;
/* HID_DG_SCANTIME is expressed in 100us, we want it in us. */
delta *= 100;
@@ -923,64 +888,69 @@ static int mt_touch_event(struct hid_device *hid, struct hid_field *field,
return 1;
}
-static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field,
- struct hid_usage *usage, __s32 value,
- struct mt_application *app, bool first_packet)
+static int mt_process_slot(struct mt_device *td, struct input_dev *input,
+ struct mt_application *app,
+ struct mt_usages *slot)
{
- struct mt_device *td = hid_get_drvdata(hid);
+ struct input_mt *mt = input->mt;
__s32 quirks = app->quirks;
- struct input_dev *input = field->hidinput->input;
+ bool valid = true;
+ bool confidence_state = true;
+ bool inrange_state = false;
+ int active;
+ int slotnum;
- if (hid->claimed & HID_CLAIMED_INPUT) {
- switch (usage->hid) {
- case HID_DG_INRANGE:
- if (quirks & MT_QUIRK_VALID_IS_INRANGE)
- app->curvalid = value;
- if (quirks & MT_QUIRK_HOVERING)
- app->curdata.inrange_state = value;
- break;
- case HID_DG_TIPSWITCH:
- if (quirks & MT_QUIRK_NOT_SEEN_MEANS_UP)
- app->curvalid = value;
- app->curdata.touch_state = value;
- break;
- case HID_DG_CONFIDENCE:
- if (quirks & MT_QUIRK_CONFIDENCE)
- app->curdata.confidence_state = value;
- if (quirks & MT_QUIRK_VALID_IS_CONFIDENCE)
- app->curvalid = value;
- break;
- case HID_DG_CONTACTID:
- app->curdata.contactid = value;
- break;
- case HID_DG_TIPPRESSURE:
- app->curdata.p = value;
- break;
- case HID_GD_X:
- if (usage->code == ABS_MT_TOOL_X)
- app->curdata.cx = value;
- else
- app->curdata.x = value;
- break;
- case HID_GD_Y:
- if (usage->code == ABS_MT_TOOL_Y)
- app->curdata.cy = value;
- else
- app->curdata.y = value;
- break;
- case HID_DG_WIDTH:
- app->curdata.w = value;
- break;
- case HID_DG_HEIGHT:
- app->curdata.h = value;
- break;
- case HID_DG_SCANTIME:
- app->timestamp = mt_compute_timestamp(app, field,
- value);
- break;
- case HID_DG_CONTACTCOUNT:
- break;
- case HID_DG_AZIMUTH:
+ if (!slot)
+ return -EINVAL;
+
+ if ((quirks & MT_QUIRK_CONTACT_CNT_ACCURATE) &&
+ app->num_received >= app->num_expected)
+ return -EAGAIN;
+
+ if (!(quirks & MT_QUIRK_ALWAYS_VALID)) {
+ if (quirks & MT_QUIRK_VALID_IS_INRANGE)
+ valid = *slot->inrange_state;
+ if (quirks & MT_QUIRK_NOT_SEEN_MEANS_UP)
+ valid = *slot->tip_state;
+ if (quirks & MT_QUIRK_VALID_IS_CONFIDENCE)
+ valid = *slot->confidence_state;
+
+ if (!valid)
+ return 0;
+ }
+
+ slotnum = mt_compute_slot(td, app, slot, input);
+ if (slotnum < 0 || slotnum >= td->maxcontacts)
+ return 0;
+
+ if ((quirks & MT_QUIRK_IGNORE_DUPLICATES) && mt) {
+ struct input_mt_slot *i_slot = &mt->slots[slotnum];
+
+ if (input_mt_is_active(i_slot) &&
+ input_mt_is_used(mt, i_slot))
+ return -EAGAIN;
+ }
+
+ if (quirks & MT_QUIRK_CONFIDENCE)
+ confidence_state = *slot->confidence_state;
+
+ if (quirks & MT_QUIRK_HOVERING)
+ inrange_state = *slot->inrange_state;
+
+ active = (*slot->tip_state || inrange_state) && confidence_state;
+
+ input_mt_slot(input, slotnum);
+ input_mt_report_slot_state(input, MT_TOOL_FINGER, active);
+ if (active) {
+ /* this finger is in proximity of the sensor */
+ int wide = (*slot->w > *slot->h);
+ int major = max(*slot->w, *slot->h);
+ int minor = min(*slot->w, *slot->h);
+ int orientation = wide;
+ int max_azimuth;
+ int azimuth;
+
+ if (slot->a != DEFAULT_ZERO) {
/*
* Azimuth is counter-clockwise and ranges from [0, MAX)
* (a full revolution). Convert it to clockwise ranging
@@ -991,52 +961,76 @@ static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field,
* out of range to [-MAX/2, MAX/2] to report an upside
* down ellipsis.
*/
- if (value > field->logical_maximum / 2)
- value -= field->logical_maximum;
- app->curdata.a = -value;
- app->curdata.has_azimuth = true;
- break;
- case HID_DG_TOUCH:
- /* do nothing */
- break;
+ azimuth = *slot->a;
+ max_azimuth = input_abs_get_max(input,
+ ABS_MT_ORIENTATION);
+ if (azimuth > max_azimuth * 2)
+ azimuth -= max_azimuth * 4;
+ orientation = -azimuth;
+ }
- default:
- /*
- * For Win8 PTP touchpads we should only look at
- * non finger/touch events in the first_packet of
- * a (possible) multi-packet frame.
- */
- if ((quirks & MT_QUIRK_WIN8_PTP_BUTTONS) &&
- !first_packet)
- return;
+ /*
+ * divided by two to match visual scale of touch
+ * for devices with this quirk
+ */
+ if (quirks & MT_QUIRK_TOUCH_SIZE_SCALING) {
+ major = major >> 1;
+ minor = minor >> 1;
+ }
- /*
- * For Win8 PTP touchpads we map both the clickpad click
- * and any "external" left buttons to BTN_LEFT if a
- * device claims to have both we need to report 1 for
- * BTN_LEFT if either is pressed, so we or all values
- * together and report the result in mt_sync_frame().
- */
- if ((quirks & MT_QUIRK_WIN8_PTP_BUTTONS) &&
- usage->type == EV_KEY && usage->code == BTN_LEFT) {
- app->left_button_state |= value;
- return;
- }
+ input_event(input, EV_ABS, ABS_MT_POSITION_X, *slot->x);
+ input_event(input, EV_ABS, ABS_MT_POSITION_Y, *slot->y);
+ input_event(input, EV_ABS, ABS_MT_TOOL_X, *slot->cx);
+ input_event(input, EV_ABS, ABS_MT_TOOL_Y, *slot->cy);
+ input_event(input, EV_ABS, ABS_MT_DISTANCE, !*slot->tip_state);
+ input_event(input, EV_ABS, ABS_MT_ORIENTATION, orientation);
+ input_event(input, EV_ABS, ABS_MT_PRESSURE, *slot->p);
+ input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, major);
+ input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, minor);
+
+ set_bit(MT_IO_FLAGS_ACTIVE_SLOTS, &td->mt_io_flags);
+ }
- if (usage->type)
- input_event(input, usage->type, usage->code,
- value);
+ return 0;
+}
+
+static void mt_process_mt_event(struct hid_device *hid,
+ struct mt_application *app,
+ struct hid_field *field,
+ struct hid_usage *usage,
+ __s32 value,
+ bool first_packet)
+{
+ __s32 quirks = app->quirks;
+ struct input_dev *input = field->hidinput->input;
+
+ if (!usage->type || !(hid->claimed & HID_CLAIMED_INPUT))
+ return;
+
+ if (quirks & MT_QUIRK_WIN8_PTP_BUTTONS) {
+
+ /*
+ * For Win8 PTP touchpads we should only look at
+ * non finger/touch events in the first_packet of a
+ * (possible) multi-packet frame.
+ */
+ if (!first_packet)
return;
- }
- if (usage->usage_index + 1 == field->report_count) {
- /* we only take into account the last report. */
- if (usage->hid == app->last_slot_field)
- mt_complete_slot(td, app,
- field->hidinput->input);
+ /*
+ * For Win8 PTP touchpads we map both the clickpad click
+ * and any "external" left buttons to BTN_LEFT if a
+ * device claims to have both we need to report 1 for
+ * BTN_LEFT if either is pressed, so we or all values
+ * together and report the result in mt_sync_frame().
+ */
+ if (usage->type == EV_KEY && usage->code == BTN_LEFT) {
+ app->left_button_state |= value;
+ return;
}
-
}
+
+ input_event(input, usage->type, usage->code, value);
}
static void mt_touch_report(struct hid_device *hid,
@@ -1046,6 +1040,8 @@ static void mt_touch_report(struct hid_device *hid,
struct hid_report *report = rdata->report;
struct mt_application *app = rdata->application;
struct hid_field *field;
+ struct input_dev *input;
+ struct mt_usages *slot;
bool first_packet;
unsigned count;
int r, n;
@@ -1056,18 +1052,16 @@ static void mt_touch_report(struct hid_device *hid,
if (test_and_set_bit(MT_IO_FLAGS_RUNNING, &td->mt_io_flags))
return;
+ scantime = *app->scantime;
+ app->timestamp = mt_compute_timestamp(app, scantime);
+ if (app->raw_cc != DEFAULT_ZERO)
+ contact_count = *app->raw_cc;
+
/*
* Includes multi-packet support where subsequent
* packets are sent with zero contactcount.
*/
- if (app->scantime_index >= 0) {
- field = report->field[app->scantime_index];
- scantime = field->value[app->scantime_val_index];
- }
- if (app->cc_index >= 0) {
- field = report->field[app->cc_index];
- contact_count = field->value[app->cc_value_index];
-
+ if (contact_count >= 0) {
/*
* For Win8 PTPs the first packet (td->num_received == 0) may
* have a contactcount of 0 if there only is a button event.
@@ -1086,6 +1080,14 @@ static void mt_touch_report(struct hid_device *hid,
app->prev_scantime = scantime;
first_packet = app->num_received == 0;
+
+ input = report->field[0]->hidinput->input;
+
+ list_for_each_entry(slot, &app->mt_usages, list) {
+ if (!mt_process_slot(td, input, app, slot))
+ app->num_received++;
+ }
+
for (r = 0; r < report->maxfield; r++) {
field = report->field[r];
count = field->report_count;
@@ -1094,12 +1096,13 @@ static void mt_touch_report(struct hid_device *hid,
continue;
for (n = 0; n < count; n++)
- mt_process_mt_event(hid, field, &field->usage[n],
- field->value[n], app, first_packet);
+ mt_process_mt_event(hid, app, field,
+ &field->usage[n], field->value[n],
+ first_packet);
}
if (app->num_received >= app->num_expected)
- mt_sync_frame(td, app, report->field[0]->hidinput->input);
+ mt_sync_frame(td, app, input);
/*
* Windows 8 specs says 2 things:
@@ -1391,7 +1394,7 @@ static void mt_post_parse_default_settings(struct mt_device *td,
__s32 quirks = app->quirks;
/* unknown serial device needs special quirks */
- if (app->touches_by_report == 1) {
+ if (list_is_singular(&app->mt_usages)) {
quirks |= MT_QUIRK_ALWAYS_VALID;
quirks &= ~MT_QUIRK_NOT_SEEN_MEANS_UP;
quirks &= ~MT_QUIRK_VALID_IS_INRANGE;
@@ -1404,16 +1407,7 @@ static void mt_post_parse_default_settings(struct mt_device *td,
static void mt_post_parse(struct mt_device *td, struct mt_application *app)
{
- struct mt_fields *f = td->fields;
-
- if (app->touches_by_report > 0) {
- int field_count_per_touch;
-
- field_count_per_touch = f->length / app->touches_by_report;
- app->last_slot_field = f->usages[field_count_per_touch - 1];
- }
-
- if (app->cc_index < 0)
+ if (!app->have_contact_count)
app->quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE;
}
@@ -1596,13 +1590,6 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
INIT_LIST_HEAD(&td->applications);
INIT_LIST_HEAD(&td->reports);
- td->fields = devm_kzalloc(&hdev->dev, sizeof(struct mt_fields),
- GFP_KERNEL);
- if (!td->fields) {
- dev_err(&hdev->dev, "cannot allocate multitouch fields data\n");
- return -ENOMEM;
- }
-
if (id->vendor == HID_ANY_ID && id->product == HID_ANY_ID)
td->serial_maybe = true;
@@ -1638,10 +1625,6 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
mt_set_modes(hdev, HID_LATENCY_NORMAL, true, true);
- /* release .fields memory as it is not used anymore */
- devm_kfree(&hdev->dev, td->fields);
- td->fields = NULL;
-
return 0;
}
--
2.14.3
^ permalink raw reply related
* [PATCH v4 05/12] HID: multitouch: ditch mt_report_id
From: Benjamin Tissoires @ 2018-07-13 14:13 UTC (permalink / raw)
To: Jiri Kosina, Dmitry Torokhov
Cc: Mario.Limonciello, Peter Hutterer, linux-input, linux-kernel,
Benjamin Tissoires
In-Reply-To: <20180713141354.7286-1-benjamin.tissoires@redhat.com>
Now that the driver can handle more than one multitouch collection in
a single HID device, ditch the last bit that contains us to use only
one mt collection.
Acked-by: Peter Hutterer <peter.hutterer@who-t.net>
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
---
no changes in v4
no changes in v3
no changes in v2
---
drivers/hid/hid-multitouch.c | 126 ++++++++++++++++++++++++++++++++-----------
1 file changed, 94 insertions(+), 32 deletions(-)
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index beaac36f61a7..a2c10fc62ef2 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -147,6 +147,13 @@ struct mt_fields {
unsigned int length;
};
+struct mt_report_data {
+ struct list_head list;
+ struct hid_report *report;
+ struct mt_application *application;
+ bool is_mt_collection;
+};
+
struct mt_device {
struct mt_class mtclass; /* our mt device class */
struct timer_list release_timer; /* to release sticky fingers */
@@ -154,13 +161,13 @@ struct mt_device {
struct mt_fields *fields; /* temporary placeholder for storing the
multitouch fields */
unsigned long mt_io_flags; /* mt flags (MT_IO_FLAGS_*) */
- unsigned mt_report_id; /* the report ID of the multitouch device */
__u8 inputmode_value; /* InputMode HID feature value */
__u8 maxcontacts;
bool is_buttonpad; /* is this device a button pad? */
bool serial_maybe; /* need to check for serial protocol */
struct list_head applications;
+ struct list_head reports;
};
static void mt_post_parse_default_settings(struct mt_device *td,
@@ -526,6 +533,60 @@ static struct mt_application *mt_find_application(struct mt_device *td,
return mt_application;
}
+static struct mt_report_data *mt_allocate_report_data(struct mt_device *td,
+ struct hid_report *report)
+{
+ struct mt_report_data *rdata;
+ struct hid_field *field;
+ int r, n;
+
+ rdata = devm_kzalloc(&td->hdev->dev, sizeof(*rdata), GFP_KERNEL);
+ if (!rdata)
+ return NULL;
+
+ rdata->report = report;
+ rdata->application = mt_find_application(td, report->application);
+
+ if (!rdata->application) {
+ devm_kfree(&td->hdev->dev, rdata);
+ return NULL;
+ }
+
+ for (r = 0; r < report->maxfield; r++) {
+ field = report->field[r];
+
+ if (!(HID_MAIN_ITEM_VARIABLE & field->flags))
+ continue;
+
+ for (n = 0; n < field->report_count; n++) {
+ if (field->usage[n].hid == HID_DG_CONTACTID)
+ rdata->is_mt_collection = true;
+ }
+ }
+
+ list_add_tail(&rdata->list, &td->reports);
+
+ return rdata;
+}
+
+static struct mt_report_data *mt_find_report_data(struct mt_device *td,
+ struct hid_report *report)
+{
+ struct mt_report_data *tmp, *rdata = NULL;
+
+ list_for_each_entry(tmp, &td->reports, list) {
+ if (report == tmp->report) {
+ rdata = tmp;
+ break;
+ }
+ }
+
+ if (!rdata)
+ rdata = mt_allocate_report_data(td, report);
+
+ return rdata;
+}
+
static void mt_store_field(struct hid_usage *usage, struct mt_device *td,
struct hid_input *hi)
{
@@ -614,7 +675,6 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
case HID_DG_CONTACTID:
mt_store_field(usage, td, hi);
app->touches_by_report++;
- td->mt_report_id = field->report->id;
return 1;
case HID_DG_WIDTH:
hid_map_usage(hi, usage, bit, max,
@@ -979,10 +1039,12 @@ static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field,
}
}
-static void mt_touch_report(struct hid_device *hid, struct hid_report *report)
+static void mt_touch_report(struct hid_device *hid,
+ struct mt_report_data *rdata)
{
struct mt_device *td = hid_get_drvdata(hid);
- struct mt_application *app;
+ struct hid_report *report = rdata->report;
+ struct mt_application *app = rdata->application;
struct hid_field *field;
bool first_packet;
unsigned count;
@@ -994,11 +1056,6 @@ static void mt_touch_report(struct hid_device *hid, struct hid_report *report)
if (test_and_set_bit(MT_IO_FLAGS_RUNNING, &td->mt_io_flags))
return;
- app = mt_find_application(td, report->application);
-
- if (!app)
- return;
-
/*
* Includes multi-packet support where subsequent
* packets are sent with zero contactcount.
@@ -1119,8 +1176,15 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
{
struct mt_device *td = hid_get_drvdata(hdev);
struct mt_application *application;
+ struct mt_report_data *rdata;
+
+ rdata = mt_find_report_data(td, field->report);
+ if (!rdata) {
+ hid_err(hdev, "failed to allocate data for report\n");
+ return 0;
+ }
- application = mt_find_application(td, field->application);
+ application = rdata->application;
/*
* If mtclass.export_all_inputs is not set, only map fields from
@@ -1163,22 +1227,9 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
return 1;
}
- /*
- * some egalax touchscreens have "application == HID_DG_TOUCHSCREEN"
- * for the stylus.
- * The check for mt_report_id ensures we don't process
- * HID_DG_CONTACTCOUNT from the pen report as it is outside the physical
- * collection, but within the report ID.
- */
- if (field->physical == HID_DG_STYLUS)
- return 0;
- else if ((field->physical == 0) &&
- (field->report->id != td->mt_report_id) &&
- (td->mt_report_id != -1))
- return 0;
-
- if (field->application == HID_DG_TOUCHSCREEN ||
- field->application == HID_DG_TOUCHPAD)
+ if (rdata->is_mt_collection &&
+ (field->application == HID_DG_TOUCHSCREEN ||
+ field->application == HID_DG_TOUCHPAD))
return mt_touch_input_mapping(hdev, hi, field, usage, bit, max,
application);
@@ -1211,8 +1262,10 @@ static int mt_event(struct hid_device *hid, struct hid_field *field,
struct hid_usage *usage, __s32 value)
{
struct mt_device *td = hid_get_drvdata(hid);
+ struct mt_report_data *rdata;
- if (field->report->id == td->mt_report_id)
+ rdata = mt_find_report_data(td, field->report);
+ if (rdata && rdata->is_mt_collection)
return mt_touch_event(hid, field, usage, value);
return 0;
@@ -1222,12 +1275,14 @@ static void mt_report(struct hid_device *hid, struct hid_report *report)
{
struct mt_device *td = hid_get_drvdata(hid);
struct hid_field *field = report->field[0];
+ struct mt_report_data *rdata;
if (!(hid->claimed & HID_CLAIMED_INPUT))
return;
- if (report->id == td->mt_report_id)
- return mt_touch_report(hid, report);
+ rdata = mt_find_report_data(td, report);
+ if (rdata && rdata->is_mt_collection)
+ return mt_touch_report(hid, rdata);
if (field && field->hidinput && field->hidinput->input)
input_sync(field->hidinput->input);
@@ -1368,15 +1423,22 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi)
char *name;
const char *suffix = NULL;
unsigned int application = 0;
+ struct mt_report_data *rdata;
struct mt_application *mt_application = NULL;
struct hid_report *report;
int ret;
list_for_each_entry(report, &hi->reports, hidinput_list) {
application = report->application;
- mt_application = mt_find_application(td, application);
+ rdata = mt_find_report_data(td, report);
+ if (!rdata) {
+ hid_err(hdev, "failed to allocate data for report\n");
+ return -ENOMEM;
+ }
+
+ mt_application = rdata->application;
- if (report->id == td->mt_report_id) {
+ if (rdata->is_mt_collection) {
ret = mt_touch_input_configured(hdev, hi,
mt_application);
if (ret)
@@ -1529,10 +1591,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
td->hdev = hdev;
td->mtclass = *mtclass;
td->inputmode_value = MT_INPUTMODE_TOUCHSCREEN;
- td->mt_report_id = -1;
hid_set_drvdata(hdev, td);
INIT_LIST_HEAD(&td->applications);
+ INIT_LIST_HEAD(&td->reports);
td->fields = devm_kzalloc(&hdev->dev, sizeof(struct mt_fields),
GFP_KERNEL);
--
2.14.3
^ permalink raw reply related
* [PATCH v4 04/12] HID: multitouch: store a per application quirks value
From: Benjamin Tissoires @ 2018-07-13 14:13 UTC (permalink / raw)
To: Jiri Kosina, Dmitry Torokhov
Cc: Mario.Limonciello, Peter Hutterer, linux-input, linux-kernel,
Benjamin Tissoires
In-Reply-To: <20180713141354.7286-1-benjamin.tissoires@redhat.com>
If a device has more than one multitouch collection, there is a chance
we need per tool quirks. This is the case for the Totem on the Dell
Canvas.
Note that thesysfs attribute quirks can now get out of sync, but there
should not be much users of it as it's debugging only.
Acked-by: Peter Hutterer <peter.hutterer@who-t.net>
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
---
no changes in v4
no changes in v3
no changes in v2
---
drivers/hid/hid-multitouch.c | 64 ++++++++++++++++++++++----------------------
1 file changed, 32 insertions(+), 32 deletions(-)
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index cd207e99d26a..beaac36f61a7 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -99,6 +99,9 @@ struct mt_slot {
struct mt_application {
struct list_head list;
unsigned int application;
+
+ __s32 quirks;
+
struct mt_slot curdata; /* placeholder of incoming data */
int cc_index; /* contact count field index in the report */
@@ -368,7 +371,6 @@ static ssize_t mt_set_quirks(struct device *dev,
struct mt_application *application;
unsigned long val;
- bool confidence_found = false;
if (kstrtoul(buf, 0, &val))
return -EINVAL;
@@ -376,13 +378,11 @@ static ssize_t mt_set_quirks(struct device *dev,
td->mtclass.quirks = val;
list_for_each_entry(application, &td->applications, list) {
- if (application->have_contact_count)
- confidence_found = true;
+ application->quirks = val;
+ if (!application->have_contact_count)
+ application->quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE;
}
- if (!confidence_found)
- td->mtclass.quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE;
-
return count;
}
@@ -501,6 +501,7 @@ static struct mt_application *mt_allocate_application(struct mt_device *td,
mt_application->cc_index = -1;
mt_application->scantime_index = -1;
+ mt_application->quirks = td->mtclass.quirks;
list_add_tail(&mt_application->list, &td->applications);
@@ -590,7 +591,7 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
case HID_UP_DIGITIZER:
switch (usage->hid) {
case HID_DG_INRANGE:
- if (cls->quirks & MT_QUIRK_HOVERING) {
+ if (app->quirks & MT_QUIRK_HOVERING) {
hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_DISTANCE);
input_set_abs_params(hi->input,
@@ -602,7 +603,7 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
if ((cls->name == MT_CLS_WIN_8 ||
cls->name == MT_CLS_WIN_8_DUAL) &&
field->application == HID_DG_TOUCHPAD)
- cls->quirks |= MT_QUIRK_CONFIDENCE;
+ app->quirks |= MT_QUIRK_CONFIDENCE;
mt_store_field(usage, td, hi);
return 1;
case HID_DG_TIPSWITCH:
@@ -618,7 +619,7 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
case HID_DG_WIDTH:
hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_TOUCH_MAJOR);
- if (!(cls->quirks & MT_QUIRK_NO_AREA))
+ if (!(app->quirks & MT_QUIRK_NO_AREA))
set_abs(hi->input, ABS_MT_TOUCH_MAJOR, field,
cls->sn_width);
mt_store_field(usage, td, hi);
@@ -626,7 +627,7 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
case HID_DG_HEIGHT:
hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_TOUCH_MINOR);
- if (!(cls->quirks & MT_QUIRK_NO_AREA)) {
+ if (!(app->quirks & MT_QUIRK_NO_AREA)) {
set_abs(hi->input, ABS_MT_TOUCH_MINOR, field,
cls->sn_height);
@@ -700,7 +701,7 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
* MS PTP spec says that external buttons left and right have
* usages 2 and 3.
*/
- if ((cls->quirks & MT_QUIRK_WIN8_PTP_BUTTONS) &&
+ if ((app->quirks & MT_QUIRK_WIN8_PTP_BUTTONS) &&
field->application == HID_DG_TOUCHPAD &&
(usage->hid & HID_USAGE) > 1)
code--;
@@ -719,7 +720,7 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
static int mt_compute_slot(struct mt_device *td, struct mt_application *app,
struct input_dev *input)
{
- __s32 quirks = td->mtclass.quirks;
+ __s32 quirks = app->quirks;
if (quirks & MT_QUIRK_SLOT_IS_CONTACTID)
return app->curdata.contactid;
@@ -743,11 +744,11 @@ static int mt_compute_slot(struct mt_device *td, struct mt_application *app,
static void mt_complete_slot(struct mt_device *td, struct mt_application *app,
struct input_dev *input)
{
- if ((td->mtclass.quirks & MT_QUIRK_CONTACT_CNT_ACCURATE) &&
+ if ((app->quirks & MT_QUIRK_CONTACT_CNT_ACCURATE) &&
app->num_received >= app->num_expected)
return;
- if (app->curvalid || (td->mtclass.quirks & MT_QUIRK_ALWAYS_VALID)) {
+ if (app->curvalid || (app->quirks & MT_QUIRK_ALWAYS_VALID)) {
int active;
int slotnum = mt_compute_slot(td, app, input);
struct mt_slot *s = &app->curdata;
@@ -756,14 +757,14 @@ static void mt_complete_slot(struct mt_device *td, struct mt_application *app,
if (slotnum < 0 || slotnum >= td->maxcontacts)
return;
- if ((td->mtclass.quirks & MT_QUIRK_IGNORE_DUPLICATES) && mt) {
+ if ((app->quirks & MT_QUIRK_IGNORE_DUPLICATES) && mt) {
struct input_mt_slot *slot = &mt->slots[slotnum];
if (input_mt_is_active(slot) &&
input_mt_is_used(mt, slot))
return;
}
- if (!(td->mtclass.quirks & MT_QUIRK_CONFIDENCE))
+ if (!(app->quirks & MT_QUIRK_CONFIDENCE))
s->confidence_state = true;
active = (s->touch_state || s->inrange_state) &&
s->confidence_state;
@@ -784,7 +785,7 @@ static void mt_complete_slot(struct mt_device *td, struct mt_application *app,
* divided by two to match visual scale of touch
* for devices with this quirk
*/
- if (td->mtclass.quirks & MT_QUIRK_TOUCH_SIZE_SCALING) {
+ if (app->quirks & MT_QUIRK_TOUCH_SIZE_SCALING) {
major = major >> 1;
minor = minor >> 1;
}
@@ -815,7 +816,7 @@ static void mt_complete_slot(struct mt_device *td, struct mt_application *app,
static void mt_sync_frame(struct mt_device *td, struct mt_application *app,
struct input_dev *input)
{
- if (td->mtclass.quirks & MT_QUIRK_WIN8_PTP_BUTTONS)
+ if (app->quirks & MT_QUIRK_WIN8_PTP_BUTTONS)
input_event(input, EV_KEY, BTN_LEFT, app->left_button_state);
input_mt_sync_frame(input);
@@ -867,7 +868,7 @@ static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field,
struct mt_application *app, bool first_packet)
{
struct mt_device *td = hid_get_drvdata(hid);
- __s32 quirks = td->mtclass.quirks;
+ __s32 quirks = app->quirks;
struct input_dev *input = field->hidinput->input;
if (hid->claimed & HID_CLAIMED_INPUT) {
@@ -1017,7 +1018,7 @@ static void mt_touch_report(struct hid_device *hid, struct hid_report *report)
* of a possible multi-packet frame be checking that the
* timestamp has changed.
*/
- if ((td->mtclass.quirks & MT_QUIRK_WIN8_PTP_BUTTONS) &&
+ if ((app->quirks & MT_QUIRK_WIN8_PTP_BUTTONS) &&
app->num_received == 0 &&
app->prev_scantime != scantime)
app->num_expected = contact_count;
@@ -1061,7 +1062,7 @@ static void mt_touch_report(struct hid_device *hid, struct hid_report *report)
* only affect laggish machines and the ones that have a firmware
* defect.
*/
- if (td->mtclass.quirks & MT_QUIRK_STICKY_FINGERS) {
+ if (app->quirks & MT_QUIRK_STICKY_FINGERS) {
if (test_bit(MT_IO_FLAGS_PENDING_SLOTS, &td->mt_io_flags))
mod_timer(&td->release_timer,
jiffies + msecs_to_jiffies(100));
@@ -1091,7 +1092,7 @@ static int mt_touch_input_configured(struct hid_device *hdev,
if (cls->is_indirect)
app->mt_flags |= INPUT_MT_POINTER;
- if (cls->quirks & MT_QUIRK_NOT_SEEN_MEANS_UP)
+ if (app->quirks & MT_QUIRK_NOT_SEEN_MEANS_UP)
app->mt_flags |= INPUT_MT_DROP_UNUSED;
/* check for clickpads */
@@ -1119,6 +1120,8 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
struct mt_device *td = hid_get_drvdata(hdev);
struct mt_application *application;
+ application = mt_find_application(td, field->application);
+
/*
* If mtclass.export_all_inputs is not set, only map fields from
* TouchScreen or TouchPad collections. We need to ignore fields
@@ -1134,7 +1137,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
field->application != HID_CP_CONSUMER_CONTROL &&
field->application != HID_GD_WIRELESS_RADIO_CTLS &&
!(field->application == HID_VD_ASUS_CUSTOM_MEDIA_KEYS &&
- td->mtclass.quirks & MT_QUIRK_ASUS_CUSTOM_UP))
+ application->quirks & MT_QUIRK_ASUS_CUSTOM_UP))
return -1;
/*
@@ -1143,7 +1146,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
* map usages to input keys.
*/
if (field->application == HID_VD_ASUS_CUSTOM_MEDIA_KEYS &&
- td->mtclass.quirks & MT_QUIRK_ASUS_CUSTOM_UP &&
+ application->quirks & MT_QUIRK_ASUS_CUSTOM_UP &&
(usage->hid & HID_USAGE_PAGE) == HID_UP_CUSTOM) {
set_bit(EV_REP, hi->input->evbit);
if (field->flags & HID_MAIN_ITEM_VARIABLE)
@@ -1160,8 +1163,6 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
return 1;
}
- application = mt_find_application(td, field->application);
-
/*
* some egalax touchscreens have "application == HID_DG_TOUCHSCREEN"
* for the stylus.
@@ -1267,9 +1268,9 @@ static bool mt_need_to_apply_feature(struct hid_device *hdev,
return true;
case HID_DG_CONTACTMAX:
- if (td->mtclass.maxcontacts) {
+ if (cls->maxcontacts) {
max = min_t(int, field->logical_maximum,
- td->mtclass.maxcontacts);
+ cls->maxcontacts);
if (field->value[index] != max) {
field->value[index] = max;
return true;
@@ -1332,7 +1333,7 @@ static void mt_set_modes(struct hid_device *hdev, enum latency_mode latency,
static void mt_post_parse_default_settings(struct mt_device *td,
struct mt_application *app)
{
- __s32 quirks = td->mtclass.quirks;
+ __s32 quirks = app->quirks;
/* unknown serial device needs special quirks */
if (app->touches_by_report == 1) {
@@ -1343,13 +1344,12 @@ static void mt_post_parse_default_settings(struct mt_device *td,
quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE;
}
- td->mtclass.quirks = quirks;
+ app->quirks = quirks;
}
static void mt_post_parse(struct mt_device *td, struct mt_application *app)
{
struct mt_fields *f = td->fields;
- struct mt_class *cls = &td->mtclass;
if (app->touches_by_report > 0) {
int field_count_per_touch;
@@ -1359,7 +1359,7 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app)
}
if (app->cc_index < 0)
- cls->quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE;
+ app->quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE;
}
static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi)
--
2.14.3
^ permalink raw reply related
* [PATCH v4 03/12] HID: multitouch: Store per collection multitouch data
From: Benjamin Tissoires @ 2018-07-13 14:13 UTC (permalink / raw)
To: Jiri Kosina, Dmitry Torokhov
Cc: Mario.Limonciello, Peter Hutterer, linux-input, linux-kernel,
Benjamin Tissoires
In-Reply-To: <20180713141354.7286-1-benjamin.tissoires@redhat.com>
Currently, hid-multitouch can only handle one multitouch collection at
a time. This is an issue for the Dell Canvas, as the Totem (a dial tool)
is also using a multitouch-like collection.
Factor out the multitouch collection data in their own struct.
Acked-by: Peter Hutterer <peter.hutterer@who-t.net>
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
---
no changes in v4
no changes in v3
changes in v2:
- changed the url of hid-tools
---
drivers/hid/hid-multitouch.c | 380 ++++++++++++++++++++++++++-----------------
1 file changed, 230 insertions(+), 150 deletions(-)
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index 91624a2240ca..cd207e99d26a 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -28,14 +28,11 @@
*/
/*
- * This driver is regularly tested thanks to the tool hid-test[1].
- * This tool relies on hid-replay[2] and a database of hid devices[3].
+ * This driver is regularly tested thanks to the test suite in hid-tools[1].
* Please run these regression tests before patching this module so that
* your patch won't break existing known devices.
*
- * [1] https://github.com/bentiss/hid-test
- * [2] https://github.com/bentiss/hid-replay
- * [3] https://github.com/bentiss/hid-devices
+ * [1] https://gitlab.freedesktop.org/libevdev/hid-tools
*/
#include <linux/device.h>
@@ -99,6 +96,37 @@ struct mt_slot {
bool has_azimuth; /* the contact reports azimuth */
};
+struct mt_application {
+ struct list_head list;
+ unsigned int application;
+ struct mt_slot curdata; /* placeholder of incoming data */
+
+ int cc_index; /* contact count field index in the report */
+ int cc_value_index; /* contact count value index in the field */
+ int scantime_index; /* scantime field index in the report */
+ int scantime_val_index; /* scantime value index in the field */
+ unsigned int last_slot_field; /* the last field of a slot */
+ bool curvalid; /* is the current contact valid? */
+
+ int left_button_state; /* left button state */
+ unsigned int mt_flags; /* flags to pass to input-mt */
+
+ __u8 num_received; /* how many contacts we received */
+ __u8 num_expected; /* expected last contact index */
+ __u8 buttons_count; /* number of physical buttons per touchpad */
+ __u8 touches_by_report; /* how many touches are present in one report:
+ * 1 means we should use a serial protocol
+ * > 1 means hybrid (multitouch) protocol
+ */
+
+ __s32 dev_time; /* the scan time provided by the device */
+ unsigned long jiffies; /* the frame's jiffies */
+ int timestamp; /* the timestamp to be sent */
+ int prev_scantime; /* scantime reported previously */
+
+ bool have_contact_count;
+};
+
struct mt_class {
__s32 name; /* MT_CLS */
__s32 quirks;
@@ -117,40 +145,24 @@ struct mt_fields {
};
struct mt_device {
- struct mt_slot curdata; /* placeholder of incoming data */
struct mt_class mtclass; /* our mt device class */
struct timer_list release_timer; /* to release sticky fingers */
struct hid_device *hdev; /* hid_device we're attached to */
struct mt_fields *fields; /* temporary placeholder for storing the
multitouch fields */
unsigned long mt_io_flags; /* mt flags (MT_IO_FLAGS_*) */
- int cc_index; /* contact count field index in the report */
- int cc_value_index; /* contact count value index in the field */
- int scantime_index; /* scantime field index in the report */
- int scantime_val_index; /* scantime value index in the field */
- int prev_scantime; /* scantime reported in the previous packet */
- int left_button_state; /* left button state */
- unsigned last_slot_field; /* the last field of a slot */
unsigned mt_report_id; /* the report ID of the multitouch device */
__u8 inputmode_value; /* InputMode HID feature value */
- __u8 num_received; /* how many contacts we received */
- __u8 num_expected; /* expected last contact index */
__u8 maxcontacts;
- __u8 touches_by_report; /* how many touches are present in one report:
- * 1 means we should use a serial protocol
- * > 1 means hybrid (multitouch) protocol */
- __u8 buttons_count; /* number of physical buttons per touchpad */
bool is_buttonpad; /* is this device a button pad? */
bool serial_maybe; /* need to check for serial protocol */
- bool curvalid; /* is the current contact valid? */
- unsigned mt_flags; /* flags to pass to input-mt */
- __s32 dev_time; /* the scan time provided by the device */
- unsigned long jiffies; /* the frame's jiffies */
- int timestamp; /* the timestamp to be sent */
+
+ struct list_head applications;
};
-static void mt_post_parse_default_settings(struct mt_device *td);
-static void mt_post_parse(struct mt_device *td);
+static void mt_post_parse_default_settings(struct mt_device *td,
+ struct mt_application *app);
+static void mt_post_parse(struct mt_device *td, struct mt_application *app);
/* classes of device behavior */
#define MT_CLS_DEFAULT 0x0001
@@ -203,10 +215,10 @@ static void mt_post_parse(struct mt_device *td);
* to a valid contact that was just read.
*/
-static int cypress_compute_slot(struct mt_device *td)
+static int cypress_compute_slot(struct mt_application *app)
{
- if (td->curdata.contactid != 0 || td->num_received == 0)
- return td->curdata.contactid;
+ if (app->curdata.contactid != 0 || app->num_received == 0)
+ return app->curdata.contactid;
else
return -1;
}
@@ -353,15 +365,22 @@ static ssize_t mt_set_quirks(struct device *dev,
{
struct hid_device *hdev = to_hid_device(dev);
struct mt_device *td = hid_get_drvdata(hdev);
+ struct mt_application *application;
unsigned long val;
+ bool confidence_found = false;
if (kstrtoul(buf, 0, &val))
return -EINVAL;
td->mtclass.quirks = val;
- if (td->cc_index < 0)
+ list_for_each_entry(application, &td->applications, list) {
+ if (application->have_contact_count)
+ confidence_found = true;
+ }
+
+ if (!confidence_found)
td->mtclass.quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE;
return count;
@@ -457,6 +476,55 @@ static void set_abs(struct input_dev *input, unsigned int code,
input_abs_set_res(input, code, hidinput_calc_abs_res(field, code));
}
+static struct mt_application *mt_allocate_application(struct mt_device *td,
+ unsigned int application)
+{
+ struct mt_application *mt_application;
+
+ mt_application = devm_kzalloc(&td->hdev->dev, sizeof(*mt_application),
+ GFP_KERNEL);
+ if (!mt_application)
+ return NULL;
+
+ mt_application->application = application;
+
+ if (application == HID_DG_TOUCHSCREEN)
+ mt_application->mt_flags |= INPUT_MT_DIRECT;
+
+ /*
+ * Model touchscreens providing buttons as touchpads.
+ */
+ if (application == HID_DG_TOUCHPAD) {
+ mt_application->mt_flags |= INPUT_MT_POINTER;
+ td->inputmode_value = MT_INPUTMODE_TOUCHPAD;
+ }
+
+ mt_application->cc_index = -1;
+ mt_application->scantime_index = -1;
+
+ list_add_tail(&mt_application->list, &td->applications);
+
+ return mt_application;
+}
+
+static struct mt_application *mt_find_application(struct mt_device *td,
+ unsigned int application)
+{
+ struct mt_application *tmp, *mt_application = NULL;
+
+ list_for_each_entry(tmp, &td->applications, list) {
+ if (application == tmp->application) {
+ mt_application = tmp;
+ break;
+ }
+ }
+
+ if (!mt_application)
+ mt_application = mt_allocate_application(td, application);
+
+ return mt_application;
+}
+
static void mt_store_field(struct hid_usage *usage, struct mt_device *td,
struct hid_input *hi)
{
@@ -470,28 +538,24 @@ static void mt_store_field(struct hid_usage *usage, struct mt_device *td,
static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
struct hid_field *field, struct hid_usage *usage,
- unsigned long **bit, int *max)
+ unsigned long **bit, int *max, struct mt_application *app)
{
struct mt_device *td = hid_get_drvdata(hdev);
struct mt_class *cls = &td->mtclass;
int code;
struct hid_usage *prev_usage = NULL;
- if (field->application == HID_DG_TOUCHSCREEN)
- td->mt_flags |= INPUT_MT_DIRECT;
-
/*
* Model touchscreens providing buttons as touchpads.
*/
- if (field->application == HID_DG_TOUCHPAD ||
- (usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON) {
- td->mt_flags |= INPUT_MT_POINTER;
+ if ((usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON) {
+ app->mt_flags |= INPUT_MT_POINTER;
td->inputmode_value = MT_INPUTMODE_TOUCHPAD;
}
/* count the buttons on touchpads */
if ((usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON)
- td->buttons_count++;
+ app->buttons_count++;
if (usage->usage_index)
prev_usage = &field->usage[usage->usage_index - 1];
@@ -501,33 +565,23 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
case HID_UP_GENDESK:
switch (usage->hid) {
case HID_GD_X:
- if (prev_usage && (prev_usage->hid == usage->hid)) {
- hid_map_usage(hi, usage, bit, max,
- EV_ABS, ABS_MT_TOOL_X);
- set_abs(hi->input, ABS_MT_TOOL_X, field,
- cls->sn_move);
- } else {
- hid_map_usage(hi, usage, bit, max,
- EV_ABS, ABS_MT_POSITION_X);
- set_abs(hi->input, ABS_MT_POSITION_X, field,
- cls->sn_move);
- }
+ if (prev_usage && (prev_usage->hid == usage->hid))
+ code = ABS_MT_TOOL_X;
+ else
+ code = ABS_MT_POSITION_X;
+ hid_map_usage(hi, usage, bit, max, EV_ABS, code);
+ set_abs(hi->input, code, field, cls->sn_move);
mt_store_field(usage, td, hi);
return 1;
case HID_GD_Y:
- if (prev_usage && (prev_usage->hid == usage->hid)) {
- hid_map_usage(hi, usage, bit, max,
- EV_ABS, ABS_MT_TOOL_Y);
- set_abs(hi->input, ABS_MT_TOOL_Y, field,
- cls->sn_move);
- } else {
- hid_map_usage(hi, usage, bit, max,
- EV_ABS, ABS_MT_POSITION_Y);
- set_abs(hi->input, ABS_MT_POSITION_Y, field,
- cls->sn_move);
- }
+ if (prev_usage && (prev_usage->hid == usage->hid))
+ code = ABS_MT_TOOL_Y;
+ else
+ code = ABS_MT_POSITION_Y;
+ hid_map_usage(hi, usage, bit, max, EV_ABS, code);
+ set_abs(hi->input, code, field, cls->sn_move);
mt_store_field(usage, td, hi);
return 1;
}
@@ -558,7 +612,7 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
return 1;
case HID_DG_CONTACTID:
mt_store_field(usage, td, hi);
- td->touches_by_report++;
+ app->touches_by_report++;
td->mt_report_id = field->report->id;
return 1;
case HID_DG_WIDTH:
@@ -602,20 +656,16 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
if (field->index >= field->report->maxfield ||
usage->usage_index >= field->report_count)
return 1;
- td->scantime_index = field->index;
- td->scantime_val_index = usage->usage_index;
- /*
- * We don't set td->last_slot_field as scan time is
- * global to the report.
- */
+ app->scantime_index = field->index;
+ app->scantime_val_index = usage->usage_index;
return 1;
case HID_DG_CONTACTCOUNT:
/* Ignore if indexes are out of bounds. */
if (field->index >= field->report->maxfield ||
usage->usage_index >= field->report_count)
return 1;
- td->cc_index = field->index;
- td->cc_value_index = usage->usage_index;
+ app->cc_index = field->index;
+ app->cc_value_index = usage->usage_index;
return 1;
case HID_DG_AZIMUTH:
hid_map_usage(hi, usage, bit, max,
@@ -666,39 +716,41 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
return 0;
}
-static int mt_compute_slot(struct mt_device *td, struct input_dev *input)
+static int mt_compute_slot(struct mt_device *td, struct mt_application *app,
+ struct input_dev *input)
{
__s32 quirks = td->mtclass.quirks;
if (quirks & MT_QUIRK_SLOT_IS_CONTACTID)
- return td->curdata.contactid;
+ return app->curdata.contactid;
if (quirks & MT_QUIRK_CYPRESS)
- return cypress_compute_slot(td);
+ return cypress_compute_slot(app);
if (quirks & MT_QUIRK_SLOT_IS_CONTACTNUMBER)
- return td->num_received;
+ return app->num_received;
if (quirks & MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE)
- return td->curdata.contactid - 1;
+ return app->curdata.contactid - 1;
- return input_mt_get_slot_by_key(input, td->curdata.contactid);
+ return input_mt_get_slot_by_key(input, app->curdata.contactid);
}
/*
* this function is called when a whole contact has been processed,
* so that it can assign it to a slot and store the data there
*/
-static void mt_complete_slot(struct mt_device *td, struct input_dev *input)
+static void mt_complete_slot(struct mt_device *td, struct mt_application *app,
+ struct input_dev *input)
{
if ((td->mtclass.quirks & MT_QUIRK_CONTACT_CNT_ACCURATE) &&
- td->num_received >= td->num_expected)
+ app->num_received >= app->num_expected)
return;
- if (td->curvalid || (td->mtclass.quirks & MT_QUIRK_ALWAYS_VALID)) {
+ if (app->curvalid || (td->mtclass.quirks & MT_QUIRK_ALWAYS_VALID)) {
int active;
- int slotnum = mt_compute_slot(td, input);
- struct mt_slot *s = &td->curdata;
+ int slotnum = mt_compute_slot(td, app, input);
+ struct mt_slot *s = &app->curdata;
struct input_mt *mt = input->mt;
if (slotnum < 0 || slotnum >= td->maxcontacts)
@@ -753,23 +805,25 @@ static void mt_complete_slot(struct mt_device *td, struct input_dev *input)
}
}
- td->num_received++;
+ app->num_received++;
}
/*
* this function is called when a whole packet has been received and processed,
* so that it can decide what to send to the input layer.
*/
-static void mt_sync_frame(struct mt_device *td, struct input_dev *input)
+static void mt_sync_frame(struct mt_device *td, struct mt_application *app,
+ struct input_dev *input)
{
if (td->mtclass.quirks & MT_QUIRK_WIN8_PTP_BUTTONS)
- input_event(input, EV_KEY, BTN_LEFT, td->left_button_state);
+ input_event(input, EV_KEY, BTN_LEFT, app->left_button_state);
input_mt_sync_frame(input);
- input_event(input, EV_MSC, MSC_TIMESTAMP, td->timestamp);
+ input_event(input, EV_MSC, MSC_TIMESTAMP, app->timestamp);
input_sync(input);
- td->num_received = 0;
- td->left_button_state = 0;
+ app->num_received = 0;
+ app->left_button_state = 0;
+
if (test_bit(MT_IO_FLAGS_ACTIVE_SLOTS, &td->mt_io_flags))
set_bit(MT_IO_FLAGS_PENDING_SLOTS, &td->mt_io_flags);
else
@@ -777,14 +831,13 @@ static void mt_sync_frame(struct mt_device *td, struct input_dev *input)
clear_bit(MT_IO_FLAGS_ACTIVE_SLOTS, &td->mt_io_flags);
}
-static int mt_compute_timestamp(struct mt_device *td, struct hid_field *field,
- __s32 value)
+static int mt_compute_timestamp(struct mt_application *app,
+ struct hid_field *field, __s32 value)
{
- long delta = value - td->dev_time;
- unsigned long jdelta = jiffies_to_usecs(jiffies - td->jiffies);
+ long delta = value - app->prev_scantime;
+ unsigned long jdelta = jiffies_to_usecs(jiffies - app->jiffies);
- td->jiffies = jiffies;
- td->dev_time = value;
+ app->jiffies = jiffies;
if (delta < 0)
delta += field->logical_maximum;
@@ -796,7 +849,7 @@ static int mt_compute_timestamp(struct mt_device *td, struct hid_field *field,
/* No data received for a while, resync the timestamp. */
return 0;
else
- return td->timestamp + delta;
+ return app->timestamp + delta;
}
static int mt_touch_event(struct hid_device *hid, struct hid_field *field,
@@ -811,7 +864,7 @@ static int mt_touch_event(struct hid_device *hid, struct hid_field *field,
static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field,
struct hid_usage *usage, __s32 value,
- bool first_packet)
+ struct mt_application *app, bool first_packet)
{
struct mt_device *td = hid_get_drvdata(hid);
__s32 quirks = td->mtclass.quirks;
@@ -821,47 +874,48 @@ static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field,
switch (usage->hid) {
case HID_DG_INRANGE:
if (quirks & MT_QUIRK_VALID_IS_INRANGE)
- td->curvalid = value;
+ app->curvalid = value;
if (quirks & MT_QUIRK_HOVERING)
- td->curdata.inrange_state = value;
+ app->curdata.inrange_state = value;
break;
case HID_DG_TIPSWITCH:
if (quirks & MT_QUIRK_NOT_SEEN_MEANS_UP)
- td->curvalid = value;
- td->curdata.touch_state = value;
+ app->curvalid = value;
+ app->curdata.touch_state = value;
break;
case HID_DG_CONFIDENCE:
if (quirks & MT_QUIRK_CONFIDENCE)
- td->curdata.confidence_state = value;
+ app->curdata.confidence_state = value;
if (quirks & MT_QUIRK_VALID_IS_CONFIDENCE)
- td->curvalid = value;
+ app->curvalid = value;
break;
case HID_DG_CONTACTID:
- td->curdata.contactid = value;
+ app->curdata.contactid = value;
break;
case HID_DG_TIPPRESSURE:
- td->curdata.p = value;
+ app->curdata.p = value;
break;
case HID_GD_X:
if (usage->code == ABS_MT_TOOL_X)
- td->curdata.cx = value;
+ app->curdata.cx = value;
else
- td->curdata.x = value;
+ app->curdata.x = value;
break;
case HID_GD_Y:
if (usage->code == ABS_MT_TOOL_Y)
- td->curdata.cy = value;
+ app->curdata.cy = value;
else
- td->curdata.y = value;
+ app->curdata.y = value;
break;
case HID_DG_WIDTH:
- td->curdata.w = value;
+ app->curdata.w = value;
break;
case HID_DG_HEIGHT:
- td->curdata.h = value;
+ app->curdata.h = value;
break;
case HID_DG_SCANTIME:
- td->timestamp = mt_compute_timestamp(td, field, value);
+ app->timestamp = mt_compute_timestamp(app, field,
+ value);
break;
case HID_DG_CONTACTCOUNT:
break;
@@ -878,8 +932,8 @@ static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field,
*/
if (value > field->logical_maximum / 2)
value -= field->logical_maximum;
- td->curdata.a = -value;
- td->curdata.has_azimuth = true;
+ app->curdata.a = -value;
+ app->curdata.has_azimuth = true;
break;
case HID_DG_TOUCH:
/* do nothing */
@@ -904,7 +958,7 @@ static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field,
*/
if ((quirks & MT_QUIRK_WIN8_PTP_BUTTONS) &&
usage->type == EV_KEY && usage->code == BTN_LEFT) {
- td->left_button_state |= value;
+ app->left_button_state |= value;
return;
}
@@ -916,8 +970,9 @@ static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field,
if (usage->usage_index + 1 == field->report_count) {
/* we only take into account the last report. */
- if (usage->hid == td->last_slot_field)
- mt_complete_slot(td, field->hidinput->input);
+ if (usage->hid == app->last_slot_field)
+ mt_complete_slot(td, app,
+ field->hidinput->input);
}
}
@@ -926,26 +981,34 @@ static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field,
static void mt_touch_report(struct hid_device *hid, struct hid_report *report)
{
struct mt_device *td = hid_get_drvdata(hid);
+ struct mt_application *app;
struct hid_field *field;
bool first_packet;
unsigned count;
- int r, n, scantime = 0;
+ int r, n;
+ int scantime = 0;
+ int contact_count = -1;
/* sticky fingers release in progress, abort */
if (test_and_set_bit(MT_IO_FLAGS_RUNNING, &td->mt_io_flags))
return;
+ app = mt_find_application(td, report->application);
+
+ if (!app)
+ return;
+
/*
* Includes multi-packet support where subsequent
* packets are sent with zero contactcount.
*/
- if (td->scantime_index >= 0) {
- field = report->field[td->scantime_index];
- scantime = field->value[td->scantime_val_index];
+ if (app->scantime_index >= 0) {
+ field = report->field[app->scantime_index];
+ scantime = field->value[app->scantime_val_index];
}
- if (td->cc_index >= 0) {
- struct hid_field *field = report->field[td->cc_index];
- int value = field->value[td->cc_value_index];
+ if (app->cc_index >= 0) {
+ field = report->field[app->cc_index];
+ contact_count = field->value[app->cc_value_index];
/*
* For Win8 PTPs the first packet (td->num_received == 0) may
@@ -955,15 +1018,16 @@ static void mt_touch_report(struct hid_device *hid, struct hid_report *report)
* timestamp has changed.
*/
if ((td->mtclass.quirks & MT_QUIRK_WIN8_PTP_BUTTONS) &&
- td->num_received == 0 && td->prev_scantime != scantime)
- td->num_expected = value;
+ app->num_received == 0 &&
+ app->prev_scantime != scantime)
+ app->num_expected = contact_count;
/* A non 0 contact count always indicates a first packet */
- else if (value)
- td->num_expected = value;
+ else if (contact_count)
+ app->num_expected = contact_count;
}
- td->prev_scantime = scantime;
+ app->prev_scantime = scantime;
- first_packet = td->num_received == 0;
+ first_packet = app->num_received == 0;
for (r = 0; r < report->maxfield; r++) {
field = report->field[r];
count = field->report_count;
@@ -973,11 +1037,11 @@ static void mt_touch_report(struct hid_device *hid, struct hid_report *report)
for (n = 0; n < count; n++)
mt_process_mt_event(hid, field, &field->usage[n],
- field->value[n], first_packet);
+ field->value[n], app, first_packet);
}
- if (td->num_received >= td->num_expected)
- mt_sync_frame(td, report->field[0]->hidinput->input);
+ if (app->num_received >= app->num_expected)
+ mt_sync_frame(td, app, report->field[0]->hidinput->input);
/*
* Windows 8 specs says 2 things:
@@ -1009,7 +1073,8 @@ static void mt_touch_report(struct hid_device *hid, struct hid_report *report)
}
static int mt_touch_input_configured(struct hid_device *hdev,
- struct hid_input *hi)
+ struct hid_input *hi,
+ struct mt_application *app)
{
struct mt_device *td = hid_get_drvdata(hdev);
struct mt_class *cls = &td->mtclass;
@@ -1019,28 +1084,29 @@ static int mt_touch_input_configured(struct hid_device *hdev,
if (!td->maxcontacts)
td->maxcontacts = MT_DEFAULT_MAXCONTACT;
- mt_post_parse(td);
+ mt_post_parse(td, app);
if (td->serial_maybe)
- mt_post_parse_default_settings(td);
+ mt_post_parse_default_settings(td, app);
if (cls->is_indirect)
- td->mt_flags |= INPUT_MT_POINTER;
+ app->mt_flags |= INPUT_MT_POINTER;
if (cls->quirks & MT_QUIRK_NOT_SEEN_MEANS_UP)
- td->mt_flags |= INPUT_MT_DROP_UNUSED;
+ app->mt_flags |= INPUT_MT_DROP_UNUSED;
/* check for clickpads */
- if ((td->mt_flags & INPUT_MT_POINTER) && (td->buttons_count == 1))
+ if ((app->mt_flags & INPUT_MT_POINTER) &&
+ (app->buttons_count == 1))
td->is_buttonpad = true;
if (td->is_buttonpad)
__set_bit(INPUT_PROP_BUTTONPAD, input->propbit);
- ret = input_mt_init_slots(input, td->maxcontacts, td->mt_flags);
+ ret = input_mt_init_slots(input, td->maxcontacts, app->mt_flags);
if (ret)
return ret;
- td->mt_flags = 0;
+ app->mt_flags = 0;
return 0;
}
@@ -1051,6 +1117,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
unsigned long **bit, int *max)
{
struct mt_device *td = hid_get_drvdata(hdev);
+ struct mt_application *application;
/*
* If mtclass.export_all_inputs is not set, only map fields from
@@ -1093,6 +1160,8 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
return 1;
}
+ application = mt_find_application(td, field->application);
+
/*
* some egalax touchscreens have "application == HID_DG_TOUCHSCREEN"
* for the stylus.
@@ -1109,7 +1178,8 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
if (field->application == HID_DG_TOUCHSCREEN ||
field->application == HID_DG_TOUCHPAD)
- return mt_touch_input_mapping(hdev, hi, field, usage, bit, max);
+ return mt_touch_input_mapping(hdev, hi, field, usage, bit, max,
+ application);
/* let hid-core decide for the others */
return 0;
@@ -1259,12 +1329,13 @@ static void mt_set_modes(struct hid_device *hdev, enum latency_mode latency,
}
}
-static void mt_post_parse_default_settings(struct mt_device *td)
+static void mt_post_parse_default_settings(struct mt_device *td,
+ struct mt_application *app)
{
__s32 quirks = td->mtclass.quirks;
/* unknown serial device needs special quirks */
- if (td->touches_by_report == 1) {
+ if (app->touches_by_report == 1) {
quirks |= MT_QUIRK_ALWAYS_VALID;
quirks &= ~MT_QUIRK_NOT_SEEN_MEANS_UP;
quirks &= ~MT_QUIRK_VALID_IS_INRANGE;
@@ -1275,17 +1346,19 @@ static void mt_post_parse_default_settings(struct mt_device *td)
td->mtclass.quirks = quirks;
}
-static void mt_post_parse(struct mt_device *td)
+static void mt_post_parse(struct mt_device *td, struct mt_application *app)
{
struct mt_fields *f = td->fields;
struct mt_class *cls = &td->mtclass;
- if (td->touches_by_report > 0) {
- int field_count_per_touch = f->length / td->touches_by_report;
- td->last_slot_field = f->usages[field_count_per_touch - 1];
+ if (app->touches_by_report > 0) {
+ int field_count_per_touch;
+
+ field_count_per_touch = f->length / app->touches_by_report;
+ app->last_slot_field = f->usages[field_count_per_touch - 1];
}
- if (td->cc_index < 0)
+ if (app->cc_index < 0)
cls->quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE;
}
@@ -1295,13 +1368,17 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi)
char *name;
const char *suffix = NULL;
unsigned int application = 0;
+ struct mt_application *mt_application = NULL;
struct hid_report *report;
int ret;
list_for_each_entry(report, &hi->reports, hidinput_list) {
application = report->application;
+ mt_application = mt_find_application(td, application);
+
if (report->id == td->mt_report_id) {
- ret = mt_touch_input_configured(hdev, hi);
+ ret = mt_touch_input_configured(hdev, hi,
+ mt_application);
if (ret)
return ret;
}
@@ -1390,6 +1467,7 @@ static void mt_fix_const_fields(struct hid_device *hdev, unsigned int usage)
static void mt_release_contacts(struct hid_device *hid)
{
struct hid_input *hidinput;
+ struct mt_application *application;
struct mt_device *td = hid_get_drvdata(hid);
list_for_each_entry(hidinput, &hid->inputs, list) {
@@ -1409,7 +1487,9 @@ static void mt_release_contacts(struct hid_device *hid)
}
}
- td->num_received = 0;
+ list_for_each_entry(application, &td->applications, list) {
+ application->num_received = 0;
+ }
}
static void mt_expired_timeout(struct timer_list *t)
@@ -1449,11 +1529,11 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
td->hdev = hdev;
td->mtclass = *mtclass;
td->inputmode_value = MT_INPUTMODE_TOUCHSCREEN;
- td->cc_index = -1;
- td->scantime_index = -1;
td->mt_report_id = -1;
hid_set_drvdata(hdev, td);
+ INIT_LIST_HEAD(&td->applications);
+
td->fields = devm_kzalloc(&hdev->dev, sizeof(struct mt_fields),
GFP_KERNEL);
if (!td->fields) {
--
2.14.3
^ permalink raw reply related
* [PATCH v4 02/12] HID: multitouch: make sure the static list of class is not changed
From: Benjamin Tissoires @ 2018-07-13 14:13 UTC (permalink / raw)
To: Jiri Kosina, Dmitry Torokhov
Cc: Mario.Limonciello, Peter Hutterer, linux-input, linux-kernel,
Benjamin Tissoires
In-Reply-To: <20180713141354.7286-1-benjamin.tissoires@redhat.com>
const is a magic keyword here :)
Acked-by: Peter Hutterer <peter.hutterer@who-t.net>
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
---
no changes in v4
no changes in v3
no changes in v2
---
drivers/hid/hid-multitouch.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index 45968f7970f8..91624a2240ca 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -211,7 +211,7 @@ static int cypress_compute_slot(struct mt_device *td)
return -1;
}
-static struct mt_class mt_classes[] = {
+static const struct mt_class mt_classes[] = {
{ .name = MT_CLS_DEFAULT,
.quirks = MT_QUIRK_ALWAYS_VALID |
MT_QUIRK_CONTACT_CNT_ACCURATE },
@@ -1432,7 +1432,7 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
{
int ret, i;
struct mt_device *td;
- struct mt_class *mtclass = mt_classes; /* MT_CLS_DEFAULT */
+ const struct mt_class *mtclass = mt_classes; /* MT_CLS_DEFAULT */
for (i = 0; mt_classes[i].name ; i++) {
if (id->driver_data == mt_classes[i].name) {
--
2.14.3
^ permalink raw reply related
* [PATCH v4 01/12] input: add MT_TOOL_DIAL
From: Benjamin Tissoires @ 2018-07-13 14:13 UTC (permalink / raw)
To: Jiri Kosina, Dmitry Torokhov
Cc: Mario.Limonciello, Peter Hutterer, linux-input, linux-kernel,
Benjamin Tissoires
In-Reply-To: <20180713141354.7286-1-benjamin.tissoires@redhat.com>
A dial is a tool you place on a multitouch surface which reports its
orientation or a relative angle of rotation when rotating its knob.
Some examples are the Dell Totem (on the Canvas 27"), the Microsoft Dial,
or the Griffin Powermate, though the later can't be put on a touch surface.
We give some extra space to account for other types of fingers if we need
(MT_TOOL_THUMB)
Slightly change the documentation to not make it mandatory to update each
MT_TOOL we add.
Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>
Acked-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
---
changes in v4:
- replace the values with hex
- make MT_TOOL_MAX > MT_TOOL_DIAL
changes in v3:
- re-insert the change in include/uapi/linux/input.h
new in v2 (extracted from previous series in its own patch)
---
Documentation/input/multi-touch-protocol.rst | 12 ++++++------
include/uapi/linux/input.h | 9 +++++----
2 files changed, 11 insertions(+), 10 deletions(-)
diff --git a/Documentation/input/multi-touch-protocol.rst b/Documentation/input/multi-touch-protocol.rst
index b51751a0cd5d..6be70342e709 100644
--- a/Documentation/input/multi-touch-protocol.rst
+++ b/Documentation/input/multi-touch-protocol.rst
@@ -310,12 +310,12 @@ ABS_MT_TOOL_Y
ABS_MT_TOOL_TYPE
The type of approaching tool. A lot of kernel drivers cannot distinguish
between different tool types, such as a finger or a pen. In such cases, the
- event should be omitted. The protocol currently supports MT_TOOL_FINGER,
- MT_TOOL_PEN, and MT_TOOL_PALM [#f2]_. For type B devices, this event is
- handled by input core; drivers should instead use
- input_mt_report_slot_state(). A contact's ABS_MT_TOOL_TYPE may change over
- time while still touching the device, because the firmware may not be able
- to determine which tool is being used when it first appears.
+ event should be omitted. The protocol currently mainly supports
+ MT_TOOL_FINGER, MT_TOOL_PEN, and MT_TOOL_PALM [#f2]_.
+ For type B devices, this event is handled by input core; drivers should
+ instead use input_mt_report_slot_state(). A contact's ABS_MT_TOOL_TYPE may
+ change over time while still touching the device, because the firmware may
+ not be able to determine which tool is being used when it first appears.
ABS_MT_BLOB_ID
The BLOB_ID groups several packets together into one arbitrarily shaped
diff --git a/include/uapi/linux/input.h b/include/uapi/linux/input.h
index 7288a7c573cc..fb78f6f500f3 100644
--- a/include/uapi/linux/input.h
+++ b/include/uapi/linux/input.h
@@ -270,10 +270,11 @@ struct input_mask {
/*
* MT_TOOL types
*/
-#define MT_TOOL_FINGER 0
-#define MT_TOOL_PEN 1
-#define MT_TOOL_PALM 2
-#define MT_TOOL_MAX 2
+#define MT_TOOL_FINGER 0x00
+#define MT_TOOL_PEN 0x01
+#define MT_TOOL_PALM 0x02
+#define MT_TOOL_DIAL 0x0a
+#define MT_TOOL_MAX 0x0f
/*
* Values describing the status of a force-feedback effect
--
2.14.3
^ permalink raw reply related
* [PATCH v4 00/12] Hid multitouch rewrite, support os system multi-axis devices, take 4
From: Benjamin Tissoires @ 2018-07-13 14:13 UTC (permalink / raw)
To: Jiri Kosina, Dmitry Torokhov
Cc: Mario.Limonciello, Peter Hutterer, linux-input, linux-kernel,
Benjamin Tissoires
Hi,
this is the v4 of my hid-multitouch rewrite series.
Changes are:
- added Peter's rev-by / acked-by
- changed MT_TOOL_MAX value to be 0x0f
- dropped the touch major/minor modifications
Cheers,
Benjamin
Benjamin Tissoires (12):
input: add MT_TOOL_DIAL
HID: multitouch: make sure the static list of class is not changed
HID: multitouch: Store per collection multitouch data
HID: multitouch: store a per application quirks value
HID: multitouch: ditch mt_report_id
HID: multitouch: remove one copy of values
HID: input: enable Totem on the Dell Canvas 27
HID: core: do not upper bound the collection stack
HID: microsoft: support the Surface Dial
HID: multitouch: report MT_TOOL_PALM for non-confident touches
HID: multitouch: touchscreens also use confidence reports
HID: multitouch: handle palm for touchscreens
Documentation/input/multi-touch-protocol.rst | 12 +-
drivers/hid/hid-core.c | 17 +-
drivers/hid/hid-input.c | 3 +
drivers/hid/hid-microsoft.c | 49 +-
drivers/hid/hid-multitouch.c | 989 ++++++++++++++++-----------
include/linux/hid.h | 15 +-
include/uapi/linux/input.h | 9 +-
7 files changed, 679 insertions(+), 415 deletions(-)
--
2.14.3
^ permalink raw reply
* Re: [PATCH v2 00/10] Split i2c_lock_adapter into i2c_lock_root and i2c_lock_segment
From: Wolfram Sang @ 2018-07-12 22:11 UTC (permalink / raw)
To: Peter Rosin
Cc: linux-kernel, Peter Huewe, Jarkko Sakkinen, Jason Gunthorpe,
Arnd Bergmann, Greg Kroah-Hartman, Brian Norris, Gregory Fong,
Florian Fainelli, bcm-kernel-feedback-list, Sekhar Nori,
Kevin Hilman, Haavard Skinnemoen, Kukjin Kim, Krzysztof Kozlowski,
Orson Zhai, Baolin Wang, Chunyan Zhang, Guenter Roeck, Crt Mori
In-Reply-To: <20180620051803.12206-1-peda@axentia.se>
[-- Attachment #1: Type: text/plain, Size: 2366 bytes --]
On Wed, Jun 20, 2018 at 07:17:53AM +0200, Peter Rosin wrote:
> Hi!
>
> With the introduction of mux-locked I2C muxes, the concept of
> locking only a segment of the I2C adapter tree was added. At the
> time, I did not want to cause a lot of extra churn, so left most
> users of i2c_lock_adapter alone and apparently didn't think enough
> about it; they simply continued to lock the whole adapter tree.
> However, i2c_lock_adapter is in fact wrong for almost every caller
> (there is naturally an exception) that is itself not a driver for
> a root adapter. What normal drivers generally want is to only
> lock the segment of the adapter tree that their device sits on.
>
> In fact, if a device sits behind a mux-locked I2C mux, and its
> driver calls i2c_lock_adapter followed by an unlocked I2C transfer,
> things will deadlock (since even a mux-locked I2C adapter will lock
> its parent at some point). If the device is not sitting behind a
> mux-locked I2C mux (i.e. either directly on the root adapter or
> behind a (chain of) parent-locked I2C muxes) the root/segment
> distinction is of no consequence; the root adapter is locked either
> way.
>
> Mux-locked I2C muxes are probably not that common, and putting any
> of the affected devices behind one is probably even rarer, which
> is why we have not seen any deadlocks. At least not that I know
> of...
>
> Since silently changing the semantics of i2c_lock_adapter might
> be quite a surprise, especially for out-of-tree users, this series
> instead removes the function and forces all users to explicitly
> name I2C_LOCK_SEGMENT or I2C_LOCK_ROOT_ADAPTER in a call to
> i2c_lock_bus, as suggested by Wolfram. Yes, users will be a teensy
> bit more wordy, but open-coding I2C locking from random drivers
> should be avoided, so it's perhaps a good thing if it doesn't look
> too neat?
>
> I suggest that Wolfram takes this series through the I2C tree and
> creates an immutable branch for the other subsystems. The series
> is based on v4.18-r1.
>
> I do not have *any* of the affected devices, and have thus only
> done build tests.
>
> Cheers,
> Peter
Applied to for-next, thanks! And thanks for all the acks. An immutable
branch can be found here:
git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux.git i2c/precise-locking-names_immutable
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply
* Re: [PATCH v2 00/10] Split i2c_lock_adapter into i2c_lock_root and i2c_lock_segment
From: Mauro Carvalho Chehab @ 2018-07-12 21:59 UTC (permalink / raw)
To: Wolfram Sang
Cc: Crt Mori, linux-iio, Sekhar Nori, Jarkko Sakkinen, linux-i2c,
Peter Meerwald-Stadler, Peter Huewe, Michael Krufky, Lee Jones,
Antti Palosaari, linux-samsung-soc, Florian Fainelli,
Kevin Hilman, Chunyan Zhang, Krzysztof Kozlowski, Jason Gunthorpe,
Kukjin Kim, bcm-kernel-feedback-list, linux-input, Orson Zhai,
Guenter Roeck, Haavard Skinnemoen, Arnd Bergmann, linux-media,
Lars-Peter Clausen, Gregory
In-Reply-To: <20180712212850.axi3rrfwivqymqh5@ninjato>
Em Thu, 12 Jul 2018 23:28:51 +0200
Wolfram Sang <wsa@the-dreams.de> escreveu:
> On Tue, Jun 26, 2018 at 11:37:36AM +0900, Wolfram Sang wrote:
> > On Wed, Jun 20, 2018 at 07:17:53AM +0200, Peter Rosin wrote:
> > > Hi!
> > >
> > > With the introduction of mux-locked I2C muxes, the concept of
> > > locking only a segment of the I2C adapter tree was added. At the
> > > time, I did not want to cause a lot of extra churn, so left most
> > > users of i2c_lock_adapter alone and apparently didn't think enough
> > > about it; they simply continued to lock the whole adapter tree.
> > > However, i2c_lock_adapter is in fact wrong for almost every caller
> > > (there is naturally an exception) that is itself not a driver for
> > > a root adapter. What normal drivers generally want is to only
> > > lock the segment of the adapter tree that their device sits on.
> > >
> > > In fact, if a device sits behind a mux-locked I2C mux, and its
> > > driver calls i2c_lock_adapter followed by an unlocked I2C transfer,
> > > things will deadlock (since even a mux-locked I2C adapter will lock
> > > its parent at some point). If the device is not sitting behind a
> > > mux-locked I2C mux (i.e. either directly on the root adapter or
> > > behind a (chain of) parent-locked I2C muxes) the root/segment
> > > distinction is of no consequence; the root adapter is locked either
> > > way.
> > >
> > > Mux-locked I2C muxes are probably not that common, and putting any
> > > of the affected devices behind one is probably even rarer, which
> > > is why we have not seen any deadlocks. At least not that I know
> > > of...
> > >
> > > Since silently changing the semantics of i2c_lock_adapter might
> > > be quite a surprise, especially for out-of-tree users, this series
> > > instead removes the function and forces all users to explicitly
> > > name I2C_LOCK_SEGMENT or I2C_LOCK_ROOT_ADAPTER in a call to
> > > i2c_lock_bus, as suggested by Wolfram. Yes, users will be a teensy
> > > bit more wordy, but open-coding I2C locking from random drivers
> > > should be avoided, so it's perhaps a good thing if it doesn't look
> > > too neat?
> > >
> > > I suggest that Wolfram takes this series through the I2C tree and
> > > creates an immutable branch for the other subsystems. The series
> > > is based on v4.18-r1.
> >
> > Applied to a seperate branch named "i2c/precise-locking-names" which I
> > will merge into for-next, so it will get proper testing already. Once we
> > get the missing acks from media, MFD, and IIO maintainers, I will merge
> > it into for-4.19.
>
> Ping for media related acks.
For the media-related ones:
Acked-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
>
> Thanks,
>
> Wolfram
>
Thanks,
Mauro
^ permalink raw reply
* Re: [PATCH v2 00/10] Split i2c_lock_adapter into i2c_lock_root and i2c_lock_segment
From: Wolfram Sang @ 2018-07-12 21:28 UTC (permalink / raw)
To: Peter Rosin
Cc: linux-kernel, Peter Huewe, Jarkko Sakkinen, Jason Gunthorpe,
Arnd Bergmann, Greg Kroah-Hartman, Brian Norris, Gregory Fong,
Florian Fainelli, bcm-kernel-feedback-list, Sekhar Nori,
Kevin Hilman, Haavard Skinnemoen, Kukjin Kim, Krzysztof Kozlowski,
Orson Zhai, Baolin Wang, Chunyan Zhang, Guenter Roeck, Crt Mori
In-Reply-To: <20180626023735.xj7aqhvw7ta2lq6s@ninjato>
[-- Attachment #1: Type: text/plain, Size: 2498 bytes --]
On Tue, Jun 26, 2018 at 11:37:36AM +0900, Wolfram Sang wrote:
> On Wed, Jun 20, 2018 at 07:17:53AM +0200, Peter Rosin wrote:
> > Hi!
> >
> > With the introduction of mux-locked I2C muxes, the concept of
> > locking only a segment of the I2C adapter tree was added. At the
> > time, I did not want to cause a lot of extra churn, so left most
> > users of i2c_lock_adapter alone and apparently didn't think enough
> > about it; they simply continued to lock the whole adapter tree.
> > However, i2c_lock_adapter is in fact wrong for almost every caller
> > (there is naturally an exception) that is itself not a driver for
> > a root adapter. What normal drivers generally want is to only
> > lock the segment of the adapter tree that their device sits on.
> >
> > In fact, if a device sits behind a mux-locked I2C mux, and its
> > driver calls i2c_lock_adapter followed by an unlocked I2C transfer,
> > things will deadlock (since even a mux-locked I2C adapter will lock
> > its parent at some point). If the device is not sitting behind a
> > mux-locked I2C mux (i.e. either directly on the root adapter or
> > behind a (chain of) parent-locked I2C muxes) the root/segment
> > distinction is of no consequence; the root adapter is locked either
> > way.
> >
> > Mux-locked I2C muxes are probably not that common, and putting any
> > of the affected devices behind one is probably even rarer, which
> > is why we have not seen any deadlocks. At least not that I know
> > of...
> >
> > Since silently changing the semantics of i2c_lock_adapter might
> > be quite a surprise, especially for out-of-tree users, this series
> > instead removes the function and forces all users to explicitly
> > name I2C_LOCK_SEGMENT or I2C_LOCK_ROOT_ADAPTER in a call to
> > i2c_lock_bus, as suggested by Wolfram. Yes, users will be a teensy
> > bit more wordy, but open-coding I2C locking from random drivers
> > should be avoided, so it's perhaps a good thing if it doesn't look
> > too neat?
> >
> > I suggest that Wolfram takes this series through the I2C tree and
> > creates an immutable branch for the other subsystems. The series
> > is based on v4.18-r1.
>
> Applied to a seperate branch named "i2c/precise-locking-names" which I
> will merge into for-next, so it will get proper testing already. Once we
> get the missing acks from media, MFD, and IIO maintainers, I will merge
> it into for-4.19.
Ping for media related acks.
Thanks,
Wolfram
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply
* Re: [PATCH v10 1/2] mfd: bd71837: mfd driver for ROHM BD71837 PMIC
From: Lee Jones @ 2018-07-12 13:00 UTC (permalink / raw)
To: Matti Vaittinen
Cc: mturquette, robh+dt, sboyd, mark.rutland, lgirdwood, broonie,
mazziesaccount, arnd, dmitry.torokhov, sre, chenjh,
andrew.smirnov, linus.walleij, kstewart, heiko, gregkh, eballetbo,
linux-clk, devicetree, linux-kernel, linux-input, mikko.mutanen,
heikki.haikola
In-Reply-To: <e737bb13d17b75ea5e55f59005ef3181d428e704.1530800707.git.matti.vaittinen@fi.rohmeurope.com>
On Thu, 05 Jul 2018, Matti Vaittinen wrote:
> ROHM BD71837 PMIC MFD driver providing interrupts and support
> for three subsystems:
> - clk
> - Regulators
> - input/power-key
>
> Signed-off-by: Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>
> ---
> drivers/mfd/Kconfig | 13 ++
> drivers/mfd/Makefile | 1 +
> drivers/mfd/rohm-bd718x7.c | 198 +++++++++++++++++++++++
> include/linux/mfd/rohm-bd718x7.h | 333 +++++++++++++++++++++++++++++++++++++++
> 4 files changed, 545 insertions(+)
> create mode 100644 drivers/mfd/rohm-bd718x7.c
> create mode 100644 include/linux/mfd/rohm-bd718x7.h
Just a few nits. See below.
> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> index b860eb5aa194..ac317c9bf065 100644
> --- a/drivers/mfd/Kconfig
> +++ b/drivers/mfd/Kconfig
> @@ -1787,6 +1787,19 @@ config MFD_STW481X
> in various ST Microelectronics and ST-Ericsson embedded
> Nomadik series.
>
> +config MFD_ROHM_BD718XX
> + tristate "ROHM BD71837 Power Management IC"
> + depends on I2C=y
> + depends on OF
> + select REGMAP_I2C
> + select REGMAP_IRQ
> + select MFD_CORE
> + help
> + Select this option to get support for the ROHM BD71837
> + Power Management ICs. BD71837 is designed to power processors like
> + NXP i.MX8. It contains 8 BUCK outputs and 7 LDOs, voltage monitoring
> + and emergency shut down as well as 32,768KHz clock output.
> +
> config MFD_STM32_LPTIMER
> tristate "Support for STM32 Low-Power Timer"
> depends on (ARCH_STM32 && OF) || COMPILE_TEST
> diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
> index e9fd20dba18d..c7a5c3b0e776 100644
> --- a/drivers/mfd/Makefile
> +++ b/drivers/mfd/Makefile
> @@ -227,4 +227,5 @@ obj-$(CONFIG_MFD_STM32_TIMERS) += stm32-timers.o
> obj-$(CONFIG_MFD_MXS_LRADC) += mxs-lradc.o
> obj-$(CONFIG_MFD_SC27XX_PMIC) += sprd-sc27xx-spi.o
> obj-$(CONFIG_RAVE_SP_CORE) += rave-sp.o
> +obj-$(CONFIG_MFD_ROHM_BD718XX) += rohm-bd718x7.o
>
> diff --git a/drivers/mfd/rohm-bd718x7.c b/drivers/mfd/rohm-bd718x7.c
> new file mode 100644
> index 000000000000..34df74940dfa
> --- /dev/null
> +++ b/drivers/mfd/rohm-bd718x7.c
> @@ -0,0 +1,198 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +//
> +// Copyright (C) 2018 ROHM Semiconductors
> +//
> +// ROHM BD71837MWV PMIC driver
> +//
> +// Datasheet available from
> +// https://www.rohm.com/datasheet/BD71837MWV/bd71837mwv-e
> +
> +#include <linux/i2c.h>
> +#include <linux/input.h>
> +#include <linux/interrupt.h>
> +#include <linux/mfd/rohm-bd718x7.h>
> +#include <linux/mfd/core.h>
> +#include <linux/module.h>
> +#include <linux/regmap.h>
> +
> +/*
> + * gpio_keys.h requires definiton of bool. It is brought in
> + * by abowe includes. Keep this as last untill gpio_keys.h gets fixed.
Nit: Spell check.
> + */
> +#include <linux/gpio_keys.h>
> +
> +static struct gpio_keys_button button = {
> + .code = KEY_POWER,
> + .gpio = -1,
> + .type = EV_KEY,
> +};
> +
> +static struct gpio_keys_platform_data bd718xx_powerkey_data = {
> + .buttons = &button,
> + .nbuttons = 1,
> + .name = "bd718xx-pwrkey",
> +};
> +
> +static struct mfd_cell bd71837_mfd_cells[] = {
> + {
> + .name = "gpio-keys",
> + .platform_data = &bd718xx_powerkey_data,
> + .pdata_size = sizeof(bd718xx_powerkey_data),
> + },
> + { .name = "bd71837-clk", },
> + { .name = "bd71837-pmic", },
> +};
> +
> +static const struct regmap_irq bd71837_irqs[] = {
> + REGMAP_IRQ_REG(BD71837_INT_SWRST, 0, BD71837_INT_SWRST_MASK),
> + REGMAP_IRQ_REG(BD71837_INT_PWRBTN_S, 0, BD71837_INT_PWRBTN_S_MASK),
> + REGMAP_IRQ_REG(BD71837_INT_PWRBTN_L, 0, BD71837_INT_PWRBTN_L_MASK),
> + REGMAP_IRQ_REG(BD71837_INT_PWRBTN, 0, BD71837_INT_PWRBTN_MASK),
> + REGMAP_IRQ_REG(BD71837_INT_WDOG, 0, BD71837_INT_WDOG_MASK),
> + REGMAP_IRQ_REG(BD71837_INT_ON_REQ, 0, BD71837_INT_ON_REQ_MASK),
> + REGMAP_IRQ_REG(BD71837_INT_STBY_REQ, 0, BD71837_INT_STBY_REQ_MASK),
> +};
> +
> +static struct regmap_irq_chip bd71837_irq_chip = {
> + .name = "bd71837-irq",
> + .irqs = bd71837_irqs,
> + .num_irqs = ARRAY_SIZE(bd71837_irqs),
> + .num_regs = 1,
> + .irq_reg_stride = 1,
> + .status_base = BD71837_REG_IRQ,
> + .mask_base = BD71837_REG_MIRQ,
> + .ack_base = BD71837_REG_IRQ,
> + .init_ack_masked = true,
> + .mask_invert = false,
> +};
> +
> +static const struct regmap_range pmic_status_range = {
> + .range_min = BD71837_REG_IRQ,
> + .range_max = BD71837_REG_POW_STATE,
> +};
> +
> +static const struct regmap_access_table volatile_regs = {
> + .yes_ranges = &pmic_status_range,
> + .n_yes_ranges = 1,
> +};
> +
> +static const struct regmap_config bd71837_regmap_config = {
> + .reg_bits = 8,
> + .val_bits = 8,
> + .volatile_table = &volatile_regs,
> + .max_register = BD71837_MAX_REGISTER - 1,
> + .cache_type = REGCACHE_RBTREE,
> +};
> +
> +static const struct of_device_id bd71837_of_match[] = {
> + { .compatible = "rohm,bd71837", },
> + { }
> +};
> +MODULE_DEVICE_TABLE(of, bd71837_of_match);
This has no reason for being here.
Please move it to *just* before it's about to be used.
> +static int bd71837_i2c_probe(struct i2c_client *i2c,
> + const struct i2c_device_id *id)
> +{
> + struct bd71837 *bd71837;
> + int ret;
> + unsigned int val;
> +
> + bd71837 = devm_kzalloc(&i2c->dev, sizeof(struct bd71837), GFP_KERNEL);
> +
> + if (!bd71837)
> + return -ENOMEM;
> +
> + bd71837->chip_irq = i2c->irq;
> +
> + if (!bd71837->chip_irq) {
> + dev_err(&i2c->dev, "No IRQ configured\n");
> + return -EINVAL;
> + }
> +
> + bd71837->dev = &i2c->dev;
> + bd71837->i2c_client = i2c;
> + i2c_set_clientdata(i2c, bd71837);
> +
> + bd71837->regmap = devm_regmap_init_i2c(i2c, &bd71837_regmap_config);
> + if (IS_ERR(bd71837->regmap)) {
> + dev_err(&i2c->dev, "regmap initialization failed\n");
> + return PTR_ERR(bd71837->regmap);
> + }
> +
> + ret = regmap_read(bd71837->regmap, BD71837_REG_REV, &val);
> + if (ret) {
> + dev_err(&i2c->dev, "Read BD71837_REG_DEVICE failed\n");
> + return ret;
> + }
You never do anything with the value here.
Please either utilise it, read something useful or remove it.
> + ret = devm_regmap_add_irq_chip(&i2c->dev, bd71837->regmap,
> + bd71837->chip_irq, IRQF_ONESHOT, 0,
> + &bd71837_irq_chip, &bd71837->irq_data);
> + if (ret) {
> + dev_err(&i2c->dev, "Failed to add irq_chip\n");
> + return ret;
> + }
> +
> + /* Configure short press to 10 milliseconds */
> + ret = regmap_update_bits(bd71837->regmap,
> + BD71837_REG_PWRONCONFIG0,
> + BD718XX_PWRBTN_PRESS_DURATION_MASK,
> + BD718XX_PWRBTN_SHORT_PRESS_10MS);
> + if (ret) {
> + dev_err(&i2c->dev, "Failed to configure button short press timeout\n");
> + return ret;
> + }
> +
> + /* Configure long press to 10 seconds */
> + ret = regmap_update_bits(bd71837->regmap,
> + BD71837_REG_PWRONCONFIG1,
> + BD718XX_PWRBTN_PRESS_DURATION_MASK,
> + BD718XX_PWRBTN_LONG_PRESS_10S);
> +
> + if (ret) {
> + dev_err(&i2c->dev, "Failed to configure button long press timeout\n");
> + return ret;
> + }
> +
> + button.irq = regmap_irq_get_virq(bd71837->irq_data,
> + BD71837_INT_PWRBTN_S);
> +
> + if (button.irq < 0) {
> + dev_err(&i2c->dev, "Failed to get the IRQ\n");
> + return button.irq;
> + }
> +
> + ret = devm_mfd_add_devices(bd71837->dev, PLATFORM_DEVID_AUTO,
> + bd71837_mfd_cells,
> + ARRAY_SIZE(bd71837_mfd_cells), NULL, 0,
> + regmap_irq_get_domain(bd71837->irq_data));
> + if (ret)
> + dev_err(&i2c->dev, "Failed to create subdevices\n");
> +
> + return ret;
> +}
> +
> +static struct i2c_driver bd71837_i2c_driver = {
> + .driver = {
> + .name = "rohm-bd718x7",
> + .of_match_table = bd71837_of_match,
> + },
> + .probe = bd71837_i2c_probe,
> +};
> +
> +static int __init bd71837_i2c_init(void)
> +{
> + return i2c_add_driver(&bd71837_i2c_driver);
> +}
Nit: '\n' here.
> +/* init early so consumer devices can complete system boot */
Nit: s/init/Initialise/
> +subsys_initcall(bd71837_i2c_init);
> +
> +static void __exit bd71837_i2c_exit(void)
> +{
> + i2c_del_driver(&bd71837_i2c_driver);
> +}
> +module_exit(bd71837_i2c_exit);
> +
> +MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
> +MODULE_DESCRIPTION("ROHM BD71837 Power Management IC driver");
> +MODULE_LICENSE("GPL");
> diff --git a/include/linux/mfd/rohm-bd718x7.h b/include/linux/mfd/rohm-bd718x7.h
> new file mode 100644
> index 000000000000..749d72ed9ae5
> --- /dev/null
> +++ b/include/linux/mfd/rohm-bd718x7.h
> @@ -0,0 +1,333 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/* Copyright (C) 2018 ROHM Semiconductors */
> +
> +#ifndef __LINUX_MFD_BD71837_H__
> +#define __LINUX_MFD_BD71837_H__
> +
> +#include <linux/regmap.h>
> +
> +enum {
> + BD71837_BUCK1 = 0,
> + BD71837_BUCK2,
> + BD71837_BUCK3,
> + BD71837_BUCK4,
> + BD71837_BUCK5,
> + BD71837_BUCK6,
> + BD71837_BUCK7,
> + BD71837_BUCK8,
> + BD71837_LDO1,
> + BD71837_LDO2,
> + BD71837_LDO3,
> + BD71837_LDO4,
> + BD71837_LDO5,
> + BD71837_LDO6,
> + BD71837_LDO7,
> + BD71837_REGULATOR_CNT,
> +};
> +
> +#define BD71837_BUCK1_VOLTAGE_NUM 0x40
> +#define BD71837_BUCK2_VOLTAGE_NUM 0x40
> +#define BD71837_BUCK3_VOLTAGE_NUM 0x40
> +#define BD71837_BUCK4_VOLTAGE_NUM 0x40
> +
> +#define BD71837_BUCK5_VOLTAGE_NUM 0x08
> +#define BD71837_BUCK6_VOLTAGE_NUM 0x04
> +#define BD71837_BUCK7_VOLTAGE_NUM 0x08
> +#define BD71837_BUCK8_VOLTAGE_NUM 0x40
> +
> +#define BD71837_LDO1_VOLTAGE_NUM 0x04
> +#define BD71837_LDO2_VOLTAGE_NUM 0x02
> +#define BD71837_LDO3_VOLTAGE_NUM 0x10
> +#define BD71837_LDO4_VOLTAGE_NUM 0x10
> +#define BD71837_LDO5_VOLTAGE_NUM 0x10
> +#define BD71837_LDO6_VOLTAGE_NUM 0x10
> +#define BD71837_LDO7_VOLTAGE_NUM 0x10
> +
> +enum {
> + BD71837_REG_REV = 0x00,
> + BD71837_REG_SWRESET = 0x01,
> + BD71837_REG_I2C_DEV = 0x02,
> + BD71837_REG_PWRCTRL0 = 0x03,
> + BD71837_REG_PWRCTRL1 = 0x04,
> + BD71837_REG_BUCK1_CTRL = 0x05,
> + BD71837_REG_BUCK2_CTRL = 0x06,
> + BD71837_REG_BUCK3_CTRL = 0x07,
> + BD71837_REG_BUCK4_CTRL = 0x08,
> + BD71837_REG_BUCK5_CTRL = 0x09,
> + BD71837_REG_BUCK6_CTRL = 0x0A,
> + BD71837_REG_BUCK7_CTRL = 0x0B,
> + BD71837_REG_BUCK8_CTRL = 0x0C,
> + BD71837_REG_BUCK1_VOLT_RUN = 0x0D,
> + BD71837_REG_BUCK1_VOLT_IDLE = 0x0E,
> + BD71837_REG_BUCK1_VOLT_SUSP = 0x0F,
> + BD71837_REG_BUCK2_VOLT_RUN = 0x10,
> + BD71837_REG_BUCK2_VOLT_IDLE = 0x11,
> + BD71837_REG_BUCK3_VOLT_RUN = 0x12,
> + BD71837_REG_BUCK4_VOLT_RUN = 0x13,
> + BD71837_REG_BUCK5_VOLT = 0x14,
> + BD71837_REG_BUCK6_VOLT = 0x15,
> + BD71837_REG_BUCK7_VOLT = 0x16,
> + BD71837_REG_BUCK8_VOLT = 0x17,
> + BD71837_REG_LDO1_VOLT = 0x18,
> + BD71837_REG_LDO2_VOLT = 0x19,
> + BD71837_REG_LDO3_VOLT = 0x1A,
> + BD71837_REG_LDO4_VOLT = 0x1B,
> + BD71837_REG_LDO5_VOLT = 0x1C,
> + BD71837_REG_LDO6_VOLT = 0x1D,
> + BD71837_REG_LDO7_VOLT = 0x1E,
> + BD71837_REG_TRANS_COND0 = 0x1F,
> + BD71837_REG_TRANS_COND1 = 0x20,
> + BD71837_REG_VRFAULTEN = 0x21,
> + BD71837_REG_MVRFLTMASK0 = 0x22,
> + BD71837_REG_MVRFLTMASK1 = 0x23,
> + BD71837_REG_MVRFLTMASK2 = 0x24,
> + BD71837_REG_RCVCFG = 0x25,
> + BD71837_REG_RCVNUM = 0x26,
> + BD71837_REG_PWRONCONFIG0 = 0x27,
> + BD71837_REG_PWRONCONFIG1 = 0x28,
> + BD71837_REG_RESETSRC = 0x29,
> + BD71837_REG_MIRQ = 0x2A,
> + BD71837_REG_IRQ = 0x2B,
> + BD71837_REG_IN_MON = 0x2C,
> + BD71837_REG_POW_STATE = 0x2D,
> + BD71837_REG_OUT32K = 0x2E,
> + BD71837_REG_REGLOCK = 0x2F,
> + BD71837_REG_OTPVER = 0xFF,
> + BD71837_MAX_REGISTER = 0x100,
> +};
> +
> +#define REGLOCK_PWRSEQ 0x1
> +#define REGLOCK_VREG 0x10
> +
> +/* Generic BUCK control masks */
> +#define BD71837_BUCK_SEL 0x02
> +#define BD71837_BUCK_EN 0x01
> +#define BD71837_BUCK_RUN_ON 0x04
> +
> +/* Generic LDO masks */
> +#define BD71837_LDO_SEL 0x80
> +#define BD71837_LDO_EN 0x40
> +
> +/* BD71837 BUCK ramp rate CTRL reg bits */
> +#define BUCK_RAMPRATE_MASK 0xC0
> +#define BUCK_RAMPRATE_10P00MV 0x0
> +#define BUCK_RAMPRATE_5P00MV 0x1
> +#define BUCK_RAMPRATE_2P50MV 0x2
> +#define BUCK_RAMPRATE_1P25MV 0x3
> +
> +/* BD71837_REG_BUCK1_VOLT_RUN bits */
> +#define BUCK1_RUN_MASK 0x3F
> +#define BUCK1_RUN_DEFAULT 0x14
> +
> +/* BD71837_REG_BUCK1_VOLT_SUSP bits */
> +#define BUCK1_SUSP_MASK 0x3F
> +#define BUCK1_SUSP_DEFAULT 0x14
> +
> +/* BD71837_REG_BUCK1_VOLT_IDLE bits */
> +#define BUCK1_IDLE_MASK 0x3F
> +#define BUCK1_IDLE_DEFAULT 0x14
> +
> +/* BD71837_REG_BUCK2_VOLT_RUN bits */
> +#define BUCK2_RUN_MASK 0x3F
> +#define BUCK2_RUN_DEFAULT 0x1E
> +
> +/* BD71837_REG_BUCK2_VOLT_IDLE bits */
> +#define BUCK2_IDLE_MASK 0x3F
> +#define BUCK2_IDLE_DEFAULT 0x14
> +
> +/* BD71837_REG_BUCK3_VOLT_RUN bits */
> +#define BUCK3_RUN_MASK 0x3F
> +#define BUCK3_RUN_DEFAULT 0x1E
> +
> +/* BD71837_REG_BUCK4_VOLT_RUN bits */
> +#define BUCK4_RUN_MASK 0x3F
> +#define BUCK4_RUN_DEFAULT 0x1E
> +
> +/* BD71837_REG_BUCK5_VOLT bits */
> +#define BUCK5_MASK 0x07
> +#define BUCK5_DEFAULT 0x02
> +
> +/* BD71837_REG_BUCK6_VOLT bits */
> +#define BUCK6_MASK 0x03
> +#define BUCK6_DEFAULT 0x03
> +
> +/* BD71837_REG_BUCK7_VOLT bits */
> +#define BUCK7_MASK 0x07
> +#define BUCK7_DEFAULT 0x03
> +
> +/* BD71837_REG_BUCK8_VOLT bits */
> +#define BUCK8_MASK 0x3F
> +#define BUCK8_DEFAULT 0x1E
> +
> +/* BD71837_REG_IRQ bits */
> +#define IRQ_SWRST 0x40
> +#define IRQ_PWRON_S 0x20
> +#define IRQ_PWRON_L 0x10
> +#define IRQ_PWRON 0x08
> +#define IRQ_WDOG 0x04
> +#define IRQ_ON_REQ 0x02
> +#define IRQ_STBY_REQ 0x01
> +
> +/* BD71837_REG_OUT32K bits */
> +#define BD71837_OUT32K_EN 0x01
> +
> +/* BD71837 gated clock rate */
> +#define BD71837_CLK_RATE 32768
> +
> +/* ROHM BD71837 irqs */
> +enum {
> + BD71837_INT_STBY_REQ,
> + BD71837_INT_ON_REQ,
> + BD71837_INT_WDOG,
> + BD71837_INT_PWRBTN,
> + BD71837_INT_PWRBTN_L,
> + BD71837_INT_PWRBTN_S,
> + BD71837_INT_SWRST
> +};
> +
> +/* ROHM BD71837 interrupt masks */
> +#define BD71837_INT_SWRST_MASK 0x40
> +#define BD71837_INT_PWRBTN_S_MASK 0x20
> +#define BD71837_INT_PWRBTN_L_MASK 0x10
> +#define BD71837_INT_PWRBTN_MASK 0x8
> +#define BD71837_INT_WDOG_MASK 0x4
> +#define BD71837_INT_ON_REQ_MASK 0x2
> +#define BD71837_INT_STBY_REQ_MASK 0x1
> +
> +/* BD71837_REG_LDO1_VOLT bits */
> +#define LDO1_MASK 0x03
> +
> +/* BD71837_REG_LDO1_VOLT bits */
> +#define LDO2_MASK 0x20
> +
> +/* BD71837_REG_LDO3_VOLT bits */
> +#define LDO3_MASK 0x0F
> +
> +/* BD71837_REG_LDO4_VOLT bits */
> +#define LDO4_MASK 0x0F
> +
> +/* BD71837_REG_LDO5_VOLT bits */
> +#define LDO5_MASK 0x0F
> +
> +/* BD71837_REG_LDO6_VOLT bits */
> +#define LDO6_MASK 0x0F
> +
> +/* BD71837_REG_LDO7_VOLT bits */
> +#define LDO7_MASK 0x0F
> +
> +/* Register write induced reset settings */
> +
> +/*
> + * Even though the bit zero is not SWRESET type we still want to write zero
> + * to it when changing type. Bit zero is 'SWRESET' trigger bit and if we
> + * write 1 to it we will trigger the action. So always write 0 to it when
> + * changning SWRESET action - no matter what we read from it.
> + */
> +#define BD71837_SWRESET_TYPE_MASK 7
> +#define BD71837_SWRESET_TYPE_DISABLED 0
> +#define BD71837_SWRESET_TYPE_COLD 4
> +#define BD71837_SWRESET_TYPE_WARM 6
> +
> +#define BD71837_SWRESET_RESET_MASK 1
> +#define BD71837_SWRESET_RESET 1
> +
> +/* Poweroff state transition conditions */
> +
> +#define BD718XX_ON_REQ_POWEROFF_MASK 1
> +#define BD718XX_SWRESET_POWEROFF_MASK 2
> +#define BD718XX_WDOG_POWEROFF_MASK 4
> +#define BD718XX_KEY_L_POWEROFF_MASK 8
> +
> +#define BD718XX_POWOFF_TO_SNVS 0
> +#define BD718XX_POWOFF_TO_RDY 0xF
> +
> +#define BD718XX_POWOFF_TIME_MASK 0xF0
> +enum {
> + BD718XX_POWOFF_TIME_5MS = 0,
> + BD718XX_POWOFF_TIME_10MS,
> + BD718XX_POWOFF_TIME_15MS,
> + BD718XX_POWOFF_TIME_20MS,
> + BD718XX_POWOFF_TIME_25MS,
> + BD718XX_POWOFF_TIME_30MS,
> + BD718XX_POWOFF_TIME_35MS,
> + BD718XX_POWOFF_TIME_40MS,
> + BD718XX_POWOFF_TIME_45MS,
> + BD718XX_POWOFF_TIME_50MS,
> + BD718XX_POWOFF_TIME_75MS,
> + BD718XX_POWOFF_TIME_100MS,
> + BD718XX_POWOFF_TIME_250MS,
> + BD718XX_POWOFF_TIME_500MS,
> + BD718XX_POWOFF_TIME_750MS,
> + BD718XX_POWOFF_TIME_1500MS
> +};
> +
> +/* Poweron sequence state transition conditions */
> +#define BD718XX_RDY_TO_SNVS_MASK 0xF
> +#define BD718XX_SNVS_TO_RUN_MASK 0xF0
> +
> +#define BD718XX_PWR_TRIG_KEY_L 1
> +#define BD718XX_PWR_TRIG_KEY_S 2
> +#define BD718XX_PWR_TRIG_PMIC_ON 4
> +#define BD718XX_PWR_TRIG_VSYS_UVLO 8
> +#define BD718XX_RDY_TO_SNVS_SIFT 0
> +#define BD718XX_SNVS_TO_RUN_SIFT 4
> +
> +#define BD718XX_PWRBTN_PRESS_DURATION_MASK 0xF
> +
> +/* Timeout value for detecting short press */
> +enum {
> + BD718XX_PWRBTN_SHORT_PRESS_10MS = 0,
> + BD718XX_PWRBTN_SHORT_PRESS_500MS,
> + BD718XX_PWRBTN_SHORT_PRESS_1000MS,
> + BD718XX_PWRBTN_SHORT_PRESS_1500MS,
> + BD718XX_PWRBTN_SHORT_PRESS_2000MS,
> + BD718XX_PWRBTN_SHORT_PRESS_2500MS,
> + BD718XX_PWRBTN_SHORT_PRESS_3000MS,
> + BD718XX_PWRBTN_SHORT_PRESS_3500MS,
> + BD718XX_PWRBTN_SHORT_PRESS_4000MS,
> + BD718XX_PWRBTN_SHORT_PRESS_4500MS,
> + BD718XX_PWRBTN_SHORT_PRESS_5000MS,
> + BD718XX_PWRBTN_SHORT_PRESS_5500MS,
> + BD718XX_PWRBTN_SHORT_PRESS_6000MS,
> + BD718XX_PWRBTN_SHORT_PRESS_6500MS,
> + BD718XX_PWRBTN_SHORT_PRESS_7000MS,
> + BD718XX_PWRBTN_SHORT_PRESS_7500MS
> +};
> +
> +/* Timeout value for detecting LONG press */
> +enum {
> + BD718XX_PWRBTN_LONG_PRESS_10MS = 0,
> + BD718XX_PWRBTN_LONG_PRESS_1S,
> + BD718XX_PWRBTN_LONG_PRESS_2S,
> + BD718XX_PWRBTN_LONG_PRESS_3S,
> + BD718XX_PWRBTN_LONG_PRESS_4S,
> + BD718XX_PWRBTN_LONG_PRESS_5S,
> + BD718XX_PWRBTN_LONG_PRESS_6S,
> + BD718XX_PWRBTN_LONG_PRESS_7S,
> + BD718XX_PWRBTN_LONG_PRESS_8S,
> + BD718XX_PWRBTN_LONG_PRESS_9S,
> + BD718XX_PWRBTN_LONG_PRESS_10S,
> + BD718XX_PWRBTN_LONG_PRESS_11S,
> + BD718XX_PWRBTN_LONG_PRESS_12S,
> + BD718XX_PWRBTN_LONG_PRESS_13S,
> + BD718XX_PWRBTN_LONG_PRESS_14S,
> + BD718XX_PWRBTN_LONG_PRESS_15S
> +};
> +
> +struct bd71837_pmic;
> +struct bd71837_clk;
> +
> +struct bd71837 {
> + struct device *dev;
> + struct i2c_client *i2c_client;
Are these both being used?
If you save one, you tend not to need the other.
> + struct regmap *regmap;
> + unsigned long int id;
> +
> + int chip_irq;
> + struct regmap_irq_chip_data *irq_data;
> +
> + struct bd71837_pmic *pmic;
> + struct bd71837_clk *clk;
> +};
> +
> +#endif /* __LINUX_MFD_BD71837_H__ */
--
Lee Jones [李琼斯]
Linaro Services Technical Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog
^ permalink raw reply
* Re: [PATCH v10 2/2] mfd: bd71837: Devicetree bindings for ROHM BD71837 PMIC
From: Lee Jones @ 2018-07-12 12:32 UTC (permalink / raw)
To: Matti Vaittinen
Cc: mturquette, robh+dt, sboyd, mark.rutland, lgirdwood, broonie,
mazziesaccount, arnd, dmitry.torokhov, sre, chenjh,
andrew.smirnov, linus.walleij, kstewart, heiko, gregkh, eballetbo,
linux-clk, devicetree, linux-kernel, linux-input, mikko.mutanen,
heikki.haikola
In-Reply-To: <8ef84806b7152a4da2bffa0456052e98f4c6e1c6.1530800707.git.matti.vaittinen@fi.rohmeurope.com>
On Thu, 05 Jul 2018, Matti Vaittinen wrote:
> Document devicetree bindings for ROHM BD71837 PMIC MFD.
>
> Signed-off-by: Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>
> ---
> .../devicetree/bindings/mfd/rohm,bd71837-pmic.txt | 62 ++++++++++++++++++++++
> 1 file changed, 62 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/mfd/rohm,bd71837-pmic.txt
For my own reference:
Acked-for-MFD-by: Lee Jones <lee.jones@linaro.org>
--
Lee Jones [李琼斯]
Linaro Services Technical Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog
^ permalink raw reply
* Re: [kbuild-all] [PATCH v6 2/4] resource: Use list_head to link sibling resource
From: Baoquan He @ 2018-07-10 3:10 UTC (permalink / raw)
To: Ye Xiaolong
Cc: nicolas.pitre-QSEj5FYQhm4dnm+yROfE0A, brijesh.singh-5C7GfCeVMHo,
devicetree-u79uwXL29TY76Z2rM5mHXA, airlied-cv59FeDIM0c,
linux-pci-u79uwXL29TY76Z2rM5mHXA,
richard.weiyang-Re5JQEeQqe8AvxtiuMwx3w,
jcmvbkbc-Re5JQEeQqe8AvxtiuMwx3w,
baiyaowei-0p4V/sDNsUmm0O/7XYngnFaTQe2KTcn/,
frowand.list-Re5JQEeQqe8AvxtiuMwx3w,
lorenzo.pieralisi-5wv7dgnIgG8, sthemmin-0li6OtcxBFHby3iVrkZq2A,
kbuild test robot, linux-nvdimm-hn68Rpc1hR1g9hUCZPvPmw,
patrik.r.jakobsson-Re5JQEeQqe8AvxtiuMwx3w,
andy.shevchenko-Re5JQEeQqe8AvxtiuMwx3w,
linux-input-u79uwXL29TY76Z2rM5mHXA,
gustavo-THi1TnShQwVAfugRpC6u6w, bp-l3A5Bk7waGM,
dyoung-H+wXaHxf7aLQT0dZR+AlfA, kbuild-all-JC7UmRfGjtg,
thomas.lendacky-5C7GfCeVMHo, haiyangz-0li6OtcxBFHby3iVrkZq2A,
maarten.lankhorst-VuQAYsv1563Yd54FQh9/CA,
josh-iaAMLnmF4UmaiuxdJuQwMA, jglisse-H+wXaHxf7aLQT0dZR+AlfA,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A, seanpaul-F7+t8E8rja9g9hUCZPvPmw,
bhelgaas-hpIqsD4AKlfQT0dZR+AlfA, tglx-hfZtesqFncYOwBW4kG4KsQ,
yinghai-DgEjT+Ai2ygdnm+yROfE0A,
jonathan.derrick-ral2JQCrhuEAvxtiuMwx3w,
chris-YvXeqwSYzG2sTnJN9+BGXg, monstr-pSz03upnqPeHXe+LvDLADg,
linux-parisc-u79uwXL29TY76Z2rM5mHXA,
gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
dmitry.torokhov-Re5JQEeQqe8AvxtiuMwx3w, kexec
In-Reply-To: <20180710005927.GG10005@yexl-desktop>
On 07/10/18 at 08:59am, Ye Xiaolong wrote:
> Hi,
>
> On 07/08, Baoquan He wrote:
> >Hi,
> >
> >On 07/05/18 at 01:00am, kbuild test robot wrote:
> >> Hi Baoquan,
> >>
> >> I love your patch! Yet something to improve:
> >>
> >> [auto build test ERROR on linus/master]
> >> [also build test ERROR on v4.18-rc3 next-20180704]
> >> [if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
> >
> >Thanks for telling.
> >
> >I cloned 0day-ci/linut to my local pc.
> >https://github.com/0day-ci/linux.git
> >
> >However, I didn't find below branch. And tried to open it in web
> >broswer, also failed.
> >
>
> Sorry for the inconvenience, 0day bot didn't push the branch to github successfully,
> Just push it manually, you can have a try again.
Thanks, Xiaolong, I have applied them on top of linux-next/master, and
copy the config file attached, and run the command to reproduce as
suggested. Now I have fixed all those issues reported, will repost.
>
> >
> >> url: https://github.com/0day-ci/linux/commits/Baoquan-He/resource-Use-list_head-to-link-sibling-resource/20180704-121402
> >> config: mips-rb532_defconfig (attached as .config)
> >> compiler: mipsel-linux-gnu-gcc (Debian 7.2.0-11) 7.2.0
> >> reproduce:
> >> wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
> >> chmod +x ~/bin/make.cross
> >> # save the attached .config to linux build tree
> >> GCC_VERSION=7.2.0 make.cross ARCH=mips
> >
> >I did find a old one which is for the old version 5 post.
> >
> >[bhe@linux]$ git remote -v
> >0day-ci https://github.com/0day-ci/linux.git (fetch)
> >0day-ci https://github.com/0day-ci/linux.git (push)
> >[bhe@dhcp-128-28 linux]$ git branch -a| grep Baoquan| grep resource
> > remotes/0day-ci/Baoquan-He/resource-Use-list_head-to-link-sibling-resource/20180612-113600
> >
> >Could you help have a look at this?
> >
> >Thanks
> >Baoquan
> >
> >>
> >> All error/warnings (new ones prefixed by >>):
> >>
> >> >> arch/mips/pci/pci-rc32434.c:57:11: error: initialization from incompatible pointer type [-Werror=incompatible-pointer-types]
> >> .child = &rc32434_res_pci_mem2
> >> ^
> >> arch/mips/pci/pci-rc32434.c:57:11: note: (near initialization for 'rc32434_res_pci_mem1.child.next')
> >> >> arch/mips/pci/pci-rc32434.c:51:47: warning: missing braces around initializer [-Wmissing-braces]
> >> static struct resource rc32434_res_pci_mem1 = {
> >> ^
> >> arch/mips/pci/pci-rc32434.c:60:47: warning: missing braces around initializer [-Wmissing-braces]
> >> static struct resource rc32434_res_pci_mem2 = {
> >> ^
> >> cc1: some warnings being treated as errors
> >>
> >> vim +57 arch/mips/pci/pci-rc32434.c
> >>
> >> 73b4390f Ralf Baechle 2008-07-16 50
> >> 73b4390f Ralf Baechle 2008-07-16 @51 static struct resource rc32434_res_pci_mem1 = {
> >> 73b4390f Ralf Baechle 2008-07-16 52 .name = "PCI MEM1",
> >> 73b4390f Ralf Baechle 2008-07-16 53 .start = 0x50000000,
> >> 73b4390f Ralf Baechle 2008-07-16 54 .end = 0x5FFFFFFF,
> >> 73b4390f Ralf Baechle 2008-07-16 55 .flags = IORESOURCE_MEM,
> >> 73b4390f Ralf Baechle 2008-07-16 56 .sibling = NULL,
> >> 73b4390f Ralf Baechle 2008-07-16 @57 .child = &rc32434_res_pci_mem2
> >> 73b4390f Ralf Baechle 2008-07-16 58 };
> >> 73b4390f Ralf Baechle 2008-07-16 59
> >>
> >> :::::: The code at line 57 was first introduced by commit
> >> :::::: 73b4390fb23456964201abda79f1210fe337d01a [MIPS] Routerboard 532: Support for base system
> >>
> >> :::::: TO: Ralf Baechle <ralf-6z/3iImG2C8G8FEW9MqTrA@public.gmane.org>
> >> :::::: CC: Ralf Baechle <ralf-6z/3iImG2C8G8FEW9MqTrA@public.gmane.org>
> >>
> >> ---
> >> 0-DAY kernel test infrastructure Open Source Technology Center
> >> https://lists.01.org/pipermail/kbuild-all Intel Corporation
> >
> >
> >_______________________________________________
> >kbuild-all mailing list
> >kbuild-all-hn68Rpc1hR1g9hUCZPvPmw@public.gmane.org
> >https://lists.01.org/mailman/listinfo/kbuild-all
^ permalink raw reply
* Re: [PATCH 0/5] m68k: IO Fixes and Cleanups
From: Greg Ungerer @ 2018-07-10 1:48 UTC (permalink / raw)
To: Geert Uytterhoeven, Dmitry Torokhov, Helge Deller
Cc: linux-m68k, netdev, linux-input, linux-kernel
In-Reply-To: <20180709093040.23597-1-geert@linux-m68k.org>
Hi Geert,
On 09/07/18 19:30, Geert Uytterhoeven wrote:
> Hi all,
>
> This patch series contains fixes and cleanups for I/O accessors on m68k
> platforms (with MMU).
>
> The first patch contains small fixes without any dependencies.
> Patches 2 and 3 make small adjustments to drivers that are dependencies
> for further cleanup.
> Patch 4 and 5 complete the cleanup.
>
> Changes compared to v1:
> - Move ARCH_HAS_IOREMAP_WT to fix "ioremap_wt redefined" warnings with
> m5475evb defconfig,
> - Add Acked-by.
>
> Given the dependencies, I think it's easiest if the respective
> maintainers would provide their Acked-by, so all patches can go in
> through the m68k tree.
Retested on ColdFire 5475, looks good.
For the whole series:
Acked-by: Greg Ungerer <gerg@linux-m68k.org>
Regards
Greg
> Thanks!
>
> Geert Uytterhoeven (5):
> m68k/io: Add missing ioremap define guards, fix typo
> net: mac8390: Use standard memcpy_{from,to}io()
> Input: hilkbd - Add casts to HP9000/300 I/O accessors
> m68k/io: Move mem*io define guards to <asm/kmap.h>
> m68k/io: Switch mmu variant to <asm-generic/io.h>
>
> arch/m68k/include/asm/io.h | 7 +++++
> arch/m68k/include/asm/io_mm.h | 42 +++--------------------------
> arch/m68k/include/asm/io_no.h | 12 ---------
> arch/m68k/include/asm/kmap.h | 9 ++++++-
> drivers/input/keyboard/hilkbd.c | 4 +--
> drivers/net/ethernet/8390/mac8390.c | 20 +++++++-------
> 6 files changed, 30 insertions(+), 64 deletions(-)
>
^ permalink raw reply
* Re: [kbuild-all] [PATCH v6 2/4] resource: Use list_head to link sibling resource
From: Ye Xiaolong @ 2018-07-10 0:59 UTC (permalink / raw)
To: Baoquan He
Cc: nicolas.pitre-QSEj5FYQhm4dnm+yROfE0A, brijesh.singh-5C7GfCeVMHo,
devicetree-u79uwXL29TY76Z2rM5mHXA, airlied-cv59FeDIM0c,
linux-pci-u79uwXL29TY76Z2rM5mHXA,
richard.weiyang-Re5JQEeQqe8AvxtiuMwx3w,
jcmvbkbc-Re5JQEeQqe8AvxtiuMwx3w,
baiyaowei-0p4V/sDNsUmm0O/7XYngnFaTQe2KTcn/,
frowand.list-Re5JQEeQqe8AvxtiuMwx3w,
lorenzo.pieralisi-5wv7dgnIgG8, sthemmin-0li6OtcxBFHby3iVrkZq2A,
kbuild test robot, linux-nvdimm-hn68Rpc1hR1g9hUCZPvPmw,
patrik.r.jakobsson-Re5JQEeQqe8AvxtiuMwx3w,
andy.shevchenko-Re5JQEeQqe8AvxtiuMwx3w,
linux-input-u79uwXL29TY76Z2rM5mHXA,
gustavo-THi1TnShQwVAfugRpC6u6w, bp-l3A5Bk7waGM,
dyoung-H+wXaHxf7aLQT0dZR+AlfA, kbuild-all-JC7UmRfGjtg,
thomas.lendacky-5C7GfCeVMHo, haiyangz-0li6OtcxBFHby3iVrkZq2A,
maarten.lankhorst-VuQAYsv1563Yd54FQh9/CA,
josh-iaAMLnmF4UmaiuxdJuQwMA, jglisse-H+wXaHxf7aLQT0dZR+AlfA,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A, seanpaul-F7+t8E8rja9g9hUCZPvPmw,
bhelgaas-hpIqsD4AKlfQT0dZR+AlfA, tglx-hfZtesqFncYOwBW4kG4KsQ,
yinghai-DgEjT+Ai2ygdnm+yROfE0A,
jonathan.derrick-ral2JQCrhuEAvxtiuMwx3w,
chris-YvXeqwSYzG2sTnJN9+BGXg, monstr-pSz03upnqPeHXe+LvDLADg,
linux-parisc-u79uwXL29TY76Z2rM5mHXA,
gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
dmitry.torokhov-Re5JQEeQqe8AvxtiuMwx3w, kexec
In-Reply-To: <20180708025946.GI3047@MiWiFi-R3L-srv>
Hi,
On 07/08, Baoquan He wrote:
>Hi,
>
>On 07/05/18 at 01:00am, kbuild test robot wrote:
>> Hi Baoquan,
>>
>> I love your patch! Yet something to improve:
>>
>> [auto build test ERROR on linus/master]
>> [also build test ERROR on v4.18-rc3 next-20180704]
>> [if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
>
>Thanks for telling.
>
>I cloned 0day-ci/linut to my local pc.
>https://github.com/0day-ci/linux.git
>
>However, I didn't find below branch. And tried to open it in web
>broswer, also failed.
>
Sorry for the inconvenience, 0day bot didn't push the branch to github successfully,
Just push it manually, you can have a try again.
Thanks,
Xiaolong
>
>> url: https://github.com/0day-ci/linux/commits/Baoquan-He/resource-Use-list_head-to-link-sibling-resource/20180704-121402
>> config: mips-rb532_defconfig (attached as .config)
>> compiler: mipsel-linux-gnu-gcc (Debian 7.2.0-11) 7.2.0
>> reproduce:
>> wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
>> chmod +x ~/bin/make.cross
>> # save the attached .config to linux build tree
>> GCC_VERSION=7.2.0 make.cross ARCH=mips
>
>I did find a old one which is for the old version 5 post.
>
>[bhe@linux]$ git remote -v
>0day-ci https://github.com/0day-ci/linux.git (fetch)
>0day-ci https://github.com/0day-ci/linux.git (push)
>[bhe@dhcp-128-28 linux]$ git branch -a| grep Baoquan| grep resource
> remotes/0day-ci/Baoquan-He/resource-Use-list_head-to-link-sibling-resource/20180612-113600
>
>Could you help have a look at this?
>
>Thanks
>Baoquan
>
>>
>> All error/warnings (new ones prefixed by >>):
>>
>> >> arch/mips/pci/pci-rc32434.c:57:11: error: initialization from incompatible pointer type [-Werror=incompatible-pointer-types]
>> .child = &rc32434_res_pci_mem2
>> ^
>> arch/mips/pci/pci-rc32434.c:57:11: note: (near initialization for 'rc32434_res_pci_mem1.child.next')
>> >> arch/mips/pci/pci-rc32434.c:51:47: warning: missing braces around initializer [-Wmissing-braces]
>> static struct resource rc32434_res_pci_mem1 = {
>> ^
>> arch/mips/pci/pci-rc32434.c:60:47: warning: missing braces around initializer [-Wmissing-braces]
>> static struct resource rc32434_res_pci_mem2 = {
>> ^
>> cc1: some warnings being treated as errors
>>
>> vim +57 arch/mips/pci/pci-rc32434.c
>>
>> 73b4390f Ralf Baechle 2008-07-16 50
>> 73b4390f Ralf Baechle 2008-07-16 @51 static struct resource rc32434_res_pci_mem1 = {
>> 73b4390f Ralf Baechle 2008-07-16 52 .name = "PCI MEM1",
>> 73b4390f Ralf Baechle 2008-07-16 53 .start = 0x50000000,
>> 73b4390f Ralf Baechle 2008-07-16 54 .end = 0x5FFFFFFF,
>> 73b4390f Ralf Baechle 2008-07-16 55 .flags = IORESOURCE_MEM,
>> 73b4390f Ralf Baechle 2008-07-16 56 .sibling = NULL,
>> 73b4390f Ralf Baechle 2008-07-16 @57 .child = &rc32434_res_pci_mem2
>> 73b4390f Ralf Baechle 2008-07-16 58 };
>> 73b4390f Ralf Baechle 2008-07-16 59
>>
>> :::::: The code at line 57 was first introduced by commit
>> :::::: 73b4390fb23456964201abda79f1210fe337d01a [MIPS] Routerboard 532: Support for base system
>>
>> :::::: TO: Ralf Baechle <ralf-6z/3iImG2C8G8FEW9MqTrA@public.gmane.org>
>> :::::: CC: Ralf Baechle <ralf-6z/3iImG2C8G8FEW9MqTrA@public.gmane.org>
>>
>> ---
>> 0-DAY kernel test infrastructure Open Source Technology Center
>> https://lists.01.org/pipermail/kbuild-all Intel Corporation
>
>
>_______________________________________________
>kbuild-all mailing list
>kbuild-all-hn68Rpc1hR1g9hUCZPvPmw@public.gmane.org
>https://lists.01.org/mailman/listinfo/kbuild-all
^ permalink raw reply
* Re: [PATCH 2/8] mfd: stpmu1: add stpmu1 pmic driver
From: Enric Balletbo Serra @ 2018-07-09 22:38 UTC (permalink / raw)
To: p.paillet
Cc: Dmitry Torokhov, Rob Herring, Mark Rutland, Lee Jones,
Liam Girdwood, Mark Brown, wim, Guenter Roeck, linux-input,
devicetree@vger.kernel.org, linux-kernel, linux-watchdog,
benjamin.gaignard
In-Reply-To: <1530803657-17684-3-git-send-email-p.paillet@st.com>
Hi Pascal,
Thanks for the patch some comments below.
Missatge de Pascal PAILLET-LME <p.paillet@st.com> del dia dj., 5 de
jul. 2018 a les 17:17:
>
> From: pascal paillet <p.paillet@st.com>
>
> stpmu1 is a pmic from STMicroelectronics. The stpmu1 integrates 10
> regulators and 3 switches with various capabilities.
>
> Signed-off-by: pascal paillet <p.paillet@st.com>
> ---
> drivers/mfd/Kconfig | 14 ++
> drivers/mfd/Makefile | 1 +
> drivers/mfd/stpmu1.c | 490 ++++++++++++++++++++++++++++++++++++
> include/dt-bindings/mfd/st,stpmu1.h | 46 ++++
> include/linux/mfd/stpmu1.h | 220 ++++++++++++++++
> 5 files changed, 771 insertions(+)
> create mode 100644 drivers/mfd/stpmu1.c
> create mode 100644 include/dt-bindings/mfd/st,stpmu1.h
> create mode 100644 include/linux/mfd/stpmu1.h
>
> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> index b860eb5..e15140b 100644
> --- a/drivers/mfd/Kconfig
> +++ b/drivers/mfd/Kconfig
> @@ -1812,6 +1812,20 @@ config MFD_STM32_TIMERS
> for PWM and IIO Timer. This driver allow to share the
> registers between the others drivers.
>
> +config MFD_STPMU1
> + tristate "Support for STPMU1 PMIC"
> + depends on (I2C=y && OF)
> + select REGMAP_I2C
> + select REGMAP_IRQ
> + select MFD_CORE
> + help
> + Support for ST Microelectronics STPMU1 PMIC. Stpmu1 mfd driver is
> + the core driver for stpmu1 component that mainly handles interrupts.
> +
> + To compile this driver as a module, choose M here: the
> + module will be called stpmu1.
> +
> +
Extra line not needed.
> menu "Multimedia Capabilities Port drivers"
> depends on ARCH_SA1100
>
> diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
> index e9fd20d..f1c4be1 100644
> --- a/drivers/mfd/Makefile
> +++ b/drivers/mfd/Makefile
> @@ -220,6 +220,7 @@ obj-$(CONFIG_INTEL_SOC_PMIC_CHTDC_TI) += intel_soc_pmic_chtdc_ti.o
> obj-$(CONFIG_MFD_MT6397) += mt6397-core.o
>
> obj-$(CONFIG_MFD_ALTERA_A10SR) += altera-a10sr.o
> +obj-$(CONFIG_MFD_STPMU1) += stpmu1.o
> obj-$(CONFIG_MFD_SUN4I_GPADC) += sun4i-gpadc.o
>
> obj-$(CONFIG_MFD_STM32_LPTIMER) += stm32-lptimer.o
> diff --git a/drivers/mfd/stpmu1.c b/drivers/mfd/stpmu1.c
> new file mode 100644
> index 0000000..a284a3e
> --- /dev/null
> +++ b/drivers/mfd/stpmu1.c
> @@ -0,0 +1,490 @@
> +// SPDX-License-Identifier: GPL-2.0
There is a license mismatch between SPDX and MODULE_LICENSE. Or SPDX
identifier should be GPL-2.0-or-later or MODULE_LICENSE should be
("GPL v2")
See https://elixir.bootlin.com/linux/latest/source/include/linux/module.h#L175
> +/*
> + * Copyright (C) STMicroelectronics 2018 - All Rights Reserved
> + * Author: Philippe Peurichard <philippe.peurichard@st.com>,
> + * Pascal Paillet <p.paillet@st.com> for STMicroelectronics.
> + */
> +
I think that Lee, like Linus, prefers the C++ style here
> +#include <linux/err.h>
That this include is not needed.
> +#include <linux/i2c.h>
> +#include <linux/interrupt.h>
> +#include <linux/mfd/core.h>
> +#include <linux/mfd/stpmu1.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_irq.h>
> +#include <linux/of_platform.h>
> +#include <linux/platform_device.h>
ditto
> +#include <linux/pm_runtime.h>
ditto
> +#include <linux/pm_wakeirq.h>
> +#include <linux/regmap.h>
> +#include <dt-bindings/mfd/st,stpmu1.h>
> +
[snip]
> +
> +static int stpmu1_configure_from_dt(struct stpmu1_dev *pmic_dev)
> +{
> + struct device_node *np = pmic_dev->np;
> + u32 reg = 0;
You don't need to initialize reg to 0, anyway will be overwriten.
> + int ret = 0;
You don't need to initialize ret to 0, anyway will be overwritten.
> + int irq;
> +
> + irq = of_irq_get(np, 0);
> + if (irq <= 0) {
> + dev_err(pmic_dev->dev,
> + "Failed to get irq config: %d\n", irq);
This can be in one line.
> + return irq ? irq : -ENODEV;
nit: return irq ?: -ENODEV;
> + }
> + pmic_dev->irq = irq;
> +
> + irq = of_irq_get(np, 1);
> + if (irq <= 0) {
> + dev_err(pmic_dev->dev,
> + "Failed to get irq_wake config: %d\n", irq);
> + return irq ? irq : -ENODEV;
nit: return irq ?: -ENODEV;
> + }
> + pmic_dev->irq_wake = irq;
> +
> + device_init_wakeup(pmic_dev->dev, true);
> + ret = dev_pm_set_dedicated_wake_irq(pmic_dev->dev, pmic_dev->irq_wake);
> + if (ret)
> + dev_warn(pmic_dev->dev, "failed to set up wakeup irq");
> +
> + if (!of_property_read_u32(np, "st,main_control_register", ®)) {
> + ret = regmap_update_bits(pmic_dev->regmap,
> + SWOFF_PWRCTRL_CR,
> + PWRCTRL_POLARITY_HIGH |
> + PWRCTRL_PIN_VALID |
> + RESTART_REQUEST_ENABLED,
> + reg);
> + if (ret) {
> + dev_err(pmic_dev->dev,
> + "Failed to update main control register: %d\n",
> + ret);
> + return ret;
> + }
> + }
> +
> + if (!of_property_read_u32(np, "st,pads_pull_register", ®)) {
> + ret = regmap_update_bits(pmic_dev->regmap,
> + PADS_PULL_CR,
> + WAKEUP_DETECTOR_DISABLED |
> + PWRCTRL_PD_ACTIVE |
> + PWRCTRL_PU_ACTIVE |
> + WAKEUP_PD_ACTIVE,
> + reg);
> + if (ret) {
> + dev_err(pmic_dev->dev,
> + "Failed to update pads control register: %d\n",
> + ret);
> + return ret;
> + }
> + }
> +
> + if (!of_property_read_u32(np, "st,vin_control_register", ®)) {
> + ret = regmap_update_bits(pmic_dev->regmap,
> + VBUS_DET_VIN_CR,
> + VINLOW_CTRL_REG_MASK,
> + reg);
> + if (ret) {
> + dev_err(pmic_dev->dev,
> + "Failed to update vin control register: %d\n",
> + ret);
> + return ret;
> + }
> + }
> +
> + if (!of_property_read_u32(np, "st,usb_control_register", ®)) {
> + ret = regmap_update_bits(pmic_dev->regmap, BST_SW_CR,
> + BOOST_OVP_DISABLED |
> + VBUS_OTG_DETECTION_DISABLED |
> + SW_OUT_DISCHARGE |
> + VBUS_OTG_DISCHARGE |
> + OCP_LIMIT_HIGH,
> + reg);
> + if (ret) {
> + dev_err(pmic_dev->dev,
> + "Failed to update usb control register: %d\n",
> + ret);
> + return ret;
> + }
> + }
> +
> + return 0;
> +}
> +
> +int stpmu1_device_init(struct stpmu1_dev *pmic_dev)
> +{
> + int ret;
> + unsigned int val;
> +
> + pmic_dev->regmap =
> + devm_regmap_init_i2c(pmic_dev->i2c, &stpmu1_regmap_config);
> +
> + if (IS_ERR(pmic_dev->regmap)) {
> + ret = PTR_ERR(pmic_dev->regmap);
You can remove this ...
> + dev_err(pmic_dev->dev, "Failed to allocate register map: %d\n",
> + ret);
> + return ret;
and just return PTR_ERR(pmic_dev->regmap);
> + }
> +
> + ret = stpmu1_configure_from_dt(pmic_dev);
> + if (ret < 0) {
Is ret >0 return valid? If not, perhaps "if (ret)" would be better.
> + dev_err(pmic_dev->dev,
> + "Unable to configure PMIC from Device Tree: %d\n", ret);
> + return ret;
> + }
> +
> + /* Read Version ID */
> + ret = regmap_read(pmic_dev->regmap, VERSION_SR, &val);
> + if (ret < 0) {
Is ret >0 return valid? If not, perhaps "if (ret)" would be better.
> + dev_err(pmic_dev->dev, "Unable to read pmic version\n");
> + return ret;
> + }
> + dev_dbg(pmic_dev->dev, "PMIC Chip Version: 0x%x\n", val);
nit: Maybe that should be dev_info instead of dev_dbg?
> +
> + /* Initialize PMIC IRQ Chip & IRQ domains associated */
> + ret = devm_regmap_add_irq_chip(pmic_dev->dev, pmic_dev->regmap,
> + pmic_dev->irq,
> + IRQF_ONESHOT | IRQF_SHARED,
> + 0, &stpmu1_regmap_irq_chip,
> + &pmic_dev->irq_data);
> + if (ret < 0) {
Is ret >0 return valid? If not, perhaps "if (ret)" would be better.
> + dev_err(pmic_dev->dev, "IRQ Chip registration failed: %d\n",
> + ret);
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> +static const struct of_device_id stpmu1_dt_match[] = {
> + {.compatible = "st,stpmu1"},
> + {},
I'd rewrite this as
+ { .compatible = "st,stpmu1" },
+ { }
Space after/before brackets and no comma at the end. The sentinel
indicates the last item on structure/arrays so no need to add a comma
at the end.
> +};
> +
Remove this line
> +MODULE_DEVICE_TABLE(of, stpmu1_dt_match);
> +
> +static int stpmu1_remove(struct i2c_client *i2c)
> +{
> + struct stpmu1_dev *pmic_dev = i2c_get_clientdata(i2c);
> +
> + of_platform_depopulate(pmic_dev->dev);
> +
> + return 0;
> +}
You can remove this function, see below ...
> +
> +static int stpmu1_probe(struct i2c_client *i2c,
> + const struct i2c_device_id *id)
> +{
> + struct stpmu1_dev *pmic;
> + struct device *dev = &i2c->dev;
> + int ret = 0;
No need to initialize to 0 if ...
> +
> + pmic = devm_kzalloc(dev, sizeof(struct stpmu1_dev), GFP_KERNEL);
> + if (!pmic)
> + return -ENOMEM;
> +
> + pmic->np = dev->of_node;
> +
> + dev_set_drvdata(dev, pmic);
> + pmic->dev = dev;
> + pmic->i2c = i2c;
> +
> + ret = stpmu1_device_init(pmic);
> + if (ret < 0)
Is ret >0 return valid? If not, perhaps "if (ret)" would be better.
> + goto err;
return ret;
> +
> + ret = of_platform_populate(pmic->np, NULL, NULL, pmic->dev);
> +
ret = devm_of_platform_populate(pmic->dev);
or even better
return devm_of_platform_populate(pmic->dev);
And remove the stpmu1_remove function.
> + dev_dbg(dev, "stpmu1 driver probed\n");
That message looks redundant to me. I'd remove it.
> +err:
And you can remove this label.
> + return ret;
And this
> +}
> +
> +static const struct i2c_device_id stpmu1_id[] = {
> + {"stpmu1", 0},
> + {}
> +};
> +
> +MODULE_DEVICE_TABLE(i2c, stpmu1_id);
The above code shouldn't be needed anymore for DT-only devices. See
da10c06a044b ("i2c: Make I2C ID tables non-mandatory for DT'ed
devices")
> +
> +#ifdef CONFIG_PM_SLEEP
> +static int stpmu1_suspend(struct device *dev)
> +{
> + struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
> + struct stpmu1_dev *pmic_dev = i2c_get_clientdata(i2c);
> +
> + if (device_may_wakeup(dev))
> + enable_irq_wake(pmic_dev->irq_wake);
> +
> + disable_irq(pmic_dev->irq);
> + return 0;
> +}
> +
> +static int stpmu1_resume(struct device *dev)
> +{
> + struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
> + struct stpmu1_dev *pmic_dev = i2c_get_clientdata(i2c);
> +
> + regcache_sync(pmic_dev->regmap);
Maybe you would like to check for an error here.
> +
> + if (device_may_wakeup(dev))
> + disable_irq_wake(pmic_dev->irq_wake);
> +
> + enable_irq(pmic_dev->irq);
> + return 0;
> +}
> +#endif
> +
> +static SIMPLE_DEV_PM_OPS(stpmu1_pm, stpmu1_suspend, stpmu1_resume);
> +
> +static struct i2c_driver stpmu1_driver = {
> + .driver = {
> + .name = "stpmu1",
> + .owner = THIS_MODULE,
This is not needed, the core does it for you.
> + .pm = &stpmu1_pm,
> + .of_match_table = of_match_ptr(stpmu1_dt_match),
It is a DT-only device so no need the of_match_ptr.
> + },
> + .probe = stpmu1_probe,
> + .remove = stpmu1_remove,
Now you can remove this
> + .id_table = stpmu1_id,
And you can remove this also.
> +};
> +
> +module_i2c_driver(stpmu1_driver);
> +
> +MODULE_DESCRIPTION("STPMU1 PMIC I2C Client");
nit: PMIC I2C Client sounds weird to me, "STPMU1 PMIC driver" ? Note
that I am not english native so I could be wrong.
> +MODULE_AUTHOR("<philippe.peurichard@st.com>");
Use "Name <email>" or just "Name"
> +MODULE_LICENSE("GPL");
As I told you there is a license mismatch with SPDX.
[snip]
Best regards,
Enric
^ permalink raw reply
* Re: [PATCH] HID: hiddev: fix potential Spectre v1
From: Jiri Kosina @ 2018-07-09 12:31 UTC (permalink / raw)
To: Gustavo A. R. Silva
Cc: Benjamin Tissoires, linux-usb, linux-input, linux-kernel
In-Reply-To: <20180629220844.GA13823@embeddedor.com>
On Fri, 29 Jun 2018, Gustavo A. R. Silva wrote:
> uref->field_index, uref->usage_index, finfo.field_index and
> cinfo.index can be indirectly controlled by user-space, hence
> leading to a potential exploitation of the Spectre variant 1
> vulnerability.
>
> This issue was detected with the help of Smatch:
Applied, thanks Gustavo.
--
Jiri Kosina
SUSE Labs
^ permalink raw reply
* Re: [PATCH] i2c-hid: Fix "incomplete report" noise
From: Jiri Kosina @ 2018-07-09 12:29 UTC (permalink / raw)
To: Jason Andryuk
Cc: linux-kernel, john-s-84, stable, Benjamin Tissoires, linux-input
In-Reply-To: <20180622162549.9563-1-jandryuk@gmail.com>
On Fri, 22 Jun 2018, Jason Andryuk wrote:
> Commit ac75a041048b ("HID: i2c-hid: fix size check and type usage")
> started writing messages when the ret_size is <= 2 from i2c_master_recv.
> However, my device i2c-DLL07D1 returns 2 for a short period of time
> (~0.5s) after I stop moving the pointing stick or touchpad. It varies,
> but you get ~50 messages each time which spams the log hard.
> [ 95.925055] i2c_hid i2c-DLL07D1:01: i2c_hid_get_input: incomplete report (83/2)
>
> This has also been observed with a i2c-ALP0017.
> [ 1781.266353] i2c_hid i2c-ALP0017:00: i2c_hid_get_input: incomplete report (30/2)
>
> Only print the message when ret_size is totally invalid and less than 2
> to cut down on the log spam.
>
> Reported-by: John Smith <john-s-84@gmx.net>
> Cc: stable@vger.kernel.org
> Signed-off-by: Jason Andryuk <jandryuk@gmail.com>
Applied, thanks.
--
Jiri Kosina
SUSE Labs
^ permalink raw reply
* Re: [PATCH] i2c-hid: Fix "incomplete report" noise
From: Jason Andryuk @ 2018-07-09 12:14 UTC (permalink / raw)
To: open list, Jiri Kosina, Benjamin Tissoires
Cc: john-s-84, Jason Andryuk, stable, linux-input
In-Reply-To: <20180622162549.9563-1-jandryuk@gmail.com>
Ping?
The logging here is very excessive. If not this change, then some
other change is needed to cut down on the sheer quantity of messages.
Thanks,
Jason
On Fri, Jun 22, 2018 at 12:25 PM, Jason Andryuk <jandryuk@gmail.com> wrote:
> Commit ac75a041048b ("HID: i2c-hid: fix size check and type usage")
> started writing messages when the ret_size is <= 2 from i2c_master_recv.
> However, my device i2c-DLL07D1 returns 2 for a short period of time
> (~0.5s) after I stop moving the pointing stick or touchpad. It varies,
> but you get ~50 messages each time which spams the log hard.
> [ 95.925055] i2c_hid i2c-DLL07D1:01: i2c_hid_get_input: incomplete report (83/2)
>
> This has also been observed with a i2c-ALP0017.
> [ 1781.266353] i2c_hid i2c-ALP0017:00: i2c_hid_get_input: incomplete report (30/2)
>
> Only print the message when ret_size is totally invalid and less than 2
> to cut down on the log spam.
>
> Reported-by: John Smith <john-s-84@gmx.net>
> Cc: stable@vger.kernel.org
> Signed-off-by: Jason Andryuk <jandryuk@gmail.com>
> ---
> John Smith originally reported this, but his post did not include a git
> formatted patch nor a Signed-off-by.
> https://www.spinics.net/lists/linux-input/msg56171.html
> https://patchwork.kernel.org/patch/10374383/
>
> When ret_size is 2, hid_input_report is passed 0 and returns early. ret_size
> == 2 seems to be a header size saying there is no content. Should
> i2c_hid_get_input just return early in that case?
>
> Also, should this condition be noted to stop an interrupt from firing to
> avoid the ~50 bogus messages?
>
> drivers/hid/i2c-hid/i2c-hid.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c
> index c1652bb7bd15..eae0cb3ddec6 100644
> --- a/drivers/hid/i2c-hid/i2c-hid.c
> +++ b/drivers/hid/i2c-hid/i2c-hid.c
> @@ -484,7 +484,7 @@ static void i2c_hid_get_input(struct i2c_hid *ihid)
> return;
> }
>
> - if ((ret_size > size) || (ret_size <= 2)) {
> + if ((ret_size > size) || (ret_size < 2)) {
> dev_err(&ihid->client->dev, "%s: incomplete report (%d/%d)\n",
> __func__, size, ret_size);
> return;
> --
> 2.17.1
>
^ permalink raw reply
* [PATCH 5/5] m68k/io: Switch mmu variant to <asm-generic/io.h>
From: Geert Uytterhoeven @ 2018-07-09 9:30 UTC (permalink / raw)
To: Greg Ungerer, Dmitry Torokhov, Helge Deller
Cc: linux-m68k, netdev, linux-input, linux-kernel, Geert Uytterhoeven
In-Reply-To: <20180709093040.23597-1-geert@linux-m68k.org>
The dummy functions defined in <asm/io_mm.h> can be provided by
<asm-generic/io.h>.
As nommu already uses <asm-generic/io.h>, move its inclusion to
<asm/io.h>, and add/adjust include guards where appropriate.
This gets rid of lots of "statement with no effect" and "unused
variable" warnings when compile-testing.
Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
---
v2:
- No changes.
---
arch/m68k/include/asm/io.h | 7 ++++++
arch/m68k/include/asm/io_mm.h | 40 +++--------------------------------
arch/m68k/include/asm/io_no.h | 1 -
3 files changed, 10 insertions(+), 38 deletions(-)
diff --git a/arch/m68k/include/asm/io.h b/arch/m68k/include/asm/io.h
index ca2849afb0877339..aabe6420ead2a599 100644
--- a/arch/m68k/include/asm/io.h
+++ b/arch/m68k/include/asm/io.h
@@ -1,6 +1,13 @@
/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _M68K_IO_H
+#define _M68K_IO_H
+
#if defined(__uClinux__) || defined(CONFIG_COLDFIRE)
#include <asm/io_no.h>
#else
#include <asm/io_mm.h>
#endif
+
+#include <asm-generic/io.h>
+
+#endif /* _M68K_IO_H */
diff --git a/arch/m68k/include/asm/io_mm.h b/arch/m68k/include/asm/io_mm.h
index 7e518303786c2d65..782b78f8a04890b3 100644
--- a/arch/m68k/include/asm/io_mm.h
+++ b/arch/m68k/include/asm/io_mm.h
@@ -16,8 +16,8 @@
* isa_readX(),isa_writeX() are for ISA memory
*/
-#ifndef _IO_H
-#define _IO_H
+#ifndef _M68K_IO_MM_H
+#define _M68K_IO_MM_H
#ifdef __KERNEL__
@@ -367,40 +367,6 @@ static inline void isa_delay(void)
#define writew(val, addr) out_le16((addr), (val))
#endif /* CONFIG_ATARI_ROM_ISA */
-#if !defined(CONFIG_ISA) && !defined(CONFIG_ATARI_ROM_ISA)
-/*
- * We need to define dummy functions for GENERIC_IOMAP support.
- */
-#define inb(port) 0xff
-#define inb_p(port) 0xff
-#define outb(val,port) ((void)0)
-#define outb_p(val,port) ((void)0)
-#define inw(port) 0xffff
-#define inw_p(port) 0xffff
-#define outw(val,port) ((void)0)
-#define outw_p(val,port) ((void)0)
-#define inl(port) 0xffffffffUL
-#define inl_p(port) 0xffffffffUL
-#define outl(val,port) ((void)0)
-#define outl_p(val,port) ((void)0)
-
-#define insb(port,buf,nr) ((void)0)
-#define outsb(port,buf,nr) ((void)0)
-#define insw(port,buf,nr) ((void)0)
-#define outsw(port,buf,nr) ((void)0)
-#define insl(port,buf,nr) ((void)0)
-#define outsl(port,buf,nr) ((void)0)
-
-/*
- * These should be valid on any ioremap()ed region
- */
-#define readb(addr) in_8(addr)
-#define writeb(val,addr) out_8((addr),(val))
-#define readw(addr) in_le16(addr)
-#define writew(val,addr) out_le16((addr),(val))
-
-#endif /* !CONFIG_ISA && !CONFIG_ATARI_ROM_ISA */
-
#define readl(addr) in_le32(addr)
#define writel(val,addr) out_le32((addr),(val))
@@ -442,4 +408,4 @@ static inline void isa_delay(void)
#define writew_relaxed(b, addr) writew(b, addr)
#define writel_relaxed(b, addr) writel(b, addr)
-#endif /* _IO_H */
+#endif /* _M68K_IO_MM_H */
diff --git a/arch/m68k/include/asm/io_no.h b/arch/m68k/include/asm/io_no.h
index c207428fae5953e7..0498192e1d983292 100644
--- a/arch/m68k/include/asm/io_no.h
+++ b/arch/m68k/include/asm/io_no.h
@@ -133,6 +133,5 @@ static inline void writel(u32 value, volatile void __iomem *addr)
#include <asm/kmap.h>
#include <asm/virtconvert.h>
-#include <asm-generic/io.h>
#endif /* _M68KNOMMU_IO_H */
--
2.17.1
^ permalink raw reply related
* [PATCH 4/5] m68k/io: Move mem*io define guards to <asm/kmap.h>
From: Geert Uytterhoeven @ 2018-07-09 9:30 UTC (permalink / raw)
To: Greg Ungerer, Dmitry Torokhov, Helge Deller
Cc: linux-m68k, netdev, linux-input, linux-kernel, Geert Uytterhoeven
In-Reply-To: <20180709093040.23597-1-geert@linux-m68k.org>
The mem*io define guards are applicable to all users of <asm/kmap.h>.
Hence move them, and drop the #ifdef.
Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
---
To avoid redefined warnings, this depends on "net: mac8390: Use standard
memcpy_{from,to}io()".
v2:
- No changes.
---
arch/m68k/include/asm/io_no.h | 11 -----------
arch/m68k/include/asm/kmap.h | 3 +++
2 files changed, 3 insertions(+), 11 deletions(-)
diff --git a/arch/m68k/include/asm/io_no.h b/arch/m68k/include/asm/io_no.h
index 83a0a6d449f44bdd..c207428fae5953e7 100644
--- a/arch/m68k/include/asm/io_no.h
+++ b/arch/m68k/include/asm/io_no.h
@@ -131,17 +131,6 @@ static inline void writel(u32 value, volatile void __iomem *addr)
#define PCI_SPACE_LIMIT PCI_IO_MASK
#endif /* CONFIG_PCI */
-/*
- * These are defined in kmap.h as static inline functions. To maintain
- * previous behavior we put these define guards here so io_mm.h doesn't
- * see them.
- */
-#ifdef CONFIG_MMU
-#define memset_io memset_io
-#define memcpy_fromio memcpy_fromio
-#define memcpy_toio memcpy_toio
-#endif
-
#include <asm/kmap.h>
#include <asm/virtconvert.h>
#include <asm-generic/io.h>
diff --git a/arch/m68k/include/asm/kmap.h b/arch/m68k/include/asm/kmap.h
index 608e12f058a7cd7d..aac7f045f7f0aa85 100644
--- a/arch/m68k/include/asm/kmap.h
+++ b/arch/m68k/include/asm/kmap.h
@@ -50,18 +50,21 @@ static inline void __iomem *ioremap_fullcache(unsigned long physaddr,
return __ioremap(physaddr, size, IOMAP_FULL_CACHING);
}
+#define memset_io memset_io
static inline void memset_io(volatile void __iomem *addr, unsigned char val,
int count)
{
__builtin_memset((void __force *) addr, val, count);
}
+#define memcpy_fromio memcpy_fromio
static inline void memcpy_fromio(void *dst, const volatile void __iomem *src,
int count)
{
__builtin_memcpy(dst, (void __force *) src, count);
}
+#define memcpy_toio memcpy_toio
static inline void memcpy_toio(volatile void __iomem *dst, const void *src,
int count)
{
--
2.17.1
^ permalink raw reply related
* [PATCH 3/5] Input: hilkbd - Add casts to HP9000/300 I/O accessors
From: Geert Uytterhoeven @ 2018-07-09 9:30 UTC (permalink / raw)
To: Greg Ungerer, Dmitry Torokhov, Helge Deller
Cc: linux-m68k, netdev, linux-input, linux-kernel, Geert Uytterhoeven
In-Reply-To: <20180709093040.23597-1-geert@linux-m68k.org>
Internally, hilkbd uses "unsigned long" I/O addresses everywhere.
This works fine as:
- On PA-RISC, hilkbd uses the gsc_{read,write}b() I/O accessors, which
take "unsigned long" addresses,
- On m68k, hilkbd uses {read,write}b(), which are currently mapped to
{in,out}_8(), and convert the passed addresses to pointers
internally.
However, the asm-generic version of {read,write}b() does not perform
such conversions, and requires passing pointers instead. Hence add
casts to prepare for switching m68k to the asm-generic version.
Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
---
This is a dependency for "m68k/io: Switch mmu variant to
<asm-generic/io.h>".
v2:
- No changes.
---
drivers/input/keyboard/hilkbd.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/input/keyboard/hilkbd.c b/drivers/input/keyboard/hilkbd.c
index a4e404aaf64bdb82..5c7afdec192c139b 100644
--- a/drivers/input/keyboard/hilkbd.c
+++ b/drivers/input/keyboard/hilkbd.c
@@ -57,8 +57,8 @@ MODULE_LICENSE("GPL v2");
#define HIL_DATA 0x1
#define HIL_CMD 0x3
#define HIL_IRQ 2
- #define hil_readb(p) readb(p)
- #define hil_writeb(v,p) writeb((v),(p))
+ #define hil_readb(p) readb((const volatile void __iomem *)(p))
+ #define hil_writeb(v, p) writeb((v), (volatile void __iomem *)(p))
#else
#error "HIL is not supported on this platform"
--
2.17.1
^ permalink raw reply related
* [PATCH 2/5] net: mac8390: Use standard memcpy_{from,to}io()
From: Geert Uytterhoeven @ 2018-07-09 9:30 UTC (permalink / raw)
To: Greg Ungerer, Dmitry Torokhov, Helge Deller
Cc: linux-m68k, netdev, linux-input, linux-kernel, Geert Uytterhoeven
In-Reply-To: <20180709093040.23597-1-geert@linux-m68k.org>
The mac8390 driver defines its own variants of memcpy_fromio() and
memcpy_toio(), using similar implementations, but different function
signatures.
Remove the custom definitions of memcpy_fromio() and memcpy_toio(), and
adjust all callers to the standard signatures.
Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
Acked-by: David S. Miller <davem@davemloft.net>
---
This is a dependency for "m68k: Move mem*io define guards to
<asm/kmap.h>".
Untested on real hardware, assembler output compared.
v2:
- Add Acked-by.
---
drivers/net/ethernet/8390/mac8390.c | 20 ++++++++++----------
1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/drivers/net/ethernet/8390/mac8390.c b/drivers/net/ethernet/8390/mac8390.c
index b6d735bf80117e27..342ae08ec3c29832 100644
--- a/drivers/net/ethernet/8390/mac8390.c
+++ b/drivers/net/ethernet/8390/mac8390.c
@@ -153,9 +153,6 @@ static void dayna_block_input(struct net_device *dev, int count,
static void dayna_block_output(struct net_device *dev, int count,
const unsigned char *buf, int start_page);
-#define memcpy_fromio(a, b, c) memcpy((a), (void *)(b), (c))
-#define memcpy_toio(a, b, c) memcpy((void *)(a), (b), (c))
-
#define memcmp_withio(a, b, c) memcmp((a), (void *)(b), (c))
/* Slow Sane (16-bit chunk memory read/write) Cabletron uses this */
@@ -239,7 +236,7 @@ static enum mac8390_access mac8390_testio(unsigned long membase)
unsigned long outdata = 0xA5A0B5B0;
unsigned long indata = 0x00000000;
/* Try writing 32 bits */
- memcpy_toio(membase, &outdata, 4);
+ memcpy_toio((void __iomem *)membase, &outdata, 4);
/* Now compare them */
if (memcmp_withio(&outdata, membase, 4) == 0)
return ACCESS_32;
@@ -711,7 +708,7 @@ static void sane_get_8390_hdr(struct net_device *dev,
struct e8390_pkt_hdr *hdr, int ring_page)
{
unsigned long hdr_start = (ring_page - WD_START_PG)<<8;
- memcpy_fromio(hdr, dev->mem_start + hdr_start, 4);
+ memcpy_fromio(hdr, (void __iomem *)dev->mem_start + hdr_start, 4);
/* Fix endianness */
hdr->count = swab16(hdr->count);
}
@@ -725,13 +722,16 @@ static void sane_block_input(struct net_device *dev, int count,
if (xfer_start + count > ei_status.rmem_end) {
/* We must wrap the input move. */
int semi_count = ei_status.rmem_end - xfer_start;
- memcpy_fromio(skb->data, dev->mem_start + xfer_base,
+ memcpy_fromio(skb->data,
+ (void __iomem *)dev->mem_start + xfer_base,
semi_count);
count -= semi_count;
- memcpy_fromio(skb->data + semi_count, ei_status.rmem_start,
- count);
+ memcpy_fromio(skb->data + semi_count,
+ (void __iomem *)ei_status.rmem_start, count);
} else {
- memcpy_fromio(skb->data, dev->mem_start + xfer_base, count);
+ memcpy_fromio(skb->data,
+ (void __iomem *)dev->mem_start + xfer_base,
+ count);
}
}
@@ -740,7 +740,7 @@ static void sane_block_output(struct net_device *dev, int count,
{
long shmem = (start_page - WD_START_PG)<<8;
- memcpy_toio(dev->mem_start + shmem, buf, count);
+ memcpy_toio((void __iomem *)dev->mem_start + shmem, buf, count);
}
/* dayna block input/output */
--
2.17.1
^ permalink raw reply related
* [PATCH 1/5] m68k/io: Add missing ioremap define guards, fix typo
From: Geert Uytterhoeven @ 2018-07-09 9:30 UTC (permalink / raw)
To: Greg Ungerer, Dmitry Torokhov, Helge Deller
Cc: linux-m68k, netdev, linux-input, linux-kernel, Geert Uytterhoeven
In-Reply-To: <20180709093040.23597-1-geert@linux-m68k.org>
- Add missing define guard for ioremap_wt(),
- Move ARCH_HAS_IOREMAP_WT from <asm/io_mm.h> to <asm/kmap.h>, as it
is applicable to Coldfire with MMU, too,
- Fix typo s/ioremap_fillcache/ioremap_fullcache/,
- Add define guard for iounmap() for consistency with other
architectures.
Fixes: 9746882f547d2f00 ("m68k: group io mapping definitions and functions")
Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
---
v2:
- Move ARCH_HAS_IOREMAP_WT to fix "ioremap_wt redefined" warnings with
m5475evb defconfig.
---
arch/m68k/include/asm/io_mm.h | 2 --
arch/m68k/include/asm/kmap.h | 6 +++++-
2 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/arch/m68k/include/asm/io_mm.h b/arch/m68k/include/asm/io_mm.h
index fe485f4f5fac4d92..7e518303786c2d65 100644
--- a/arch/m68k/include/asm/io_mm.h
+++ b/arch/m68k/include/asm/io_mm.h
@@ -21,8 +21,6 @@
#ifdef __KERNEL__
-#define ARCH_HAS_IOREMAP_WT
-
#include <linux/compiler.h>
#include <asm/raw_io.h>
#include <asm/virtconvert.h>
diff --git a/arch/m68k/include/asm/kmap.h b/arch/m68k/include/asm/kmap.h
index 84b8333db8ad1987..608e12f058a7cd7d 100644
--- a/arch/m68k/include/asm/kmap.h
+++ b/arch/m68k/include/asm/kmap.h
@@ -4,6 +4,8 @@
#ifdef CONFIG_MMU
+#define ARCH_HAS_IOREMAP_WT
+
/* Values for nocacheflag and cmode */
#define IOMAP_FULL_CACHING 0
#define IOMAP_NOCACHE_SER 1
@@ -16,6 +18,7 @@
*/
extern void __iomem *__ioremap(unsigned long physaddr, unsigned long size,
int cacheflag);
+#define iounmap iounmap
extern void iounmap(void __iomem *addr);
extern void __iounmap(void *addr, unsigned long size);
@@ -33,13 +36,14 @@ static inline void __iomem *ioremap_nocache(unsigned long physaddr,
}
#define ioremap_uc ioremap_nocache
+#define ioremap_wt ioremap_wt
static inline void __iomem *ioremap_wt(unsigned long physaddr,
unsigned long size)
{
return __ioremap(physaddr, size, IOMAP_WRITETHROUGH);
}
-#define ioremap_fillcache ioremap_fullcache
+#define ioremap_fullcache ioremap_fullcache
static inline void __iomem *ioremap_fullcache(unsigned long physaddr,
unsigned long size)
{
--
2.17.1
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox