diff options
author | Johan Hovold <jhovold@gmail.com> | 2010-05-13 15:02:02 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2010-05-20 16:21:45 -0400 |
commit | df66e8a2afef506e303f931741193c7cf8fe0794 (patch) | |
tree | 45065263f4be47158b16204b3e1d1bedf547ce23 /drivers/usb/serial/ir-usb.c | |
parent | 6f6ed696945c9c98fb6e0def32d29411d958a6fa (diff) |
USB: ir-usb: fix set_termios race
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>
Diffstat (limited to 'drivers/usb/serial/ir-usb.c')
-rw-r--r-- | drivers/usb/serial/ir-usb.c | 63 |
1 files changed, 47 insertions, 16 deletions
diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c index aaebb70aca59..d8490eaeb234 100644 --- a/drivers/usb/serial/ir-usb.c +++ b/drivers/usb/serial/ir-usb.c | |||
@@ -469,9 +469,23 @@ static void ir_read_bulk_callback(struct urb *urb) | |||
469 | return; | 469 | return; |
470 | } | 470 | } |
471 | 471 | ||
472 | static void ir_set_termios_callback(struct urb *urb) | ||
473 | { | ||
474 | struct usb_serial_port *port = urb->context; | ||
475 | int status = urb->status; | ||
476 | |||
477 | dbg("%s - port %d", __func__, port->number); | ||
478 | |||
479 | kfree(urb->transfer_buffer); | ||
480 | |||
481 | if (status) | ||
482 | dbg("%s - non-zero urb status: %d", __func__, status); | ||
483 | } | ||
484 | |||
472 | static void ir_set_termios(struct tty_struct *tty, | 485 | static void ir_set_termios(struct tty_struct *tty, |
473 | struct usb_serial_port *port, struct ktermios *old_termios) | 486 | struct usb_serial_port *port, struct ktermios *old_termios) |
474 | { | 487 | { |
488 | struct urb *urb; | ||
475 | unsigned char *transfer_buffer; | 489 | unsigned char *transfer_buffer; |
476 | int result; | 490 | int result; |
477 | speed_t baud; | 491 | speed_t baud; |
@@ -525,35 +539,52 @@ static void ir_set_termios(struct tty_struct *tty, | |||
525 | else | 539 | else |
526 | ir_xbof = ir_xbof_change(xbof) ; | 540 | ir_xbof = ir_xbof_change(xbof) ; |
527 | 541 | ||
528 | /* FIXME need to check to see if our write urb is busy right | 542 | /* Only speed changes are supported */ |
529 | * now, or use a urb pool. | 543 | tty_termios_copy_hw(tty->termios, old_termios); |
530 | * | 544 | tty_encode_baud_rate(tty, baud, baud); |
545 | |||
546 | /* | ||
531 | * send the baud change out on an "empty" data packet | 547 | * send the baud change out on an "empty" data packet |
532 | */ | 548 | */ |
533 | transfer_buffer = port->write_urb->transfer_buffer; | 549 | urb = usb_alloc_urb(0, GFP_KERNEL); |
550 | if (!urb) { | ||
551 | dev_err(&port->dev, "%s - no more urbs\n", __func__); | ||
552 | return; | ||
553 | } | ||
554 | transfer_buffer = kmalloc(1, GFP_KERNEL); | ||
555 | if (!transfer_buffer) { | ||
556 | dev_err(&port->dev, "%s - out of memory\n", __func__); | ||
557 | goto err_buf; | ||
558 | } | ||
559 | |||
534 | *transfer_buffer = ir_xbof | ir_baud; | 560 | *transfer_buffer = ir_xbof | ir_baud; |
535 | 561 | ||
536 | usb_fill_bulk_urb( | 562 | usb_fill_bulk_urb( |
537 | port->write_urb, | 563 | urb, |
538 | port->serial->dev, | 564 | port->serial->dev, |
539 | usb_sndbulkpipe(port->serial->dev, | 565 | usb_sndbulkpipe(port->serial->dev, |
540 | port->bulk_out_endpointAddress), | 566 | port->bulk_out_endpointAddress), |
541 | port->write_urb->transfer_buffer, | 567 | transfer_buffer, |
542 | 1, | 568 | 1, |
543 | ir_write_bulk_callback, | 569 | ir_set_termios_callback, |
544 | port); | 570 | port); |
545 | 571 | ||
546 | port->write_urb->transfer_flags = URB_ZERO_PACKET; | 572 | urb->transfer_flags = URB_ZERO_PACKET; |
547 | 573 | ||
548 | result = usb_submit_urb(port->write_urb, GFP_KERNEL); | 574 | result = usb_submit_urb(urb, GFP_KERNEL); |
549 | if (result) | 575 | if (result) { |
550 | dev_err(&port->dev, | 576 | dev_err(&port->dev, "%s - failed to submit urb: %d\n", |
551 | "%s - failed submitting write urb, error %d\n", | 577 | __func__, result); |
552 | __func__, result); | 578 | goto err_subm; |
579 | } | ||
553 | 580 | ||
554 | /* Only speed changes are supported */ | 581 | usb_free_urb(urb); |
555 | tty_termios_copy_hw(tty->termios, old_termios); | 582 | |
556 | tty_encode_baud_rate(tty, baud, baud); | 583 | return; |
584 | err_subm: | ||
585 | kfree(transfer_buffer); | ||
586 | err_buf: | ||
587 | usb_free_urb(urb); | ||
557 | } | 588 | } |
558 | 589 | ||
559 | static int __init ir_init(void) | 590 | static int __init ir_init(void) |