mirror of
https://github.com/torvalds/linux.git
synced 2026-03-08 04:04:43 +01:00
HID: haptic: add hid_haptic_switch_mode
Function hid_haptic_switch_mode() can be used to switch between device-controlled mode and host-controlled mode. Uploading a WAVEFORMPRESS or WAVEFORMRELEASE effect triggers host-controlled mode if the device is in device-controlled mode. Signed-off-by: Angela Czubak <aczubak@google.com> Co-developed-by: Jonathan Denose <jdenose@google.com> Signed-off-by: Jonathan Denose <jdenose@google.com> Signed-off-by: Benjamin Tissoires <bentiss@kernel.org>
This commit is contained in:
parent
4e584ac737
commit
ff66b8eebb
1 changed files with 59 additions and 7 deletions
|
|
@ -5,6 +5,7 @@
|
|||
* Copyright (c) 2021 Angela Czubak <acz@semihalf.com>
|
||||
*/
|
||||
|
||||
#include <linux/input/mt.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include "hid-haptic.h"
|
||||
|
|
@ -197,12 +198,46 @@ static void fill_effect_buf(struct hid_haptic_device *haptic,
|
|||
mutex_unlock(&haptic->manual_trigger_mutex);
|
||||
}
|
||||
|
||||
static void switch_mode(struct hid_device *hdev, struct hid_haptic_device *haptic,
|
||||
int mode)
|
||||
{
|
||||
struct hid_report *rep = haptic->auto_trigger_report;
|
||||
struct hid_field *field;
|
||||
s32 value;
|
||||
int i, j;
|
||||
|
||||
if (mode == HID_HAPTIC_MODE_HOST)
|
||||
value = HID_HAPTIC_ORDINAL_WAVEFORMSTOP;
|
||||
else
|
||||
value = haptic->default_auto_trigger;
|
||||
|
||||
mutex_lock(&haptic->auto_trigger_mutex);
|
||||
for (i = 0; i < rep->maxfield; i++) {
|
||||
field = rep->field[i];
|
||||
/* Ignore if report count is out of bounds. */
|
||||
if (field->report_count < 1)
|
||||
continue;
|
||||
|
||||
for (j = 0; j < field->maxusage; j++) {
|
||||
if (field->usage[j].hid == HID_HP_AUTOTRIGGER)
|
||||
field->value[j] = value;
|
||||
}
|
||||
}
|
||||
|
||||
/* send the report */
|
||||
hid_hw_request(hdev, rep, HID_REQ_SET_REPORT);
|
||||
mutex_unlock(&haptic->auto_trigger_mutex);
|
||||
haptic->mode = mode;
|
||||
}
|
||||
|
||||
static int hid_haptic_upload_effect(struct input_dev *dev, struct ff_effect *effect,
|
||||
struct ff_effect *old)
|
||||
{
|
||||
struct hid_device *hdev = input_get_drvdata(dev);
|
||||
struct ff_device *ff = dev->ff;
|
||||
struct hid_haptic_device *haptic = ff->private;
|
||||
int i, ordinal = 0;
|
||||
bool switch_modes = false;
|
||||
|
||||
/* If vendor range, check vendor id and page */
|
||||
if (effect->u.haptic.hid_usage >= (HID_HP_VENDORWAVEFORMMIN & HID_USAGE) &&
|
||||
|
|
@ -225,6 +260,16 @@ static int hid_haptic_upload_effect(struct input_dev *dev, struct ff_effect *eff
|
|||
fill_effect_buf(haptic, &effect->u.haptic, &haptic->effect[effect->id],
|
||||
ordinal);
|
||||
|
||||
if (effect->u.haptic.hid_usage == (HID_HP_WAVEFORMPRESS & HID_USAGE) ||
|
||||
effect->u.haptic.hid_usage == (HID_HP_WAVEFORMRELEASE & HID_USAGE))
|
||||
switch_modes = true;
|
||||
|
||||
/* If device is in autonomous mode, and the uploaded effect signals userspace
|
||||
* wants control of the device, change modes
|
||||
*/
|
||||
if (switch_modes && haptic->mode == HID_HAPTIC_MODE_DEVICE)
|
||||
switch_mode(hdev, haptic, HID_HAPTIC_MODE_HOST);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -290,6 +335,7 @@ static void effect_set_default(struct ff_effect *effect)
|
|||
static int hid_haptic_erase(struct input_dev *dev, int effect_id)
|
||||
{
|
||||
struct hid_haptic_device *haptic = dev->ff->private;
|
||||
struct hid_device *hdev = input_get_drvdata(dev);
|
||||
struct ff_effect effect;
|
||||
int ordinal;
|
||||
|
||||
|
|
@ -297,20 +343,25 @@ static int hid_haptic_erase(struct input_dev *dev, int effect_id)
|
|||
|
||||
if (effect.u.haptic.hid_usage == (HID_HP_WAVEFORMRELEASE & HID_USAGE)) {
|
||||
ordinal = haptic->release_ordinal;
|
||||
if (!ordinal)
|
||||
if (!ordinal) {
|
||||
ordinal = HID_HAPTIC_ORDINAL_WAVEFORMNONE;
|
||||
else
|
||||
effect.u.haptic.hid_usage = HID_HP_WAVEFORMRELEASE &
|
||||
HID_USAGE;
|
||||
if (haptic->mode == HID_HAPTIC_MODE_HOST)
|
||||
switch_mode(hdev, haptic, HID_HAPTIC_MODE_DEVICE);
|
||||
} else
|
||||
effect.u.haptic.hid_usage = HID_HP_WAVEFORMRELEASE & HID_USAGE;
|
||||
|
||||
fill_effect_buf(haptic, &effect.u.haptic, &haptic->effect[effect_id],
|
||||
ordinal);
|
||||
} else if (effect.u.haptic.hid_usage == (HID_HP_WAVEFORMPRESS & HID_USAGE)) {
|
||||
ordinal = haptic->press_ordinal;
|
||||
if (!ordinal)
|
||||
if (!ordinal) {
|
||||
ordinal = HID_HAPTIC_ORDINAL_WAVEFORMNONE;
|
||||
if (haptic->mode == HID_HAPTIC_MODE_HOST)
|
||||
switch_mode(hdev, haptic, HID_HAPTIC_MODE_DEVICE);
|
||||
}
|
||||
else
|
||||
effect.u.haptic.hid_usage = HID_HP_WAVEFORMPRESS &
|
||||
HID_USAGE;
|
||||
effect.u.haptic.hid_usage = HID_HP_WAVEFORMPRESS & HID_USAGE;
|
||||
|
||||
fill_effect_buf(haptic, &effect.u.haptic, &haptic->effect[effect_id],
|
||||
ordinal);
|
||||
}
|
||||
|
|
@ -392,6 +443,7 @@ int hid_haptic_init(struct hid_device *hdev,
|
|||
haptic->hid_usage_map[HID_HAPTIC_ORDINAL_WAVEFORMSTOP] =
|
||||
HID_HP_WAVEFORMSTOP & HID_USAGE;
|
||||
|
||||
mutex_init(&haptic->auto_trigger_mutex);
|
||||
for (r = 0; r < haptic->auto_trigger_report->maxfield; r++)
|
||||
parse_auto_trigger_field(haptic, haptic->auto_trigger_report->field[r]);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue