From: Michael Zaidman <michael.zaidman@gmail.com>
To: Jiri Kosina <jikos@kernel.org>, Benjamin Tissoires <bentiss@kernel.org>
Cc: Linus Walleij <linusw@kernel.org>,
Bartosz Golaszewski <brgl@kernel.org>,
Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
Jiri Slaby <jirislaby@kernel.org>,
Raman Varabets <kernel-linux-20260610-80b7ab08@raman.v1.sg>,
Germain Hebert <germain.hebert@ca.abb.com>,
Christina Quast <contact@christina-quast.de>,
Rio Liu <rio@r26.me>, Bruno Giacomazzi <brunoceg1@gmail.com>,
linux-input@vger.kernel.org, linux-serial@vger.kernel.org,
linux-gpio@vger.kernel.org, linux-i2c@vger.kernel.org,
linux-kernel@vger.kernel.org,
Michael Zaidman <michael.zaidman@gmail.com>
Subject: [PATCH v3 16/16] HID: ft260: use lock guards
Date: Sun, 15 Nov 2026 01:08:00 +0200 [thread overview]
Message-ID: <20261114230800.1344401-17-michael.zaidman@gmail.com> (raw)
In-Reply-To: <20261114230800.1344401-1-michael.zaidman@gmail.com>
Convert the mutex_lock() and mutex_unlock() pairs to guard(mutex) from
linux/cleanup.h. The lock is released on each return, so the goto
labels that only unlock a mutex are removed, and the error paths
return directly.
ft260_uart_port_remove(), ft260_remove() and ft260_schedule_reset()
take a lock for one or two statements in the middle of the function.
They use scoped_guard(), which releases the lock at the end of the
block. The two remove functions do not hold the lock over the tty
hangup and the rest of the removal. ft260_schedule_reset() must not
hold it when it calls ft260_chip_put(), which takes the same lock.
The i2c_exit and smbus_exit labels stay, because they also set the
normal power mode with hid_hw_power().
No functional change.
Suggested-by: Bartosz Golaszewski <brgl@kernel.org>
Signed-off-by: Michael Zaidman <michael.zaidman@gmail.com>
---
v3:
New patch (suggested by Bartosz Golaszewski). It is the last patch,
so the out-of-tree driver for kernels older than 6.5, which do not
have linux/cleanup.h, can leave it out.
---
drivers/hid/hid-ft260.c | 119 +++++++++++++---------------------------
1 file changed, 39 insertions(+), 80 deletions(-)
diff --git a/drivers/hid/hid-ft260.c b/drivers/hid/hid-ft260.c
index 53321c8d70fd..716b37cead7d 100644
--- a/drivers/hid/hid-ft260.c
+++ b/drivers/hid/hid-ft260.c
@@ -532,11 +532,11 @@ static struct ft260_chip *ft260_chip_get(struct usb_device *udev)
{
struct ft260_chip *chip;
- mutex_lock(&ft260_chip_list_lock);
+ guard(mutex)(&ft260_chip_list_lock);
list_for_each_entry(chip, &ft260_chip_list, list) {
if (chip->udev == udev) {
kref_get(&chip->kref);
- goto out;
+ return chip;
}
}
@@ -547,8 +547,6 @@ static struct ft260_chip *ft260_chip_get(struct usb_device *udev)
mutex_init(&chip->gpio_lock);
list_add_tail(&chip->list, &ft260_chip_list);
}
-out:
- mutex_unlock(&ft260_chip_list_lock);
return chip;
}
@@ -567,9 +565,8 @@ static void ft260_chip_put(struct ft260_chip *chip)
if (!chip)
return;
- mutex_lock(&ft260_chip_list_lock);
+ guard(mutex)(&ft260_chip_list_lock);
kref_put(&chip->kref, ft260_chip_release);
- mutex_unlock(&ft260_chip_list_lock);
}
static int ft260_hid_feature_report_get(struct hid_device *hdev,
@@ -1034,12 +1031,11 @@ static int ft260_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
struct ft260_device *dev = i2c_get_adapdata(adapter);
struct hid_device *hdev = dev->hdev;
- mutex_lock(&dev->lock);
+ guard(mutex)(&dev->lock);
ret = hid_hw_power(hdev, PM_HINT_FULLON);
if (ret < 0) {
hid_err(hdev, "failed to enter FULLON power mode: %d\n", ret);
- mutex_unlock(&dev->lock);
return ret;
}
@@ -1063,7 +1059,6 @@ static int ft260_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
ret = num;
i2c_exit:
hid_hw_power(hdev, PM_HINT_NORMAL);
- mutex_unlock(&dev->lock);
return ret;
}
@@ -1077,12 +1072,11 @@ static int ft260_smbus_xfer(struct i2c_adapter *adapter, u16 addr, u16 flags,
ft260_dbg("smbus size %d\n", size);
- mutex_lock(&dev->lock);
+ guard(mutex)(&dev->lock);
ret = hid_hw_power(hdev, PM_HINT_FULLON);
if (ret < 0) {
hid_err(hdev, "power management error: %d\n", ret);
- mutex_unlock(&dev->lock);
return ret;
}
@@ -1190,7 +1184,6 @@ static int ft260_smbus_xfer(struct i2c_adapter *adapter, u16 addr, u16 flags,
smbus_exit:
hid_hw_power(hdev, PM_HINT_NORMAL);
- mutex_unlock(&dev->lock);
return ret;
}
@@ -1317,21 +1310,20 @@ static int ft260_gpio_set(struct gpio_chip *gc, u32 offset, int value)
ft260_dbg("offset %d val %d\n", offset, value);
- mutex_lock(&dev->lock);
+ guard(mutex)(&dev->lock);
if (!(dev->gpio_en & BIT(offset))) {
hid_err(hdev, "%s: wrong pin function %d\n", __func__, offset);
- ret = -EINVAL;
- goto exit;
+ return -EINVAL;
}
- mutex_lock(&dev->chip->gpio_lock);
+ guard(mutex)(&dev->chip->gpio_lock);
ret = ft260_hid_feature_report_get(hdev, FT260_GPIO, (u8 *)&buf,
sizeof(buf));
if (unlikely(ret < 0)) {
hid_err(hdev, "%s: cannot get GPIO: %d\n", __func__, ret);
- goto unlock;
+ return ret;
}
rep.report = FT260_GPIO;
@@ -1357,16 +1349,11 @@ static int ft260_gpio_set(struct gpio_chip *gc, u32 offset, int value)
ret = ft260_hid_feature_report_set(hdev, (u8 *)&rep, sizeof(rep));
if (unlikely(ret < 0)) {
hid_err(hdev, "%s: cannot set GPIO: %d\n", __func__, ret);
- goto unlock;
+ return ret;
}
dev->gpio = rep.gpio;
- ret = 0;
-unlock:
- mutex_unlock(&dev->chip->gpio_lock);
-exit:
- mutex_unlock(&dev->lock);
- return ret;
+ return 0;
}
/*
@@ -1383,12 +1370,12 @@ static int ft260_gpio_pin_set(struct ft260_device *dev, u32 offset,
struct ft260_gpio_write_request_report *rep;
struct hid_device *hdev = dev->hdev;
- mutex_lock(&dev->chip->gpio_lock);
+ guard(mutex)(&dev->chip->gpio_lock);
ret = ft260_hid_feature_report_get(hdev, FT260_GPIO, (u8 *)&buf, sizeof(buf));
if (unlikely(ret < 0)) {
hid_err(hdev, "%s: cannot get GPIO: %d\n", __func__, ret);
- goto unlock;
+ return ret;
}
rep = (struct ft260_gpio_write_request_report *)&buf;
@@ -1422,20 +1409,16 @@ static int ft260_gpio_pin_set(struct ft260_device *dev, u32 offset,
ret = ft260_hid_feature_report_set(hdev, (u8 *)rep, sizeof(*rep));
if (unlikely(ret < 0)) {
hid_err(hdev, "%s: cannot set GPIO: %d\n", __func__, ret);
- goto unlock;
+ return ret;
}
dev->gpio = rep->gpio;
- ret = 0;
-unlock:
- mutex_unlock(&dev->chip->gpio_lock);
- return ret;
+ return 0;
}
static int ft260_gpio_direction_set(struct gpio_chip *gc, u32 offset,
int value, int direction)
{
- int ret;
struct ft260_device *dev = gpiochip_get_data(gc);
struct hid_device *hdev = dev->hdev;
@@ -1446,17 +1429,14 @@ static int ft260_gpio_direction_set(struct gpio_chip *gc, u32 offset,
ft260_dbg("offset %d val %d direction %d\n", offset, value, direction);
- mutex_lock(&dev->lock);
+ guard(mutex)(&dev->lock);
if (!(dev->gpio_en & BIT(offset))) {
hid_err(hdev, "%s: wrong pin function %d\n", __func__, offset);
- ret = -EIO;
- } else {
- ret = ft260_gpio_pin_set(dev, offset, value, direction);
+ return -EIO;
}
- mutex_unlock(&dev->lock);
- return ret;
+ return ft260_gpio_pin_set(dev, offset, value, direction);
}
static int ft260_gpio_direction_output(struct gpio_chip *gc,
@@ -1791,7 +1771,7 @@ static int ft260_i2c_clock_parse(const char *buf, unsigned int base, u16 *clock)
rep.name = conv(name); \
rep.report = id; \
rep.request = req; \
- mutex_lock(&dev->lock); \
+ guard(mutex)(&dev->lock); \
ret = ft260_hid_feature_report_set(hdev, (u8 *)&rep, \
sizeof(rep)); \
if (ret < 0) \
@@ -1800,7 +1780,6 @@ static int ft260_i2c_clock_parse(const char *buf, unsigned int base, u16 *clock)
func(hdev, req, name); \
ret = count; \
} \
- mutex_unlock(&dev->lock); \
} else { \
ret = -EINVAL; \
} \
@@ -1975,7 +1954,7 @@ static int ft260_uart_add_port(struct ft260_device *port)
if (kfifo_alloc(&port->xmit_fifo, XMIT_FIFO_SIZE, GFP_KERNEL))
return -ENOMEM;
- mutex_lock(&ft260_uart_list_lock);
+ guard(mutex)(&ft260_uart_list_lock);
list_for_each_entry(dev, &ft260_uart_device_list, device_list) {
if (dev->index != index)
break;
@@ -1985,7 +1964,6 @@ static int ft260_uart_add_port(struct ft260_device *port)
port->index = index;
/* Before the first gap, or at the end: the list stays sorted */
list_add_tail(&port->device_list, &dev->device_list);
- mutex_unlock(&ft260_uart_list_lock);
return ret;
}
@@ -2004,9 +1982,8 @@ static void ft260_uart_port_remove(struct ft260_device *port)
timer_shutdown_sync(&port->wakeup_timer);
cancel_work_sync(&port->wakeup_work);
- mutex_lock(&ft260_uart_list_lock);
- list_del(&port->device_list);
- mutex_unlock(&ft260_uart_list_lock);
+ scoped_guard(mutex, &ft260_uart_list_lock)
+ list_del(&port->device_list);
tty_port_tty_vhangup(&port->port);
@@ -2025,11 +2002,10 @@ static struct ft260_device *ft260_uart_port_get(int index)
if (index >= UART_COUNT_MAX)
return NULL;
- mutex_lock(&ft260_uart_list_lock);
+ guard(mutex)(&ft260_uart_list_lock);
port = ft260_dev_by_index(index);
if (port)
tty_port_get(&port->port);
- mutex_unlock(&ft260_uart_list_lock);
return port;
}
@@ -2224,7 +2200,7 @@ static int ft260_uart_change_speed(struct ft260_device *port,
req.data_bit, req.parity,
req.stop_bit, req.breaking);
- mutex_lock(&port->lock);
+ guard(mutex)(&port->lock);
ret = ft260_hid_feature_report_set(hdev, (u8 *)&req, sizeof(req));
if (ret < 0)
@@ -2232,8 +2208,6 @@ static int ft260_uart_change_speed(struct ft260_device *port,
else
ft260_gpio_en_update(hdev, FT260_SET_UART_MODE, req.flow_ctrl);
- mutex_unlock(&port->lock);
-
return ret;
}
@@ -2266,20 +2240,16 @@ static int ft260_uart_tiocmget(struct tty_struct *tty)
*/
int mask = FT260_GPIO_UART_MODE_4_SET;
- mutex_lock(&port->lock);
- if (port->removed) {
- mutex_unlock(&port->lock);
+ guard(mutex)(&port->lock);
+ if (port->removed)
return -ENODEV;
- }
if ((port->gpio_en & mask) != mask) {
ft260_dbg("Illegal gpio config %#02x != mask %#04x\n",
port->gpio_en, mask);
- mutex_unlock(&port->lock);
return -EINVAL;
}
gpios = ft260_gpio_get_all(&port->gc, FT260_GPIO_VALUE);
- mutex_unlock(&port->lock);
if (gpios < 0)
return gpios;
@@ -2301,26 +2271,22 @@ static int ft260_uart_tiocmset(struct tty_struct *tty,
struct hid_device *hdev = port->hdev;
int mask = FT260_GPIO_UART_MODE_4_SET;
- mutex_lock(&port->lock);
- if (port->removed) {
- mutex_unlock(&port->lock);
+ guard(mutex)(&port->lock);
+ if (port->removed)
return -ENODEV;
- }
if ((port->gpio_en & mask) != mask) {
ft260_dbg("Illegal gpio config %#02x != mask %#04x\n",
port->gpio_en, mask);
- mutex_unlock(&port->lock);
return -EINVAL;
}
- mutex_lock(&port->chip->gpio_lock);
+ guard(mutex)(&port->chip->gpio_lock);
ret = ft260_hid_feature_report_get(hdev, FT260_GPIO, (u8 *)&buf,
sizeof(buf));
if (unlikely(ret < 0)) {
hid_err(hdev, "%s: cannot get GPIO: %d\n", __func__, ret);
- ret = -EIO;
- goto unlock;
+ return -EIO;
}
rep.report = FT260_GPIO;
@@ -2342,16 +2308,11 @@ static int ft260_uart_tiocmset(struct tty_struct *tty,
ret = ft260_hid_feature_report_set(hdev, (u8 *)&rep, sizeof(rep));
if (unlikely(ret < 0)) {
hid_err(hdev, "%s: cannot set GPIO: %d\n", __func__, ret);
- ret = -EIO;
- goto unlock;
+ return -EIO;
}
port->gpio = rep.gpio;
- ret = 0;
-unlock:
- mutex_unlock(&port->chip->gpio_lock);
- mutex_unlock(&port->lock);
- return ret;
+ return 0;
}
static int ft260_uart_install(struct tty_driver *driver, struct tty_struct *tty)
@@ -2733,9 +2694,8 @@ static struct workqueue_struct *ft260_reset_wq;
static void ft260_chip_reset_done(struct ft260_chip *chip)
{
- mutex_lock(&ft260_chip_list_lock);
+ guard(mutex)(&ft260_chip_list_lock);
chip->reset_pending = false;
- mutex_unlock(&ft260_chip_list_lock);
}
static void ft260_reset_and_rebind(struct work_struct *ws)
@@ -2845,10 +2805,10 @@ static int ft260_schedule_reset(struct usb_interface *usbif)
return -ENOMEM;
}
- mutex_lock(&ft260_chip_list_lock);
- pending = chip->reset_pending;
- chip->reset_pending = true;
- mutex_unlock(&ft260_chip_list_lock);
+ scoped_guard(mutex, &ft260_chip_list_lock) {
+ pending = chip->reset_pending;
+ chip->reset_pending = true;
+ }
if (pending) {
ft260_chip_put(chip);
kfree(rw);
@@ -3092,9 +3052,8 @@ static void ft260_remove(struct hid_device *hdev)
* The hangup does not wait for a TIOCMGET or TIOCMSET
* that is running; they hold the lock while they use hdev.
*/
- mutex_lock(&dev->lock);
- dev->removed = true;
- mutex_unlock(&dev->lock);
+ scoped_guard(mutex, &dev->lock)
+ dev->removed = true;
if (dev->chip_mode & FT260_MODE_UART ||
dev->chip_mode == FT260_MODE_ALL ||
dev->chip_mode == FT260_MODE_BOTH)
--
2.43.0
prev parent reply other threads:[~2026-11-14 23:09 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-14 23:07 [PATCH v3 00/16] HID: ft260: add UART and GPIO support, plus I2C fixes Michael Zaidman
2026-11-14 23:07 ` [PATCH v3 01/16] HID: ft260: add serial driver Michael Zaidman
2026-11-14 23:07 ` [PATCH v3 02/16] HID: ft260: uart: fix the " Michael Zaidman
2026-11-14 23:07 ` [PATCH v3 03/16] HID: ft260: add GPIO support Michael Zaidman
2026-11-14 23:07 ` [PATCH v3 04/16] HID: ft260: i2c: reduce driver module loading time Michael Zaidman
2026-11-14 23:07 ` [PATCH v3 05/16] HID: ft260: fix sysfs store failure notice for big numbers Michael Zaidman
2026-11-14 23:07 ` [PATCH v3 06/16] HID: ft260: i2c: reduce bus-error message severity Michael Zaidman
2026-11-14 23:07 ` [PATCH v3 07/16] HID: ft260: uart: enable flow control Michael Zaidman
2026-11-14 23:07 ` [PATCH v3 08/16] HID: ft260: uart: add modem pins control via ioctl Michael Zaidman
2026-11-14 23:07 ` [PATCH v3 09/16] HID: ft260: group sysfs attrs per HID interface Michael Zaidman
2026-11-14 23:07 ` [PATCH v3 10/16] HID: ft260: i2c: fix large write transaction failure Michael Zaidman
2026-11-14 23:07 ` [PATCH v3 11/16] HID: ft260: workaround for TN_189 errata endpoint STALL after enumeration Michael Zaidman
2026-11-14 23:07 ` [PATCH v3 12/16] HID: ft260: i2c: abort in-flight transfers with STOP before reset Michael Zaidman
2026-11-14 23:07 ` [PATCH v3 13/16] HID: ft260: i2c: reject an I2C clock outside the supported range Michael Zaidman
2026-11-14 23:07 ` [PATCH v3 14/16] HID: ft260: i2c: fix i2c_reset sysfs store return value Michael Zaidman
2026-11-14 23:07 ` [PATCH v3 15/16] HID: ft260: i2c: recover a bus held by a slave Michael Zaidman
2026-11-14 23:08 ` Michael Zaidman [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261114230800.1344401-17-michael.zaidman@gmail.com \
--to=michael.zaidman@gmail.com \
--cc=bentiss@kernel.org \
--cc=brgl@kernel.org \
--cc=brunoceg1@gmail.com \
--cc=contact@christina-quast.de \
--cc=germain.hebert@ca.abb.com \
--cc=gregkh@linuxfoundation.org \
--cc=jikos@kernel.org \
--cc=jirislaby@kernel.org \
--cc=kernel-linux-20260610-80b7ab08@raman.v1.sg \
--cc=linusw@kernel.org \
--cc=linux-gpio@vger.kernel.org \
--cc=linux-i2c@vger.kernel.org \
--cc=linux-input@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-serial@vger.kernel.org \
--cc=rio@r26.me \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox