[PATCH v2 05/15] HID: ft260: i2c: silence sysfs store big-numbers

From: Michael Zaidman

Date: Fri Oct 30 2026 - 18:39:21 EST


FT260_ATTR_STORE returned the feature-report transfer length from
ft260_hid_feature_report_set() instead of the sysfs write size. For
values like 1000, userspace writes more bytes than the HID report
length, so the VFS retries the remainder and reports "Invalid argument"
even though the attribute was applied correctly:

$ echo 1000 > .../clock
bash: line 1: echo: write error: Invalid argument
$ cat .../clock
1000

Return count after a successful parse so the full write is consumed.

Do not report success when the feature report fails. Store 16-bit
attributes in little endian (reported by Sashiko).

Signed-off-by: Michael Zaidman <michael.zaidman@xxxxxxxxx>

---
v2: do not mask a failed feature report; cpu_to_le16 on word store
(reported by Sashiko).
---
drivers/hid/hid-ft260.c | 16 ++++++++++------
1 file changed, 10 insertions(+), 6 deletions(-)

diff --git a/drivers/hid/hid-ft260.c b/drivers/hid/hid-ft260.c
index f134fab08285..d2c5c9ed7927 100644
--- a/drivers/hid/hid-ft260.c
+++ b/drivers/hid/hid-ft260.c
@@ -1471,63 +1471,67 @@ static int ft260_word_show(struct hid_device *hdev, int id, u8 *cfg, int len,
static void ft260_attr_dummy_func(struct hid_device *hdev, u8 req, u16 value)
{
}

#define FT260_ATTR_SHOW(name, reptype, id, type, func) \
static ssize_t name##_show(struct device *kdev, \
struct device_attribute *attr, char *buf) \
{ \
struct reptype rep; \
struct hid_device *hdev = to_hid_device(kdev); \
type *field = &rep.name; \
int len = sizeof(rep); \
\
return func(hdev, id, (u8 *)&rep, len, field, buf); \
}

#define FT260_SSTAT_ATTR_SHOW(name) \
FT260_ATTR_SHOW(name, ft260_get_system_status_report, \
FT260_SYSTEM_SETTINGS, u8, ft260_byte_show)

#define FT260_I2CST_ATTR_SHOW(name) \
FT260_ATTR_SHOW(name, ft260_get_i2c_status_report, \
FT260_I2C_STATUS, __le16, ft260_word_show)

-#define FT260_ATTR_STORE(name, reptype, id, req, type, ctype, strtou, func) \
+#define FT260_STORE_NATIVE(v) (v)
+
+#define FT260_ATTR_STORE(name, reptype, id, req, type, strtou, func, conv) \
static ssize_t name##_store(struct device *kdev, \
struct device_attribute *attr, \
const char *buf, size_t count) \
{ \
struct reptype rep; \
struct hid_device *hdev = to_hid_device(kdev); \
struct ft260_device *dev = hid_get_drvdata(hdev); \
type name; \
int ret; \
\
- if (!strtou(buf, 10, (ctype *)&name)) { \
- rep.name = name; \
+ if (!strtou(buf, 10, &name)) { \
+ rep.name = conv(name); \
rep.report = id; \
rep.request = req; \
mutex_lock(&dev->lock); \
ret = ft260_hid_feature_report_set(hdev, (u8 *)&rep, \
sizeof(rep)); \
if (ret < 0) \
hid_err(hdev, "%s: failed!\n", __func__); \
- else \
+ else { \
func(hdev, req, name); \
+ ret = count; \
+ } \
mutex_unlock(&dev->lock); \
} else { \
ret = -EINVAL; \
} \
return ret; \
}

#define FT260_BYTE_ATTR_STORE(name, reptype, req, func) \
FT260_ATTR_STORE(name, reptype, FT260_SYSTEM_SETTINGS, req, \
- u8, u8, kstrtou8, func)
+ u8, kstrtou8, func, FT260_STORE_NATIVE)

#define FT260_WORD_ATTR_STORE(name, reptype, req, func) \
FT260_ATTR_STORE(name, reptype, FT260_SYSTEM_SETTINGS, req, \
- __le16, u16, kstrtou16, func)
+ u16, kstrtou16, func, cpu_to_le16)

FT260_SSTAT_ATTR_SHOW(chip_mode);
static DEVICE_ATTR_RO(chip_mode);
--
2.43.0