diff options
author | Alan Cox <alan@redhat.com> | 2008-07-22 06:09:07 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-07-22 16:03:22 -0400 |
commit | 95da310e66ee8090119596c70ca8432e57f9a97f (patch) | |
tree | 7f18c30e9c9ad4d7d53df6453fa338be06f09a85 /drivers/usb/serial/oti6858.c | |
parent | 1aa3692da57c773e5c76de55c5c4a953962d360e (diff) |
usb_serial: API all change
USB serial likes to use port->tty back pointers for the real work it does and
to do so without any actual locking. Unfortunately when you consider hangup
events, hangup/parallel reopen or even worse hangup followed by parallel close
events the tty->port and port->tty pointers are not guaranteed to be the same
as port->tty is the active tty while tty->port is the port the tty may or
may not still be attached to.
So rework the entire API to pass the tty struct. For console cases we need
to pass both for now. This shows up multiple drivers that immediately crash
with USB console some of which have been fixed in the process.
Longer term we need a proper tty as console abstraction
Signed-off-by: Alan Cox <alan@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/usb/serial/oti6858.c')
-rw-r--r-- | drivers/usb/serial/oti6858.c | 119 |
1 files changed, 48 insertions, 71 deletions
diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c index a9625c180dc3..069d276a5276 100644 --- a/drivers/usb/serial/oti6858.c +++ b/drivers/usb/serial/oti6858.c | |||
@@ -140,22 +140,23 @@ struct oti6858_control_pkt { | |||
140 | && ((a)->frame_fmt == (priv)->pending_setup.frame_fmt) ) | 140 | && ((a)->frame_fmt == (priv)->pending_setup.frame_fmt) ) |
141 | 141 | ||
142 | /* function prototypes */ | 142 | /* function prototypes */ |
143 | static int oti6858_open(struct usb_serial_port *port, struct file *filp); | 143 | static int oti6858_open(struct tty_struct *tty, |
144 | static void oti6858_close(struct usb_serial_port *port, struct file *filp); | 144 | struct usb_serial_port *port, struct file *filp); |
145 | static void oti6858_set_termios(struct usb_serial_port *port, | 145 | static void oti6858_close(struct tty_struct *tty, |
146 | struct ktermios *old); | 146 | struct usb_serial_port *port, struct file *filp); |
147 | static int oti6858_ioctl(struct usb_serial_port *port, struct file *file, | 147 | static void oti6858_set_termios(struct tty_struct *tty, |
148 | struct usb_serial_port *port, struct ktermios *old); | ||
149 | static int oti6858_ioctl(struct tty_struct *tty, struct file *file, | ||
148 | unsigned int cmd, unsigned long arg); | 150 | unsigned int cmd, unsigned long arg); |
149 | static void oti6858_read_int_callback(struct urb *urb); | 151 | static void oti6858_read_int_callback(struct urb *urb); |
150 | static void oti6858_read_bulk_callback(struct urb *urb); | 152 | static void oti6858_read_bulk_callback(struct urb *urb); |
151 | static void oti6858_write_bulk_callback(struct urb *urb); | 153 | static void oti6858_write_bulk_callback(struct urb *urb); |
152 | static int oti6858_write(struct usb_serial_port *port, | 154 | static int oti6858_write(struct tty_struct *tty, struct usb_serial_port *port, |
153 | const unsigned char *buf, int count); | 155 | const unsigned char *buf, int count); |
154 | static int oti6858_write_room(struct usb_serial_port *port); | 156 | static int oti6858_write_room(struct tty_struct *tty); |
155 | static void oti6858_break_ctl(struct usb_serial_port *port, int break_state); | 157 | static int oti6858_chars_in_buffer(struct tty_struct *tty); |
156 | static int oti6858_chars_in_buffer(struct usb_serial_port *port); | 158 | static int oti6858_tiocmget(struct tty_struct *tty, struct file *file); |
157 | static int oti6858_tiocmget(struct usb_serial_port *port, struct file *file); | 159 | static int oti6858_tiocmset(struct tty_struct *tty, struct file *file, |
158 | static int oti6858_tiocmset(struct usb_serial_port *port, struct file *file, | ||
159 | unsigned int set, unsigned int clear); | 160 | unsigned int set, unsigned int clear); |
160 | static int oti6858_startup(struct usb_serial *serial); | 161 | static int oti6858_startup(struct usb_serial *serial); |
161 | static void oti6858_shutdown(struct usb_serial *serial); | 162 | static void oti6858_shutdown(struct usb_serial *serial); |
@@ -184,7 +185,6 @@ static struct usb_serial_driver oti6858_device = { | |||
184 | .close = oti6858_close, | 185 | .close = oti6858_close, |
185 | .write = oti6858_write, | 186 | .write = oti6858_write, |
186 | .ioctl = oti6858_ioctl, | 187 | .ioctl = oti6858_ioctl, |
187 | .break_ctl = oti6858_break_ctl, | ||
188 | .set_termios = oti6858_set_termios, | 188 | .set_termios = oti6858_set_termios, |
189 | .tiocmget = oti6858_tiocmget, | 189 | .tiocmget = oti6858_tiocmget, |
190 | .tiocmset = oti6858_tiocmset, | 190 | .tiocmset = oti6858_tiocmset, |
@@ -395,7 +395,7 @@ static int oti6858_startup(struct usb_serial *serial) | |||
395 | return -ENOMEM; | 395 | return -ENOMEM; |
396 | } | 396 | } |
397 | 397 | ||
398 | static int oti6858_write(struct usb_serial_port *port, | 398 | static int oti6858_write(struct tty_struct *tty, struct usb_serial_port *port, |
399 | const unsigned char *buf, int count) | 399 | const unsigned char *buf, int count) |
400 | { | 400 | { |
401 | struct oti6858_private *priv = usb_get_serial_port_data(port); | 401 | struct oti6858_private *priv = usb_get_serial_port_data(port); |
@@ -413,8 +413,9 @@ static int oti6858_write(struct usb_serial_port *port, | |||
413 | return count; | 413 | return count; |
414 | } | 414 | } |
415 | 415 | ||
416 | static int oti6858_write_room(struct usb_serial_port *port) | 416 | static int oti6858_write_room(struct tty_struct *tty) |
417 | { | 417 | { |
418 | struct usb_serial_port *port = tty->driver_data; | ||
418 | struct oti6858_private *priv = usb_get_serial_port_data(port); | 419 | struct oti6858_private *priv = usb_get_serial_port_data(port); |
419 | int room = 0; | 420 | int room = 0; |
420 | unsigned long flags; | 421 | unsigned long flags; |
@@ -428,8 +429,9 @@ static int oti6858_write_room(struct usb_serial_port *port) | |||
428 | return room; | 429 | return room; |
429 | } | 430 | } |
430 | 431 | ||
431 | static int oti6858_chars_in_buffer(struct usb_serial_port *port) | 432 | static int oti6858_chars_in_buffer(struct tty_struct *tty) |
432 | { | 433 | { |
434 | struct usb_serial_port *port = tty->driver_data; | ||
433 | struct oti6858_private *priv = usb_get_serial_port_data(port); | 435 | struct oti6858_private *priv = usb_get_serial_port_data(port); |
434 | int chars = 0; | 436 | int chars = 0; |
435 | unsigned long flags; | 437 | unsigned long flags; |
@@ -443,8 +445,8 @@ static int oti6858_chars_in_buffer(struct usb_serial_port *port) | |||
443 | return chars; | 445 | return chars; |
444 | } | 446 | } |
445 | 447 | ||
446 | static void oti6858_set_termios(struct usb_serial_port *port, | 448 | static void oti6858_set_termios(struct tty_struct *tty, |
447 | struct ktermios *old_termios) | 449 | struct usb_serial_port *port, struct ktermios *old_termios) |
448 | { | 450 | { |
449 | struct oti6858_private *priv = usb_get_serial_port_data(port); | 451 | struct oti6858_private *priv = usb_get_serial_port_data(port); |
450 | unsigned long flags; | 452 | unsigned long flags; |
@@ -455,22 +457,22 @@ static void oti6858_set_termios(struct usb_serial_port *port, | |||
455 | 457 | ||
456 | dbg("%s(port = %d)", __func__, port->number); | 458 | dbg("%s(port = %d)", __func__, port->number); |
457 | 459 | ||
458 | if (!port->tty || !port->tty->termios) { | 460 | if (!tty) { |
459 | dbg("%s(): no tty structures", __func__); | 461 | dbg("%s(): no tty structures", __func__); |
460 | return; | 462 | return; |
461 | } | 463 | } |
462 | 464 | ||
463 | spin_lock_irqsave(&priv->lock, flags); | 465 | spin_lock_irqsave(&priv->lock, flags); |
464 | if (!priv->flags.termios_initialized) { | 466 | if (!priv->flags.termios_initialized) { |
465 | *(port->tty->termios) = tty_std_termios; | 467 | *(tty->termios) = tty_std_termios; |
466 | port->tty->termios->c_cflag = B38400 | CS8 | CREAD | HUPCL | CLOCAL; | 468 | tty->termios->c_cflag = B38400 | CS8 | CREAD | HUPCL | CLOCAL; |
469 | tty->termios->c_ispeed = 38400; | ||
470 | tty->termios->c_ospeed = 38400; | ||
467 | priv->flags.termios_initialized = 1; | 471 | priv->flags.termios_initialized = 1; |
468 | port->tty->termios->c_ispeed = 38400; | ||
469 | port->tty->termios->c_ospeed = 38400; | ||
470 | } | 472 | } |
471 | spin_unlock_irqrestore(&priv->lock, flags); | 473 | spin_unlock_irqrestore(&priv->lock, flags); |
472 | 474 | ||
473 | cflag = port->tty->termios->c_cflag; | 475 | cflag = tty->termios->c_cflag; |
474 | 476 | ||
475 | spin_lock_irqsave(&priv->lock, flags); | 477 | spin_lock_irqsave(&priv->lock, flags); |
476 | divisor = priv->pending_setup.divisor; | 478 | divisor = priv->pending_setup.divisor; |
@@ -500,7 +502,7 @@ static void oti6858_set_termios(struct usb_serial_port *port, | |||
500 | * guarantee that any other baud rate will work (especially | 502 | * guarantee that any other baud rate will work (especially |
501 | * the higher ones) | 503 | * the higher ones) |
502 | */ | 504 | */ |
503 | br = tty_get_baud_rate(port->tty); | 505 | br = tty_get_baud_rate(tty); |
504 | if (br == 0) { | 506 | if (br == 0) { |
505 | divisor = 0; | 507 | divisor = 0; |
506 | } else { | 508 | } else { |
@@ -511,7 +513,7 @@ static void oti6858_set_termios(struct usb_serial_port *port, | |||
511 | new_divisor = (96000000 + 8 * br) / (16 * br); | 513 | new_divisor = (96000000 + 8 * br) / (16 * br); |
512 | real_br = 96000000 / (16 * new_divisor); | 514 | real_br = 96000000 / (16 * new_divisor); |
513 | divisor = cpu_to_le16(new_divisor); | 515 | divisor = cpu_to_le16(new_divisor); |
514 | tty_encode_baud_rate(port->tty, real_br, real_br); | 516 | tty_encode_baud_rate(tty, real_br, real_br); |
515 | } | 517 | } |
516 | 518 | ||
517 | frame_fmt &= ~FMT_STOP_BITS_MASK; | 519 | frame_fmt &= ~FMT_STOP_BITS_MASK; |
@@ -564,7 +566,8 @@ static void oti6858_set_termios(struct usb_serial_port *port, | |||
564 | spin_unlock_irqrestore(&priv->lock, flags); | 566 | spin_unlock_irqrestore(&priv->lock, flags); |
565 | } | 567 | } |
566 | 568 | ||
567 | static int oti6858_open(struct usb_serial_port *port, struct file *filp) | 569 | static int oti6858_open(struct tty_struct *tty, |
570 | struct usb_serial_port *port, struct file *filp) | ||
568 | { | 571 | { |
569 | struct oti6858_private *priv = usb_get_serial_port_data(port); | 572 | struct oti6858_private *priv = usb_get_serial_port_data(port); |
570 | struct ktermios tmp_termios; | 573 | struct ktermios tmp_termios; |
@@ -578,7 +581,7 @@ static int oti6858_open(struct usb_serial_port *port, struct file *filp) | |||
578 | usb_clear_halt(serial->dev, port->write_urb->pipe); | 581 | usb_clear_halt(serial->dev, port->write_urb->pipe); |
579 | usb_clear_halt(serial->dev, port->read_urb->pipe); | 582 | usb_clear_halt(serial->dev, port->read_urb->pipe); |
580 | 583 | ||
581 | if (port->open_count != 1) | 584 | if (port->port.count != 1) |
582 | return 0; | 585 | return 0; |
583 | 586 | ||
584 | if ((buf = kmalloc(OTI6858_CTRL_PKT_SIZE, GFP_KERNEL)) == NULL) { | 587 | if ((buf = kmalloc(OTI6858_CTRL_PKT_SIZE, GFP_KERNEL)) == NULL) { |
@@ -617,18 +620,19 @@ static int oti6858_open(struct usb_serial_port *port, struct file *filp) | |||
617 | if (result != 0) { | 620 | if (result != 0) { |
618 | dev_err(&port->dev, "%s(): usb_submit_urb() failed" | 621 | dev_err(&port->dev, "%s(): usb_submit_urb() failed" |
619 | " with error %d\n", __func__, result); | 622 | " with error %d\n", __func__, result); |
620 | oti6858_close(port, NULL); | 623 | oti6858_close(tty, port, NULL); |
621 | return -EPROTO; | 624 | return -EPROTO; |
622 | } | 625 | } |
623 | 626 | ||
624 | /* setup termios */ | 627 | /* setup termios */ |
625 | if (port->tty) | 628 | if (tty) |
626 | oti6858_set_termios(port, &tmp_termios); | 629 | oti6858_set_termios(tty, port, &tmp_termios); |
627 | 630 | ||
628 | return 0; | 631 | return 0; |
629 | } | 632 | } |
630 | 633 | ||
631 | static void oti6858_close(struct usb_serial_port *port, struct file *filp) | 634 | static void oti6858_close(struct tty_struct *tty, |
635 | struct usb_serial_port *port, struct file *filp) | ||
632 | { | 636 | { |
633 | struct oti6858_private *priv = usb_get_serial_port_data(port); | 637 | struct oti6858_private *priv = usb_get_serial_port_data(port); |
634 | unsigned long flags; | 638 | unsigned long flags; |
@@ -641,7 +645,7 @@ static void oti6858_close(struct usb_serial_port *port, struct file *filp) | |||
641 | spin_lock_irqsave(&priv->lock, flags); | 645 | spin_lock_irqsave(&priv->lock, flags); |
642 | timeout = 30 * HZ; /* PL2303_CLOSING_WAIT */ | 646 | timeout = 30 * HZ; /* PL2303_CLOSING_WAIT */ |
643 | init_waitqueue_entry(&wait, current); | 647 | init_waitqueue_entry(&wait, current); |
644 | add_wait_queue(&port->tty->write_wait, &wait); | 648 | add_wait_queue(&tty->write_wait, &wait); |
645 | dbg("%s(): entering wait loop", __func__); | 649 | dbg("%s(): entering wait loop", __func__); |
646 | for (;;) { | 650 | for (;;) { |
647 | set_current_state(TASK_INTERRUPTIBLE); | 651 | set_current_state(TASK_INTERRUPTIBLE); |
@@ -654,7 +658,7 @@ static void oti6858_close(struct usb_serial_port *port, struct file *filp) | |||
654 | spin_lock_irqsave(&priv->lock, flags); | 658 | spin_lock_irqsave(&priv->lock, flags); |
655 | } | 659 | } |
656 | set_current_state(TASK_RUNNING); | 660 | set_current_state(TASK_RUNNING); |
657 | remove_wait_queue(&port->tty->write_wait, &wait); | 661 | remove_wait_queue(&tty->write_wait, &wait); |
658 | dbg("%s(): after wait loop", __func__); | 662 | dbg("%s(): after wait loop", __func__); |
659 | 663 | ||
660 | /* clear out any remaining data in the buffer */ | 664 | /* clear out any remaining data in the buffer */ |
@@ -669,7 +673,7 @@ static void oti6858_close(struct usb_serial_port *port, struct file *filp) | |||
669 | /* data is in the buffer to compute a delay */ | 673 | /* data is in the buffer to compute a delay */ |
670 | /* that is not unnecessarily long) */ | 674 | /* that is not unnecessarily long) */ |
671 | /* FIXME | 675 | /* FIXME |
672 | bps = tty_get_baud_rate(port->tty); | 676 | bps = tty_get_baud_rate(tty); |
673 | if (bps > 1200) | 677 | if (bps > 1200) |
674 | timeout = max((HZ*2560)/bps,HZ/10); | 678 | timeout = max((HZ*2560)/bps,HZ/10); |
675 | else | 679 | else |
@@ -690,7 +694,7 @@ static void oti6858_close(struct usb_serial_port *port, struct file *filp) | |||
690 | usb_kill_urb(port->interrupt_in_urb); | 694 | usb_kill_urb(port->interrupt_in_urb); |
691 | 695 | ||
692 | /* | 696 | /* |
693 | if (port->tty && (port->tty->termios->c_cflag) & HUPCL) { | 697 | if (tty && (tty->termios->c_cflag) & HUPCL) { |
694 | // drop DTR and RTS | 698 | // drop DTR and RTS |
695 | spin_lock_irqsave(&priv->lock, flags); | 699 | spin_lock_irqsave(&priv->lock, flags); |
696 | priv->pending_setup.control &= ~CONTROL_MASK; | 700 | priv->pending_setup.control &= ~CONTROL_MASK; |
@@ -699,9 +703,10 @@ static void oti6858_close(struct usb_serial_port *port, struct file *filp) | |||
699 | */ | 703 | */ |
700 | } | 704 | } |
701 | 705 | ||
702 | static int oti6858_tiocmset(struct usb_serial_port *port, struct file *file, | 706 | static int oti6858_tiocmset(struct tty_struct *tty, struct file *file, |
703 | unsigned int set, unsigned int clear) | 707 | unsigned int set, unsigned int clear) |
704 | { | 708 | { |
709 | struct usb_serial_port *port = tty->driver_data; | ||
705 | struct oti6858_private *priv = usb_get_serial_port_data(port); | 710 | struct oti6858_private *priv = usb_get_serial_port_data(port); |
706 | unsigned long flags; | 711 | unsigned long flags; |
707 | u8 control; | 712 | u8 control; |
@@ -732,8 +737,9 @@ static int oti6858_tiocmset(struct usb_serial_port *port, struct file *file, | |||
732 | return 0; | 737 | return 0; |
733 | } | 738 | } |
734 | 739 | ||
735 | static int oti6858_tiocmget(struct usb_serial_port *port, struct file *file) | 740 | static int oti6858_tiocmget(struct tty_struct *tty, struct file *file) |
736 | { | 741 | { |
742 | struct usb_serial_port *port = tty->driver_data; | ||
737 | struct oti6858_private *priv = usb_get_serial_port_data(port); | 743 | struct oti6858_private *priv = usb_get_serial_port_data(port); |
738 | unsigned long flags; | 744 | unsigned long flags; |
739 | unsigned pin_state; | 745 | unsigned pin_state; |
@@ -802,26 +808,15 @@ static int wait_modem_info(struct usb_serial_port *port, unsigned int arg) | |||
802 | return 0; | 808 | return 0; |
803 | } | 809 | } |
804 | 810 | ||
805 | static int oti6858_ioctl(struct usb_serial_port *port, struct file *file, | 811 | static int oti6858_ioctl(struct tty_struct *tty, struct file *file, |
806 | unsigned int cmd, unsigned long arg) | 812 | unsigned int cmd, unsigned long arg) |
807 | { | 813 | { |
808 | void __user *user_arg = (void __user *) arg; | 814 | struct usb_serial_port *port = tty->driver_data; |
809 | unsigned int x; | ||
810 | 815 | ||
811 | dbg("%s(port = %d, cmd = 0x%04x, arg = 0x%08lx)", | 816 | dbg("%s(port = %d, cmd = 0x%04x, arg = 0x%08lx)", |
812 | __func__, port->number, cmd, arg); | 817 | __func__, port->number, cmd, arg); |
813 | 818 | ||
814 | switch (cmd) { | 819 | switch (cmd) { |
815 | case TIOCMBIS: | ||
816 | if (copy_from_user(&x, user_arg, sizeof(x))) | ||
817 | return -EFAULT; | ||
818 | return oti6858_tiocmset(port, NULL, x, 0); | ||
819 | |||
820 | case TIOCMBIC: | ||
821 | if (copy_from_user(&x, user_arg, sizeof(x))) | ||
822 | return -EFAULT; | ||
823 | return oti6858_tiocmset(port, NULL, 0, x); | ||
824 | |||
825 | case TIOCMIWAIT: | 820 | case TIOCMIWAIT: |
826 | dbg("%s(): TIOCMIWAIT", __func__); | 821 | dbg("%s(): TIOCMIWAIT", __func__); |
827 | return wait_modem_info(port, arg); | 822 | return wait_modem_info(port, arg); |
@@ -834,24 +829,6 @@ static int oti6858_ioctl(struct usb_serial_port *port, struct file *file, | |||
834 | return -ENOIOCTLCMD; | 829 | return -ENOIOCTLCMD; |
835 | } | 830 | } |
836 | 831 | ||
837 | static void oti6858_break_ctl(struct usb_serial_port *port, int break_state) | ||
838 | { | ||
839 | int state; | ||
840 | |||
841 | dbg("%s(port = %d)", __func__, port->number); | ||
842 | |||
843 | state = (break_state == 0) ? 0 : 1; | ||
844 | dbg("%s(): turning break %s", __func__, state ? "on" : "off"); | ||
845 | |||
846 | /* FIXME */ | ||
847 | /* | ||
848 | result = usb_control_msg (serial->dev, usb_sndctrlpipe (serial->dev, 0), | ||
849 | BREAK_REQUEST, BREAK_REQUEST_TYPE, state, | ||
850 | 0, NULL, 0, 100); | ||
851 | if (result != 0) | ||
852 | dbg("%s(): error sending break", __func__); | ||
853 | */ | ||
854 | } | ||
855 | 832 | ||
856 | static void oti6858_shutdown(struct usb_serial *serial) | 833 | static void oti6858_shutdown(struct usb_serial *serial) |
857 | { | 834 | { |
@@ -1002,7 +979,7 @@ static void oti6858_read_bulk_callback(struct urb *urb) | |||
1002 | spin_unlock_irqrestore(&priv->lock, flags); | 979 | spin_unlock_irqrestore(&priv->lock, flags); |
1003 | 980 | ||
1004 | if (status != 0) { | 981 | if (status != 0) { |
1005 | if (!port->open_count) { | 982 | if (!port->port.count) { |
1006 | dbg("%s(): port is closed, exiting", __func__); | 983 | dbg("%s(): port is closed, exiting", __func__); |
1007 | return; | 984 | return; |
1008 | } | 985 | } |
@@ -1020,14 +997,14 @@ static void oti6858_read_bulk_callback(struct urb *urb) | |||
1020 | return; | 997 | return; |
1021 | } | 998 | } |
1022 | 999 | ||
1023 | tty = port->tty; | 1000 | tty = port->port.tty; |
1024 | if (tty != NULL && urb->actual_length > 0) { | 1001 | if (tty != NULL && urb->actual_length > 0) { |
1025 | tty_insert_flip_string(tty, data, urb->actual_length); | 1002 | tty_insert_flip_string(tty, data, urb->actual_length); |
1026 | tty_flip_buffer_push(tty); | 1003 | tty_flip_buffer_push(tty); |
1027 | } | 1004 | } |
1028 | 1005 | ||
1029 | // schedule the interrupt urb if we are still open */ | 1006 | // schedule the interrupt urb if we are still open */ |
1030 | if (port->open_count != 0) { | 1007 | if (port->port.count != 0) { |
1031 | port->interrupt_in_urb->dev = port->serial->dev; | 1008 | port->interrupt_in_urb->dev = port->serial->dev; |
1032 | result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC); | 1009 | result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC); |
1033 | if (result != 0) { | 1010 | if (result != 0) { |