Skip to content

Commit

Permalink
USB: ir-usb: fix set_termios race
Browse files Browse the repository at this point in the history
Use dynamically allocated urb for baudrate changes rather than
unconditionally submitting the port write urb which may already be in
use.

Compile-only tested.

Signed-off-by: Johan Hovold <jhovold@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
  • Loading branch information
Johan Hovold authored and Greg Kroah-Hartman committed May 20, 2010
1 parent 6f6ed69 commit df66e8a
Showing 1 changed file with 47 additions and 16 deletions.
63 changes: 47 additions & 16 deletions drivers/usb/serial/ir-usb.c
Original file line number Diff line number Diff line change
Expand Up @@ -469,9 +469,23 @@ static void ir_read_bulk_callback(struct urb *urb)
return;
}

static void ir_set_termios_callback(struct urb *urb)
{
struct usb_serial_port *port = urb->context;
int status = urb->status;

dbg("%s - port %d", __func__, port->number);

kfree(urb->transfer_buffer);

if (status)
dbg("%s - non-zero urb status: %d", __func__, status);
}

static void ir_set_termios(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios *old_termios)
{
struct urb *urb;
unsigned char *transfer_buffer;
int result;
speed_t baud;
Expand Down Expand Up @@ -525,35 +539,52 @@ static void ir_set_termios(struct tty_struct *tty,
else
ir_xbof = ir_xbof_change(xbof) ;

/* FIXME need to check to see if our write urb is busy right
* now, or use a urb pool.
*
/* Only speed changes are supported */
tty_termios_copy_hw(tty->termios, old_termios);
tty_encode_baud_rate(tty, baud, baud);

/*
* send the baud change out on an "empty" data packet
*/
transfer_buffer = port->write_urb->transfer_buffer;
urb = usb_alloc_urb(0, GFP_KERNEL);
if (!urb) {
dev_err(&port->dev, "%s - no more urbs\n", __func__);
return;
}
transfer_buffer = kmalloc(1, GFP_KERNEL);
if (!transfer_buffer) {
dev_err(&port->dev, "%s - out of memory\n", __func__);
goto err_buf;
}

*transfer_buffer = ir_xbof | ir_baud;

usb_fill_bulk_urb(
port->write_urb,
urb,
port->serial->dev,
usb_sndbulkpipe(port->serial->dev,
port->bulk_out_endpointAddress),
port->write_urb->transfer_buffer,
transfer_buffer,
1,
ir_write_bulk_callback,
ir_set_termios_callback,
port);

port->write_urb->transfer_flags = URB_ZERO_PACKET;
urb->transfer_flags = URB_ZERO_PACKET;

result = usb_submit_urb(port->write_urb, GFP_KERNEL);
if (result)
dev_err(&port->dev,
"%s - failed submitting write urb, error %d\n",
__func__, result);
result = usb_submit_urb(urb, GFP_KERNEL);
if (result) {
dev_err(&port->dev, "%s - failed to submit urb: %d\n",
__func__, result);
goto err_subm;
}

/* Only speed changes are supported */
tty_termios_copy_hw(tty->termios, old_termios);
tty_encode_baud_rate(tty, baud, baud);
usb_free_urb(urb);

return;
err_subm:
kfree(transfer_buffer);
err_buf:
usb_free_urb(urb);
}

static int __init ir_init(void)
Expand Down

0 comments on commit df66e8a

Please sign in to comment.