Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cf0cb1ae authored by Martin Schiller's avatar Martin Schiller Committed by Greg Kroah-Hartman
Browse files

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.
parent 12bdbe03
Loading
Loading
Loading
Loading
+47 −0
Original line number Diff line number Diff line
@@ -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);