Re: [PATCH net-next v2 2/2] net: wwan: add exclusive open mode capability to AT and QCDM ports
From: Loic Poulain <loic.poulain@oss.qualcomm.com>
Date: 2026-07-22 09:41:29
On Wed, Jul 22, 2026 at 11:10 AM Daniele Palmas [off-list ref] wrote:
quoted hunk ↗ jump to hunk
Add exclusive open mode capability to AT and QCDM ports to improve compatibility with user-space tools using the Qualcomm diagnostic device (e.g. libqcdm). Signed-off-by: Daniele Palmas <redacted> --- drivers/net/wwan/wwan_core.c | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-)diff --git a/drivers/net/wwan/wwan_core.c b/drivers/net/wwan/wwan_core.c index 8168239e52c3..8acb09dcb83a 100644 --- a/drivers/net/wwan/wwan_core.c +++ b/drivers/net/wwan/wwan_core.c@@ -22,6 +22,7 @@ #include <linux/termios.h> #include <linux/gnss.h> #include <linux/wwan.h> +#include <linux/tty.h> #include <net/rtnetlink.h> #include <uapi/linux/wwan.h>@@ -79,7 +80,7 @@ struct wwan_device { * @data_lock: Port specific data access serialization * @headroom_len: SKB reserved headroom size * @frag_len: Length to fragment packet - * @at_data: AT port specific data + * @at_data: AT/QCDM port specific data * @gnss: Pointer to GNSS device associated with this port */ struct wwan_port {@@ -98,6 +99,7 @@ struct wwan_port { struct { struct ktermios termios; int mdmbits; + unsigned long flags; } at_data; struct gnss_device *gnss; };@@ -748,6 +750,14 @@ static int wwan_port_op_start(struct wwan_port *port) goto out_unlock; } + /* Check exclusive open mode for AT and QCDM ports */ + if ((port->type == WWAN_PORT_AT || port->type == WWAN_PORT_QCDM) && + test_bit(TTY_EXCLUSIVE, &port->at_data.flags) && + !capable(CAP_SYS_ADMIN)) { + ret = -EBUSY; + goto out_unlock; + }
I would recommend simplifying this by relying on the already existing wwan_port flag introducing a WWAN_PORT_EXCLUSIVE. This would also eliminate the need to check the port type in the condition above.
quoted hunk ↗ jump to hunk
+ /* If port is already started, don't start again */ if (!port->start_count) ret = port->ops->start(port);@@ -769,6 +779,8 @@ static void wwan_port_op_stop(struct wwan_port *port) if (port->ops) port->ops->stop(port); skb_queue_purge(&port->rxq); + if (port->type == WWAN_PORT_AT || port->type == WWAN_PORT_QCDM) + clear_bit(TTY_EXCLUSIVE, &port->at_data.flags); } mutex_unlock(&port->ops_lock); }@@ -1031,6 +1043,22 @@ static long wwan_port_fops_at_ioctl(struct wwan_port *port, unsigned int cmd, break; } + case TIOCEXCL: + set_bit(TTY_EXCLUSIVE, &port->at_data.flags); + break; + + case TIOCNXCL: + clear_bit(TTY_EXCLUSIVE, &port->at_data.flags); + break; + + case TIOCGEXCL: + { + int excl = test_bit(TTY_EXCLUSIVE, &port->at_data.flags); + + ret = put_user(excl, (int __user *)arg); + break; + } + default: ret = -ENOIOCTLCMD; } --2.43.0