From cf0cb1ae0273f0963a5d54c7ec4dde384863fac8 Mon Sep 17 00:00:00 2001 From: Martin Schiller Date: Thu, 1 Mar 2007 13:49:48 +0100 Subject: [PATCH] USB: RTS/DTR signal patch for airprime driver I encountered some problems with the airprime driver in use with a Novatel Merlin XU870: Closing an open Connection to e.g. /dev/ttyUSB0 doesn't reset the RTS/DTR lines of the Modem. Consequently, when I use minicom to establish a connection by "ATD*99#" the modem doesn't hang up even if i exit minicom and so I cannot reuse the modem unless I remove it and plug it in again. With the attached patch, the RTS/DTR lines are resetted on a close. The code was mainly taken from the option.c driver. --- drivers/usb/serial/airprime.c | 47 +++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/drivers/usb/serial/airprime.c b/drivers/usb/serial/airprime.c index 18816bf96a4..310a8b5f590 100644 --- a/drivers/usb/serial/airprime.c +++ b/drivers/usb/serial/airprime.c @@ -44,8 +44,43 @@ struct airprime_private { int outstanding_urbs; int throttled; struct urb *read_urbp[NUM_READ_URBS]; + + /* Settings for the port */ + int rts_state; /* Handshaking pins (outputs) */ + int dtr_state; + int cts_state; /* Handshaking pins (inputs) */ + int dsr_state; + int dcd_state; + int ri_state; }; +static int airprime_send_setup(struct usb_serial_port *port) +{ + struct usb_serial *serial = port->serial; + struct airprime_private *priv; + + dbg("%s", __FUNCTION__); + + if (port->number != 0) + return 0; + + priv = usb_get_serial_port_data(port); + + if (port->tty) { + int val = 0; + if (priv->dtr_state) + val |= 0x01; + if (priv->rts_state) + val |= 0x02; + + return usb_control_msg(serial->dev, + usb_rcvctrlpipe(serial->dev, 0), + 0x22,0x21,val,0,NULL,0,USB_CTRL_SET_TIMEOUT); + } + + return 0; +} + static void airprime_read_bulk_callback(struct urb *urb) { struct usb_serial_port *port = urb->context; @@ -118,6 +153,10 @@ static int airprime_open(struct usb_serial_port *port, struct file *filp) usb_set_serial_port_data(port, priv); } + /* Set some sane defaults */ + priv->rts_state = 1; + priv->dtr_state = 1; + for (i = 0; i < NUM_READ_URBS; ++i) { buffer = kmalloc(buffer_size, GFP_KERNEL); if (!buffer) { @@ -151,6 +190,9 @@ static int airprime_open(struct usb_serial_port *port, struct file *filp) /* remember this urb so we can kill it when the port is closed */ priv->read_urbp[i] = urb; } + + airprime_send_setup(port); + goto out; errout: @@ -176,6 +218,11 @@ static void airprime_close(struct usb_serial_port *port, struct file * filp) dbg("%s - port %d", __FUNCTION__, port->number); + priv->rts_state = 0; + priv->dtr_state = 0; + + airprime_send_setup(port); + for (i = 0; i < NUM_READ_URBS; ++i) { usb_kill_urb (priv->read_urbp[i]); kfree (priv->read_urbp[i]->transfer_buffer); -- 2.41.0