From: Dominique Larchey-Wendling <Dominique.Larchey-Wendling@loria.fr>
To: linux-serial@vger.kernel.org
Subject: New IOCTL for Modem Control Lines monitoring
Date: Thu, 25 Jan 2007 18:09:33 +0100 [thread overview]
Message-ID: <45B8E44D.5050005@loria.fr> (raw)
In kernel 2.6 (file drivers/serial/serial_core.c), there exists 2 IOCTL
for receiving signals over the modem control lines
TIOCMIWAIT (function uart_wait_modem_status) for waiting for a change
on the modem status lines.
TIOCGICOUNT (uart_get_count) to get the current state of the modem
status lines.
While these IOCTL may be helpful to use the serial port as a general
serial communication device over modem control lines like in
the following (and quite old) discussion
http://www.mail-archive.com/linux-serial@vger.rutgers.edu/msg00407.html
I find a kind of "design" flaw with the 2 IOCTL for such a goal.
Indeed, it is possible that a modem status change occurs in between
ioctl(TIOCGICOUNT) and ioctl(TIOCMIWAIT) possibly locking a
communication because the last call would miss the status change
necessary to trigger a response. Indeed ioctl(TIOCMIWAIT) cannot
detect a change occurring before its call.
Even tough such an event would have a low probability to occur
if the 2 ioctl are close enough, it is still possible. This is
a race condition (outside the kernel but possibly locking some
process).
I propose the introduction of a new ioctl to solve this race,
implemented through the NEW function uart_wait_new_status associated
to a NEW ioctl.
The idea is that this new call would detect a change not compared
to the status at the beginning of the call but compared to some
previously recorded state. This way, the new ioctl would not
miss a status change, even if it occurs before the call to the
ioctl.
Could it be considered for inclusion in the kernel ?
It does not change any existing behavior. However it
does need a new ioctl name/number.
Thanks in advance for any comment
Dominique Larchey-Wendling
CNRS, France
-------------------------------------------------
Code to include in drivers/serial/serial_core.c
-------------------------------------------------
/*
* Wait until any NEW signal is received on some selected
* modem inputs lines (DCD,RI,DSR,CTS), compared to some
* previously considered state.
* If asked to wait on none, simply returns the current
* status
*/
static int
uart_wait_new_status(struct uart_state *state, struct
serial_icounter_struct __user *icnt)
{
struct uart_port *port = state->port;
DECLARE_WAITQUEUE(wait, current);
struct serial_icounter_struct icount;
struct uart_icount cstart, cnow;
unsigned int mask, mctrl;
int ret;
if (copy_from_user(&icount, icnt, sizeof(icount)))
return -EFAULT;
cstart.cts = icount.cts;
cstart.dsr = icount.dsr;
cstart.rng = icount.rng;
cstart.dcd = icount.dcd;
cstart.rx = icount.rx;
cstart.tx = icount.tx;
cstart.frame = icount.frame;
cstart.overrun = icount.overrun;
cstart.parity = icount.parity;
cstart.buf_overrun = icount.buf_overrun;
/* if mask == 0 just simulate behavior of TIOCGICOUNT
*/
mask = (unsigned) icount.reserved[0];
/* enable Modem Status Interrupts in case not already done
*/
spin_lock_irq(&port->lock);
port->ops->enable_ms(port);
spin_unlock_irq(&port->lock);
add_wait_queue(&state->info->delta_msr_wait, &wait);
for (;;) {
spin_lock_irq(&port->lock);
mctrl = port->ops->get_mctrl(port);
memcpy(&cnow, &port->icount, sizeof(struct uart_icount));
spin_unlock_irq(&port->lock);
set_current_state(TASK_INTERRUPTIBLE);
if (((mask & TIOCM_RNG) && (cnow.rng != cstart.rng)) ||
((mask & TIOCM_DSR) && (cnow.dsr != cstart.dsr)) ||
((mask & TIOCM_CAR) && (cnow.dcd != cstart.dcd)) ||
((mask & TIOCM_CTS) && (cnow.cts != cstart.cts)) ||
(mask == 0))
{
ret = 0;
break;
}
schedule();
/* see if a signal did it */
if (signal_pending(current)) {
ret = -ERESTARTSYS;
break;
}
}
current->state = TASK_RUNNING;
remove_wait_queue(&state->info->delta_msr_wait, &wait);
if (ret < 0) return ret;
/* we got our (new) state, transfer to user space
*/
icount.cts = cnow.cts;
icount.dsr = cnow.dsr;
icount.rng = cnow.rng;
icount.dcd = cnow.dcd;
icount.rx = cnow.rx;
icount.tx = cnow.tx;
icount.frame = cnow.frame;
icount.overrun = cnow.overrun;
icount.parity = cnow.parity;
icount.brk = cnow.brk;
icount.buf_overrun = cnow.buf_overrun;
icount.reserved[0] = mctrl;
return copy_to_user(icnt, &icount, sizeof(icount)) ? -EFAULT : 0;
}
next reply other threads:[~2007-01-25 17:19 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-01-25 17:09 Dominique Larchey-Wendling [this message]
2007-01-25 18:34 ` New IOCTL for Modem Control Lines monitoring Tosoni
2007-01-25 19:00 ` Dominique Larchey
2007-01-30 2:39 ` Theodore Tso
2007-01-30 17:19 ` Dominique Larchey-Wendling
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=45B8E44D.5050005@loria.fr \
--to=dominique.larchey-wendling@loria.fr \
--cc=linux-serial@vger.kernel.org \
/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;
as well as URLs for NNTP newsgroup(s).