Re: uart_ioctl OOPS with irtty-sir

Jean Tourrilhes (jt@bougret.hpl.hp.com)
Tue, 8 Apr 2003 10:44:43 -0700


On Fri, Apr 04, 2003 at 10:25:35AM +0100, Russell King wrote:
> On Thu, Apr 03, 2003 at 05:34:05PM -0800, Jean Tourrilhes wrote:
> > Unfortunately, the irtty-sir driver, which is a TTY line
> > discipline and a network driver, need to be able to change the RTS and
> > DTR line from a kernel thread.
>
> I'd prefer if we added an tty API to allow line disciplines to read/set
> the modem control lines to the tty later, rather than having line
> disciplines play games with IOCTLs.

So, the patch has to look like what is below.
I've decided to use the internal set/clear API, because it
allow to ignore the default state of control line (all the troubles
with TIOCM_OUT2/TIOCM_OUT1 on various platforms), so it's definitely a
win.
I'm not too sure about locking. I guess the spinlock in
uart_update_mctrl() is probably good enough.
I was tempted to create the same API for setting the speed
(baud rate), but that may need to wait for another time.

As you can't use IrDA SIR with 2.5.X, would you mind giving a
look at the issue ? Feel free to forward as needed to get comments
from all the interested parties. Thanks in advance...

Have fun...

Jean

---------------------------------------------------------------

diff -u -p linux/include/linux/tty_driver.d0.h linux/include/linux/tty_driver.h
--- linux/include/linux/tty_driver.d0.h Tue Apr 8 09:56:21 2003
+++ linux/include/linux/tty_driver.h Tue Apr 8 10:09:09 2003
@@ -157,6 +157,8 @@ struct tty_driver {
int (*chars_in_buffer)(struct tty_struct *tty);
int (*ioctl)(struct tty_struct *tty, struct file * file,
unsigned int cmd, unsigned long arg);
+ int (*modem_ctrl)(struct tty_struct *tty,
+ unsigned int set, unsigned int clear);
void (*set_termios)(struct tty_struct *tty, struct termios * old);
void (*throttle)(struct tty_struct * tty);
void (*unthrottle)(struct tty_struct * tty);
diff -u -p linux/drivers/serial/core.d0.c linux/drivers/serial/core.c
--- linux/drivers/serial/core.d0.c Tue Apr 8 09:51:00 2003
+++ linux/drivers/serial/core.c Tue Apr 8 10:15:29 2003
@@ -1158,6 +1158,26 @@ uart_ioctl(struct tty_struct *tty, struc
return ret;
}

+/*
+ * Called by line disciplines to change the various modem control bits...
+ * Line disciplines are implemented within the kernel, and therefore
+ * we don't want them to use the ioctl function above.
+ * Jean II
+ */
+static int
+uart_modem_ctrl(struct tty_struct *tty, unsigned int set, unsigned int clear)
+{
+ struct uart_state *state = tty->driver_data;
+
+ /* Set new values, if any */
+ /* Locking will be done in there */
+ uart_update_mctrl(state->port, set, clear);
+
+ /* Return new value */
+ return state->port->ops->get_mctrl(state->port);
+}
+
+
static void uart_set_termios(struct tty_struct *tty, struct termios *old_termios)
{
struct uart_state *state = tty->driver_data;
@@ -2150,6 +2170,7 @@ int uart_register_driver(struct uart_dri
normal->chars_in_buffer = uart_chars_in_buffer;
normal->flush_buffer = uart_flush_buffer;
normal->ioctl = uart_ioctl;
+ normal->modem_ctrl = uart_modem_ctrl;
normal->throttle = uart_throttle;
normal->unthrottle = uart_unthrottle;
normal->send_xchar = uart_send_xchar;
diff -u -p linux/drivers/net/irda/irtty-sir.d0.c linux/drivers/net/irda/irtty-sir.c
--- linux/drivers/net/irda/irtty-sir.d0.c Tue Apr 8 09:46:54 2003
+++ linux/drivers/net/irda/irtty-sir.c Tue Apr 8 10:34:53 2003
@@ -180,32 +180,29 @@ static int irtty_change_speed(struct sir
static int irtty_set_dtr_rts(struct sir_dev *dev, int dtr, int rts)
{
struct sirtty_cb *priv = dev->priv;
- int arg = 0;
+ int set = 0;
+ int clear = 0;

ASSERT(priv != NULL, return -1;);
ASSERT(priv->magic == IRTTY_MAGIC, return -1;);

-#ifdef TIOCM_OUT2 /* Not defined for ARM */
- arg = TIOCM_OUT2;
-#endif
if (rts)
- arg |= TIOCM_RTS;
+ set |= TIOCM_RTS;
+ else
+ clear |= TIOCM_RTS;
if (dtr)
- arg |= TIOCM_DTR;
+ set |= TIOCM_DTR;
+ else
+ clear |= TIOCM_DTR;

/*
- * The ioctl() function, or actually set_modem_info() in serial.c
- * expects a pointer to the argument in user space. This is working
- * here because we are always called from the kIrDAd thread which
- * has set_fs(KERNEL_DS) permanently set. Therefore copy_from_user()
- * is happy with our arg-parameter being local here in kernel space.
+ * We can't use ioctl() because it expects a non-null file structure,
+ * and we don't have that here.
+ * This function is not yet defined for all tty driver, so
+ * let's be careful... Jean II
*/
-
- lock_kernel();
- if (priv->tty->driver.ioctl(priv->tty, NULL, TIOCMSET, (unsigned long) &arg)) {
- IRDA_DEBUG(2, "%s(), error doing ioctl!\n", __FUNCTION__);
- }
- unlock_kernel();
+ ASSERT(priv->tty->driver.modem_ctrl != NULL, return -1;);
+ priv->tty->driver.modem_ctrl(priv->tty, set, clear);

return 0;
}
diff -u -p linux/drivers/net/irda/sir_kthread.d0.c linux/drivers/net/irda/sir_kthread.c
--- linux/drivers/net/irda/sir_kthread.d0.c Mon Apr 7 18:56:28 2003
+++ linux/drivers/net/irda/sir_kthread.c Mon Apr 7 18:59:31 2003
@@ -151,6 +151,13 @@ static int irda_thread(void *startup)

while (irda_rq_queue.thread != NULL) {

+ /* We use TASK_INTERRUPTIBLE, rather than
+ * TASK_UNINTERRUPTIBLE. Andrew Morton made this
+ * change ; he told me that it is safe, because "signal
+ * blocking is now handled in daemonize()", he added
+ * that the problem is that "uninterruptible sleep
+ * contributes to load average", making user worry.
+ * Jean II */
set_task_state(current, TASK_INTERRUPTIBLE);
add_wait_queue(&irda_rq_queue.kick, &wait);
if (list_empty(&irda_rq_queue.request_list))
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/