Merge branch 'improve-wwan-qcdm-compatibility-with-user-space-tools'

Daniele Palmas says:

====================
Improve wwan qcdm compatibility with user-space tools

Historically, Qualcomm diagnostic port was a serial device, so user-space
tools were developed using tty specific features. One of the most common
tool is, for example, ModemManager libqcdm, available at
https://gitlab.freedesktop.org/mobile-broadband/ModemManager
which requires tcgetattr/tcsetattr and the possibility to get exclusive
device access to properly work.

The wwan qcdm is not really a tty device, but, besides the lack of tty
functions, it behaves as a standard serial Qualcomm diagnostic port, so,
as c230035c2f ("net: wwan: core: implement terminal ioctls for AT port"),
this series add support for terminal ioctls also for qcdm ports and
implement the exclusive open mode feature to improve compatibility with
user-space tools.

This is an incremental change which should not affect the existing tools
using wwan which do not rely on the implemented features.
====================

Link: https://patch.msgid.link/20260724142909.3270824-1-dnlplm@gmail.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
Paolo Abeni 2026-07-30 11:05:17 +02:00
commit 49b5123182

View File

@ -42,6 +42,7 @@ static struct dentry *wwan_debugfs_dir;
/* WWAN port flags */
#define WWAN_PORT_TX_OFF 0
#define WWAN_PORT_EXCLUSIVE 1
/**
* struct wwan_device - The structure that defines a WWAN device
@ -748,6 +749,12 @@ static int wwan_port_op_start(struct wwan_port *port)
goto out_unlock;
}
if (test_bit(WWAN_PORT_EXCLUSIVE, &port->flags) &&
!capable(CAP_SYS_ADMIN)) {
ret = -EBUSY;
goto out_unlock;
}
/* If port is already started, don't start again */
if (!port->start_count)
ret = port->ops->start(port);
@ -769,6 +776,7 @@ static void wwan_port_op_stop(struct wwan_port *port)
if (port->ops)
port->ops->stop(port);
skb_queue_purge(&port->rxq);
clear_bit(WWAN_PORT_EXCLUSIVE, &port->flags);
}
mutex_unlock(&port->ops_lock);
}
@ -1031,6 +1039,22 @@ static long wwan_port_fops_at_ioctl(struct wwan_port *port, unsigned int cmd,
break;
}
case TIOCEXCL:
set_bit(WWAN_PORT_EXCLUSIVE, &port->flags);
break;
case TIOCNXCL:
clear_bit(WWAN_PORT_EXCLUSIVE, &port->flags);
break;
case TIOCGEXCL:
{
int excl = test_bit(WWAN_PORT_EXCLUSIVE, &port->flags);
ret = put_user(excl, (int __user *)arg);
break;
}
default:
ret = -ENOIOCTLCMD;
}
@ -1046,7 +1070,8 @@ static long wwan_port_fops_ioctl(struct file *filp, unsigned int cmd,
struct wwan_port *port = filp->private_data;
int res;
if (port->type == WWAN_PORT_AT) { /* AT port specific IOCTLs */
if (port->type == WWAN_PORT_AT || port->type == WWAN_PORT_QCDM) {
/* AT and QCDM port specific IOCTLs */
res = wwan_port_fops_at_ioctl(port, cmd, arg);
if (res != -ENOIOCTLCMD)
return res;