Commit 9154301a authored by Dmitry Torokhov's avatar Dmitry Torokhov

HID: hid-input: allow input_configured callback return errors

When configuring input device via input_configured callback we may
encounter errors (for example input_mt_init_slots() may fail). Instead
of continuing with half-initialized input device let's allow driver
indicate failures.
Signed-off-by: default avatarJaikumar Ganesh <jaikumarg@android.com>
Signed-off-by: default avatarArve Hjønnevåg <arve@android.com>
Reviewed-by: default avatarBenjamin Tissoires <benjamin.tissoires@redhat.com>
Reviewed-by: default avatarDavid Herrmann <dh.herrmann@gmail.com>
Acked-by: default avatarNikolai Kondrashov <Nikolai.Kondrashov@redhat.com>
Acked-by: default avatarAndrew Duggan <aduggan@synaptics.com>
Signed-off-by: default avatarDmitry Torokhov <dmitry.torokhov@gmail.com>
Signed-off-by: default avatarJiri Kosina <jkosina@suse.cz>
parent 84a73014
...@@ -256,7 +256,7 @@ static int appleir_raw_event(struct hid_device *hid, struct hid_report *report, ...@@ -256,7 +256,7 @@ static int appleir_raw_event(struct hid_device *hid, struct hid_report *report,
return 0; return 0;
} }
static void appleir_input_configured(struct hid_device *hid, static int appleir_input_configured(struct hid_device *hid,
struct hid_input *hidinput) struct hid_input *hidinput)
{ {
struct input_dev *input_dev = hidinput->input; struct input_dev *input_dev = hidinput->input;
...@@ -275,6 +275,8 @@ static void appleir_input_configured(struct hid_device *hid, ...@@ -275,6 +275,8 @@ static void appleir_input_configured(struct hid_device *hid,
for (i = 0; i < ARRAY_SIZE(appleir_key_table); i++) for (i = 0; i < ARRAY_SIZE(appleir_key_table); i++)
set_bit(appleir->keymap[i], input_dev->keybit); set_bit(appleir->keymap[i], input_dev->keybit);
clear_bit(KEY_RESERVED, input_dev->keybit); clear_bit(KEY_RESERVED, input_dev->keybit);
return 0;
} }
static int appleir_input_mapping(struct hid_device *hid, static int appleir_input_mapping(struct hid_device *hid,
......
...@@ -37,7 +37,7 @@ static bool use_fw_quirk = true; ...@@ -37,7 +37,7 @@ static bool use_fw_quirk = true;
module_param(use_fw_quirk, bool, S_IRUGO); module_param(use_fw_quirk, bool, S_IRUGO);
MODULE_PARM_DESC(use_fw_quirk, "Do periodic pokes for broken M firmwares (default = true)"); MODULE_PARM_DESC(use_fw_quirk, "Do periodic pokes for broken M firmwares (default = true)");
static void elo_input_configured(struct hid_device *hdev, static int elo_input_configured(struct hid_device *hdev,
struct hid_input *hidinput) struct hid_input *hidinput)
{ {
struct input_dev *input = hidinput->input; struct input_dev *input = hidinput->input;
...@@ -45,6 +45,8 @@ static void elo_input_configured(struct hid_device *hdev, ...@@ -45,6 +45,8 @@ static void elo_input_configured(struct hid_device *hdev,
set_bit(BTN_TOUCH, input->keybit); set_bit(BTN_TOUCH, input->keybit);
set_bit(ABS_PRESSURE, input->absbit); set_bit(ABS_PRESSURE, input->absbit);
input_set_abs_params(input, ABS_PRESSURE, 0, 256, 0, 0); input_set_abs_params(input, ABS_PRESSURE, 0, 256, 0, 0);
return 0;
} }
static void elo_process_data(struct input_dev *input, const u8 *data, int size) static void elo_process_data(struct input_dev *input, const u8 *data, int size)
......
...@@ -1510,8 +1510,9 @@ int hidinput_connect(struct hid_device *hid, unsigned int force) ...@@ -1510,8 +1510,9 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
* UGCI) cram a lot of unrelated inputs into the * UGCI) cram a lot of unrelated inputs into the
* same interface. */ * same interface. */
hidinput->report = report; hidinput->report = report;
if (drv->input_configured) if (drv->input_configured &&
drv->input_configured(hid, hidinput); drv->input_configured(hid, hidinput))
goto out_cleanup;
if (input_register_device(hidinput->input)) if (input_register_device(hidinput->input))
goto out_cleanup; goto out_cleanup;
hidinput = NULL; hidinput = NULL;
...@@ -1532,8 +1533,9 @@ int hidinput_connect(struct hid_device *hid, unsigned int force) ...@@ -1532,8 +1533,9 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
} }
if (hidinput) { if (hidinput) {
if (drv->input_configured) if (drv->input_configured &&
drv->input_configured(hid, hidinput); drv->input_configured(hid, hidinput))
goto out_cleanup;
if (input_register_device(hidinput->input)) if (input_register_device(hidinput->input))
goto out_cleanup; goto out_cleanup;
} }
......
...@@ -848,7 +848,7 @@ static void lenovo_remove(struct hid_device *hdev) ...@@ -848,7 +848,7 @@ static void lenovo_remove(struct hid_device *hdev)
hid_hw_stop(hdev); hid_hw_stop(hdev);
} }
static void lenovo_input_configured(struct hid_device *hdev, static int lenovo_input_configured(struct hid_device *hdev,
struct hid_input *hi) struct hid_input *hi)
{ {
switch (hdev->product) { switch (hdev->product) {
...@@ -863,6 +863,8 @@ static void lenovo_input_configured(struct hid_device *hdev, ...@@ -863,6 +863,8 @@ static void lenovo_input_configured(struct hid_device *hdev,
} }
break; break;
} }
return 0;
} }
......
...@@ -1160,13 +1160,15 @@ static void hidpp_populate_input(struct hidpp_device *hidpp, ...@@ -1160,13 +1160,15 @@ static void hidpp_populate_input(struct hidpp_device *hidpp,
m560_populate_input(hidpp, input, origin_is_hid_core); m560_populate_input(hidpp, input, origin_is_hid_core);
} }
static void hidpp_input_configured(struct hid_device *hdev, static int hidpp_input_configured(struct hid_device *hdev,
struct hid_input *hidinput) struct hid_input *hidinput)
{ {
struct hidpp_device *hidpp = hid_get_drvdata(hdev); struct hidpp_device *hidpp = hid_get_drvdata(hdev);
struct input_dev *input = hidinput->input; struct input_dev *input = hidinput->input;
hidpp_populate_input(hidpp, input, true); hidpp_populate_input(hidpp, input, true);
return 0;
} }
static int hidpp_raw_hidpp_event(struct hidpp_device *hidpp, u8 *data, static int hidpp_raw_hidpp_event(struct hidpp_device *hidpp, u8 *data,
......
...@@ -471,18 +471,22 @@ static int magicmouse_input_mapping(struct hid_device *hdev, ...@@ -471,18 +471,22 @@ static int magicmouse_input_mapping(struct hid_device *hdev,
return 0; return 0;
} }
static void magicmouse_input_configured(struct hid_device *hdev, static int magicmouse_input_configured(struct hid_device *hdev,
struct hid_input *hi) struct hid_input *hi)
{ {
struct magicmouse_sc *msc = hid_get_drvdata(hdev); struct magicmouse_sc *msc = hid_get_drvdata(hdev);
int ret;
int ret = magicmouse_setup_input(msc->input, hdev); ret = magicmouse_setup_input(msc->input, hdev);
if (ret) { if (ret) {
hid_err(hdev, "magicmouse setup input failed (%d)\n", ret); hid_err(hdev, "magicmouse setup input failed (%d)\n", ret);
/* clean msc->input to notify probe() of the failure */ /* clean msc->input to notify probe() of the failure */
msc->input = NULL; msc->input = NULL;
return ret;
} }
return 0;
} }
......
...@@ -725,12 +725,13 @@ static void mt_touch_report(struct hid_device *hid, struct hid_report *report) ...@@ -725,12 +725,13 @@ static void mt_touch_report(struct hid_device *hid, struct hid_report *report)
mt_sync_frame(td, report->field[0]->hidinput->input); mt_sync_frame(td, report->field[0]->hidinput->input);
} }
static void mt_touch_input_configured(struct hid_device *hdev, static int mt_touch_input_configured(struct hid_device *hdev,
struct hid_input *hi) struct hid_input *hi)
{ {
struct mt_device *td = hid_get_drvdata(hdev); struct mt_device *td = hid_get_drvdata(hdev);
struct mt_class *cls = &td->mtclass; struct mt_class *cls = &td->mtclass;
struct input_dev *input = hi->input; struct input_dev *input = hi->input;
int ret;
if (!td->maxcontacts) if (!td->maxcontacts)
td->maxcontacts = MT_DEFAULT_MAXCONTACT; td->maxcontacts = MT_DEFAULT_MAXCONTACT;
...@@ -752,9 +753,12 @@ static void mt_touch_input_configured(struct hid_device *hdev, ...@@ -752,9 +753,12 @@ static void mt_touch_input_configured(struct hid_device *hdev,
if (td->is_buttonpad) if (td->is_buttonpad)
__set_bit(INPUT_PROP_BUTTONPAD, input->propbit); __set_bit(INPUT_PROP_BUTTONPAD, input->propbit);
input_mt_init_slots(input, td->maxcontacts, td->mt_flags); ret = input_mt_init_slots(input, td->maxcontacts, td->mt_flags);
if (ret)
return ret;
td->mt_flags = 0; td->mt_flags = 0;
return 0;
} }
static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
...@@ -930,15 +934,19 @@ static void mt_post_parse(struct mt_device *td) ...@@ -930,15 +934,19 @@ static void mt_post_parse(struct mt_device *td)
cls->quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE; cls->quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE;
} }
static void mt_input_configured(struct hid_device *hdev, struct hid_input *hi) static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi)
{ {
struct mt_device *td = hid_get_drvdata(hdev); struct mt_device *td = hid_get_drvdata(hdev);
char *name; char *name;
const char *suffix = NULL; const char *suffix = NULL;
struct hid_field *field = hi->report->field[0]; struct hid_field *field = hi->report->field[0];
int ret;
if (hi->report->id == td->mt_report_id) if (hi->report->id == td->mt_report_id) {
mt_touch_input_configured(hdev, hi); ret = mt_touch_input_configured(hdev, hi);
if (ret)
return ret;
}
/* /*
* some egalax touchscreens have "application == HID_DG_TOUCHSCREEN" * some egalax touchscreens have "application == HID_DG_TOUCHSCREEN"
...@@ -989,6 +997,8 @@ static void mt_input_configured(struct hid_device *hdev, struct hid_input *hi) ...@@ -989,6 +997,8 @@ static void mt_input_configured(struct hid_device *hdev, struct hid_input *hi)
hi->input->name = name; hi->input->name = name;
} }
} }
return 0;
} }
static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
......
...@@ -859,14 +859,14 @@ static int ntrig_event (struct hid_device *hid, struct hid_field *field, ...@@ -859,14 +859,14 @@ static int ntrig_event (struct hid_device *hid, struct hid_field *field,
return 1; return 1;
} }
static void ntrig_input_configured(struct hid_device *hid, static int ntrig_input_configured(struct hid_device *hid,
struct hid_input *hidinput) struct hid_input *hidinput)
{ {
struct input_dev *input = hidinput->input; struct input_dev *input = hidinput->input;
if (hidinput->report->maxfield < 1) if (hidinput->report->maxfield < 1)
return; return 0;
switch (hidinput->report->field[0]->application) { switch (hidinput->report->field[0]->application) {
case HID_DG_PEN: case HID_DG_PEN:
...@@ -890,6 +890,8 @@ static void ntrig_input_configured(struct hid_device *hid, ...@@ -890,6 +890,8 @@ static void ntrig_input_configured(struct hid_device *hid,
"N-Trig MultiTouch"; "N-Trig MultiTouch";
break; break;
} }
return 0;
} }
static int ntrig_probe(struct hid_device *hdev, const struct hid_device_id *id) static int ntrig_probe(struct hid_device *hdev, const struct hid_device_id *id)
......
...@@ -1173,7 +1173,7 @@ static int rmi_populate(struct hid_device *hdev) ...@@ -1173,7 +1173,7 @@ static int rmi_populate(struct hid_device *hdev)
return 0; return 0;
} }
static void rmi_input_configured(struct hid_device *hdev, struct hid_input *hi) static int rmi_input_configured(struct hid_device *hdev, struct hid_input *hi)
{ {
struct rmi_data *data = hid_get_drvdata(hdev); struct rmi_data *data = hid_get_drvdata(hdev);
struct input_dev *input = hi->input; struct input_dev *input = hi->input;
...@@ -1185,10 +1185,10 @@ static void rmi_input_configured(struct hid_device *hdev, struct hid_input *hi) ...@@ -1185,10 +1185,10 @@ static void rmi_input_configured(struct hid_device *hdev, struct hid_input *hi)
hid_dbg(hdev, "Opening low level driver\n"); hid_dbg(hdev, "Opening low level driver\n");
ret = hid_hw_open(hdev); ret = hid_hw_open(hdev);
if (ret) if (ret)
return; return ret;
if (!(data->device_flags & RMI_DEVICE)) if (!(data->device_flags & RMI_DEVICE))
return; return 0;
/* Allow incoming hid reports */ /* Allow incoming hid reports */
hid_device_io_start(hdev); hid_device_io_start(hdev);
...@@ -1228,7 +1228,9 @@ static void rmi_input_configured(struct hid_device *hdev, struct hid_input *hi) ...@@ -1228,7 +1228,9 @@ static void rmi_input_configured(struct hid_device *hdev, struct hid_input *hi)
input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 0x0f, 0, 0); input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 0x0f, 0, 0);
input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 0, 0x0f, 0, 0); input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 0, 0x0f, 0, 0);
input_mt_init_slots(input, data->max_fingers, INPUT_MT_POINTER); ret = input_mt_init_slots(input, data->max_fingers, INPUT_MT_POINTER);
if (ret < 0)
goto exit;
if (data->button_count) { if (data->button_count) {
__set_bit(EV_KEY, input->evbit); __set_bit(EV_KEY, input->evbit);
...@@ -1244,6 +1246,7 @@ static void rmi_input_configured(struct hid_device *hdev, struct hid_input *hi) ...@@ -1244,6 +1246,7 @@ static void rmi_input_configured(struct hid_device *hdev, struct hid_input *hi)
exit: exit:
hid_device_io_stop(hdev); hid_device_io_stop(hdev);
hid_hw_close(hdev); hid_hw_close(hdev);
return ret;
} }
static int rmi_input_mapping(struct hid_device *hdev, static int rmi_input_mapping(struct hid_device *hdev,
......
...@@ -1360,20 +1360,27 @@ static int sony_register_touchpad(struct hid_input *hi, int touch_count, ...@@ -1360,20 +1360,27 @@ static int sony_register_touchpad(struct hid_input *hi, int touch_count,
return 0; return 0;
} }
static void sony_input_configured(struct hid_device *hdev, static int sony_input_configured(struct hid_device *hdev,
struct hid_input *hidinput) struct hid_input *hidinput)
{ {
struct sony_sc *sc = hid_get_drvdata(hdev); struct sony_sc *sc = hid_get_drvdata(hdev);
int ret;
/* /*
* The Dualshock 4 touchpad supports 2 touches and has a * The Dualshock 4 touchpad supports 2 touches and has a
* resolution of 1920x942 (44.86 dots/mm). * resolution of 1920x942 (44.86 dots/mm).
*/ */
if (sc->quirks & DUALSHOCK4_CONTROLLER) { if (sc->quirks & DUALSHOCK4_CONTROLLER) {
if (sony_register_touchpad(hidinput, 2, 1920, 942) != 0) ret = sony_register_touchpad(hidinput, 2, 1920, 942);
if (ret) {
hid_err(sc->hdev, hid_err(sc->hdev,
"Unable to initialize multi-touch slots\n"); "Unable to initialize multi-touch slots: %d\n",
ret);
return ret;
}
} }
return 0;
} }
/* /*
......
...@@ -731,7 +731,7 @@ static int uclogic_input_mapping(struct hid_device *hdev, struct hid_input *hi, ...@@ -731,7 +731,7 @@ static int uclogic_input_mapping(struct hid_device *hdev, struct hid_input *hi,
return 0; return 0;
} }
static void uclogic_input_configured(struct hid_device *hdev, static int uclogic_input_configured(struct hid_device *hdev,
struct hid_input *hi) struct hid_input *hi)
{ {
char *name; char *name;
...@@ -741,7 +741,7 @@ static void uclogic_input_configured(struct hid_device *hdev, ...@@ -741,7 +741,7 @@ static void uclogic_input_configured(struct hid_device *hdev,
/* no report associated (HID_QUIRK_MULTI_INPUT not set) */ /* no report associated (HID_QUIRK_MULTI_INPUT not set) */
if (!hi->report) if (!hi->report)
return; return 0;
field = hi->report->field[0]; field = hi->report->field[0];
...@@ -774,6 +774,8 @@ static void uclogic_input_configured(struct hid_device *hdev, ...@@ -774,6 +774,8 @@ static void uclogic_input_configured(struct hid_device *hdev,
hi->input->name = name; hi->input->name = name;
} }
} }
return 0;
} }
/** /**
......
...@@ -698,8 +698,8 @@ struct hid_driver { ...@@ -698,8 +698,8 @@ struct hid_driver {
int (*input_mapped)(struct hid_device *hdev, int (*input_mapped)(struct hid_device *hdev,
struct hid_input *hidinput, struct hid_field *field, struct hid_input *hidinput, struct hid_field *field,
struct hid_usage *usage, unsigned long **bit, int *max); struct hid_usage *usage, unsigned long **bit, int *max);
void (*input_configured)(struct hid_device *hdev, int (*input_configured)(struct hid_device *hdev,
struct hid_input *hidinput); struct hid_input *hidinput);
void (*feature_mapping)(struct hid_device *hdev, void (*feature_mapping)(struct hid_device *hdev,
struct hid_field *field, struct hid_field *field,
struct hid_usage *usage); struct hid_usage *usage);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment