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/kobil_sct.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/kobil_sct.c')
-rw-r--r-- | drivers/usb/serial/kobil_sct.c | 80 |
1 files changed, 44 insertions, 36 deletions
diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c index 693f00da7c03..40c67f0096b1 100644 --- a/drivers/usb/serial/kobil_sct.c +++ b/drivers/usb/serial/kobil_sct.c | |||
@@ -70,19 +70,22 @@ static int debug; | |||
70 | /* Function prototypes */ | 70 | /* Function prototypes */ |
71 | static int kobil_startup (struct usb_serial *serial); | 71 | static int kobil_startup (struct usb_serial *serial); |
72 | static void kobil_shutdown (struct usb_serial *serial); | 72 | static void kobil_shutdown (struct usb_serial *serial); |
73 | static int kobil_open (struct usb_serial_port *port, struct file *filp); | 73 | static int kobil_open (struct tty_struct *tty, |
74 | static void kobil_close (struct usb_serial_port *port, struct file *filp); | 74 | struct usb_serial_port *port, struct file *filp); |
75 | static int kobil_write (struct usb_serial_port *port, | 75 | static void kobil_close (struct tty_struct *tty, struct usb_serial_port *port, |
76 | struct file *filp); | ||
77 | static int kobil_write (struct tty_struct *tty, struct usb_serial_port *port, | ||
76 | const unsigned char *buf, int count); | 78 | const unsigned char *buf, int count); |
77 | static int kobil_write_room(struct usb_serial_port *port); | 79 | static int kobil_write_room(struct tty_struct *tty); |
78 | static int kobil_ioctl(struct usb_serial_port *port, struct file *file, | 80 | static int kobil_ioctl(struct tty_struct *tty, struct file *file, |
79 | unsigned int cmd, unsigned long arg); | 81 | unsigned int cmd, unsigned long arg); |
80 | static int kobil_tiocmget(struct usb_serial_port *port, struct file *file); | 82 | static int kobil_tiocmget(struct tty_struct *tty, struct file *file); |
81 | static int kobil_tiocmset(struct usb_serial_port *port, struct file *file, | 83 | static int kobil_tiocmset(struct tty_struct *tty, struct file *file, |
82 | unsigned int set, unsigned int clear); | 84 | unsigned int set, unsigned int clear); |
83 | static void kobil_read_int_callback( struct urb *urb ); | 85 | static void kobil_read_int_callback( struct urb *urb ); |
84 | static void kobil_write_callback( struct urb *purb ); | 86 | static void kobil_write_callback( struct urb *purb ); |
85 | static void kobil_set_termios(struct usb_serial_port *port, struct ktermios *old); | 87 | static void kobil_set_termios(struct tty_struct *tty, |
88 | struct usb_serial_port *port, struct ktermios *old); | ||
86 | 89 | ||
87 | 90 | ||
88 | static struct usb_device_id id_table [] = { | 91 | static struct usb_device_id id_table [] = { |
@@ -201,8 +204,8 @@ static void kobil_shutdown (struct usb_serial *serial) | |||
201 | dbg("%s - port %d", __func__, serial->port[0]->number); | 204 | dbg("%s - port %d", __func__, serial->port[0]->number); |
202 | 205 | ||
203 | for (i=0; i < serial->num_ports; ++i) { | 206 | for (i=0; i < serial->num_ports; ++i) { |
204 | while (serial->port[i]->open_count > 0) { | 207 | while (serial->port[i]->port.count > 0) { |
205 | kobil_close (serial->port[i], NULL); | 208 | kobil_close (NULL, serial->port[i], NULL); |
206 | } | 209 | } |
207 | kfree(usb_get_serial_port_data(serial->port[i])); | 210 | kfree(usb_get_serial_port_data(serial->port[i])); |
208 | usb_set_serial_port_data(serial->port[i], NULL); | 211 | usb_set_serial_port_data(serial->port[i], NULL); |
@@ -210,7 +213,8 @@ static void kobil_shutdown (struct usb_serial *serial) | |||
210 | } | 213 | } |
211 | 214 | ||
212 | 215 | ||
213 | static int kobil_open (struct usb_serial_port *port, struct file *filp) | 216 | static int kobil_open(struct tty_struct *tty, |
217 | struct usb_serial_port *port, struct file *filp) | ||
214 | { | 218 | { |
215 | int result = 0; | 219 | int result = 0; |
216 | struct kobil_private *priv; | 220 | struct kobil_private *priv; |
@@ -229,14 +233,15 @@ static int kobil_open (struct usb_serial_port *port, struct file *filp) | |||
229 | * the data through, otherwise it is scheduled, and with high | 233 | * the data through, otherwise it is scheduled, and with high |
230 | * data rates (like with OHCI) data can get lost. | 234 | * data rates (like with OHCI) data can get lost. |
231 | */ | 235 | */ |
232 | port->tty->low_latency = 1; | 236 | if (tty) { |
233 | 237 | tty->low_latency = 1; | |
234 | // without this, every push_tty_char is echoed :-( | 238 | |
235 | port->tty->termios->c_lflag = 0; | 239 | /* Default to echo off and other sane device settings */ |
236 | port->tty->termios->c_lflag &= ~(ISIG | ICANON | ECHO | IEXTEN | XCASE); | 240 | tty->termios->c_lflag = 0; |
237 | port->tty->termios->c_iflag = IGNBRK | IGNPAR | IXOFF; | 241 | tty->termios->c_lflag &= ~(ISIG | ICANON | ECHO | IEXTEN | XCASE); |
238 | port->tty->termios->c_oflag &= ~ONLCR; // do NOT translate CR to CR-NL (0x0A -> 0x0A 0x0D) | 242 | tty->termios->c_iflag = IGNBRK | IGNPAR | IXOFF; |
239 | 243 | tty->termios->c_oflag &= ~ONLCR; // do NOT translate CR to CR-NL (0x0A -> 0x0A 0x0D) | |
244 | } | ||
240 | // allocate memory for transfer buffer | 245 | // allocate memory for transfer buffer |
241 | transfer_buffer = kzalloc(transfer_buffer_length, GFP_KERNEL); | 246 | transfer_buffer = kzalloc(transfer_buffer_length, GFP_KERNEL); |
242 | if (! transfer_buffer) { | 247 | if (! transfer_buffer) { |
@@ -330,7 +335,8 @@ static int kobil_open (struct usb_serial_port *port, struct file *filp) | |||
330 | } | 335 | } |
331 | 336 | ||
332 | 337 | ||
333 | static void kobil_close (struct usb_serial_port *port, struct file *filp) | 338 | static void kobil_close(struct tty_struct *tty, |
339 | struct usb_serial_port *port, struct file *filp) | ||
334 | { | 340 | { |
335 | dbg("%s - port %d", __func__, port->number); | 341 | dbg("%s - port %d", __func__, port->number); |
336 | 342 | ||
@@ -360,7 +366,7 @@ static void kobil_read_int_callback(struct urb *urb) | |||
360 | return; | 366 | return; |
361 | } | 367 | } |
362 | 368 | ||
363 | tty = port->tty; | 369 | tty = port->port.tty; |
364 | if (urb->actual_length) { | 370 | if (urb->actual_length) { |
365 | 371 | ||
366 | // BEGIN DEBUG | 372 | // BEGIN DEBUG |
@@ -395,7 +401,7 @@ static void kobil_write_callback( struct urb *purb ) | |||
395 | } | 401 | } |
396 | 402 | ||
397 | 403 | ||
398 | static int kobil_write (struct usb_serial_port *port, | 404 | static int kobil_write (struct tty_struct *tty, struct usb_serial_port *port, |
399 | const unsigned char *buf, int count) | 405 | const unsigned char *buf, int count) |
400 | { | 406 | { |
401 | int length = 0; | 407 | int length = 0; |
@@ -417,12 +423,9 @@ static int kobil_write (struct usb_serial_port *port, | |||
417 | 423 | ||
418 | // Copy data to buffer | 424 | // Copy data to buffer |
419 | memcpy (priv->buf + priv->filled, buf, count); | 425 | memcpy (priv->buf + priv->filled, buf, count); |
420 | |||
421 | usb_serial_debug_data(debug, &port->dev, __func__, count, priv->buf + priv->filled); | 426 | usb_serial_debug_data(debug, &port->dev, __func__, count, priv->buf + priv->filled); |
422 | |||
423 | priv->filled = priv->filled + count; | 427 | priv->filled = priv->filled + count; |
424 | 428 | ||
425 | |||
426 | // only send complete block. TWIN, KAAN SIM and adapter K use the same protocol. | 429 | // only send complete block. TWIN, KAAN SIM and adapter K use the same protocol. |
427 | if ( ((priv->device_type != KOBIL_ADAPTER_B_PRODUCT_ID) && (priv->filled > 2) && (priv->filled >= (priv->buf[1] + 3))) || | 430 | if ( ((priv->device_type != KOBIL_ADAPTER_B_PRODUCT_ID) && (priv->filled > 2) && (priv->filled >= (priv->buf[1] + 3))) || |
428 | ((priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID) && (priv->filled > 3) && (priv->filled >= (priv->buf[2] + 4))) ) { | 431 | ((priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID) && (priv->filled > 3) && (priv->filled >= (priv->buf[2] + 4))) ) { |
@@ -478,15 +481,17 @@ static int kobil_write (struct usb_serial_port *port, | |||
478 | } | 481 | } |
479 | 482 | ||
480 | 483 | ||
481 | static int kobil_write_room (struct usb_serial_port *port) | 484 | static int kobil_write_room (struct tty_struct *tty) |
482 | { | 485 | { |
483 | //dbg("%s - port %d", __func__, port->number); | 486 | //dbg("%s - port %d", __func__, port->number); |
487 | /* FIXME */ | ||
484 | return 8; | 488 | return 8; |
485 | } | 489 | } |
486 | 490 | ||
487 | 491 | ||
488 | static int kobil_tiocmget(struct usb_serial_port *port, struct file *file) | 492 | static int kobil_tiocmget(struct tty_struct *tty, struct file *file) |
489 | { | 493 | { |
494 | struct usb_serial_port *port = tty->driver_data; | ||
490 | struct kobil_private * priv; | 495 | struct kobil_private * priv; |
491 | int result; | 496 | int result; |
492 | unsigned char *transfer_buffer; | 497 | unsigned char *transfer_buffer; |
@@ -524,9 +529,10 @@ static int kobil_tiocmget(struct usb_serial_port *port, struct file *file) | |||
524 | return result; | 529 | return result; |
525 | } | 530 | } |
526 | 531 | ||
527 | static int kobil_tiocmset(struct usb_serial_port *port, struct file *file, | 532 | static int kobil_tiocmset(struct tty_struct *tty, struct file *file, |
528 | unsigned int set, unsigned int clear) | 533 | unsigned int set, unsigned int clear) |
529 | { | 534 | { |
535 | struct usb_serial_port *port = tty->driver_data; | ||
530 | struct kobil_private * priv; | 536 | struct kobil_private * priv; |
531 | int result; | 537 | int result; |
532 | int dtr = 0; | 538 | int dtr = 0; |
@@ -590,12 +596,13 @@ static int kobil_tiocmset(struct usb_serial_port *port, struct file *file, | |||
590 | return (result < 0) ? result : 0; | 596 | return (result < 0) ? result : 0; |
591 | } | 597 | } |
592 | 598 | ||
593 | static void kobil_set_termios(struct usb_serial_port *port, struct ktermios *old) | 599 | static void kobil_set_termios(struct tty_struct *tty, |
600 | struct usb_serial_port *port, struct ktermios *old) | ||
594 | { | 601 | { |
595 | struct kobil_private * priv; | 602 | struct kobil_private * priv; |
596 | int result; | 603 | int result; |
597 | unsigned short urb_val = 0; | 604 | unsigned short urb_val = 0; |
598 | int c_cflag = port->tty->termios->c_cflag; | 605 | int c_cflag = tty->termios->c_cflag; |
599 | speed_t speed; | 606 | speed_t speed; |
600 | void * settings; | 607 | void * settings; |
601 | 608 | ||
@@ -604,7 +611,7 @@ static void kobil_set_termios(struct usb_serial_port *port, struct ktermios *old | |||
604 | // This device doesn't support ioctl calls | 611 | // This device doesn't support ioctl calls |
605 | return; | 612 | return; |
606 | 613 | ||
607 | switch (speed = tty_get_baud_rate(port->tty)) { | 614 | switch (speed = tty_get_baud_rate(tty)) { |
608 | case 1200: | 615 | case 1200: |
609 | urb_val = SUSBCR_SBR_1200; | 616 | urb_val = SUSBCR_SBR_1200; |
610 | break; | 617 | break; |
@@ -634,8 +641,8 @@ static void kobil_set_termios(struct usb_serial_port *port, struct ktermios *old | |||
634 | urb_val |= SUSBCR_SPASB_NoParity; | 641 | urb_val |= SUSBCR_SPASB_NoParity; |
635 | strcat(settings, "No Parity"); | 642 | strcat(settings, "No Parity"); |
636 | } | 643 | } |
637 | port->tty->termios->c_cflag &= ~CMSPAR; | 644 | tty->termios->c_cflag &= ~CMSPAR; |
638 | tty_encode_baud_rate(port->tty, speed, speed); | 645 | tty_encode_baud_rate(tty, speed, speed); |
639 | 646 | ||
640 | result = usb_control_msg( port->serial->dev, | 647 | result = usb_control_msg( port->serial->dev, |
641 | usb_rcvctrlpipe(port->serial->dev, 0 ), | 648 | usb_rcvctrlpipe(port->serial->dev, 0 ), |
@@ -650,8 +657,9 @@ static void kobil_set_termios(struct usb_serial_port *port, struct ktermios *old | |||
650 | kfree(settings); | 657 | kfree(settings); |
651 | } | 658 | } |
652 | 659 | ||
653 | static int kobil_ioctl(struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg) | 660 | static int kobil_ioctl(struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg) |
654 | { | 661 | { |
662 | struct usb_serial_port *port = tty->driver_data; | ||
655 | struct kobil_private * priv = usb_get_serial_port_data(port); | 663 | struct kobil_private * priv = usb_get_serial_port_data(port); |
656 | unsigned char *transfer_buffer; | 664 | unsigned char *transfer_buffer; |
657 | int transfer_buffer_length = 8; | 665 | int transfer_buffer_length = 8; |
@@ -662,7 +670,7 @@ static int kobil_ioctl(struct usb_serial_port *port, struct file * file, unsigne | |||
662 | return 0; | 670 | return 0; |
663 | 671 | ||
664 | switch (cmd) { | 672 | switch (cmd) { |
665 | case TCFLSH: // 0x540B | 673 | case TCFLSH: |
666 | transfer_buffer = kmalloc(transfer_buffer_length, GFP_KERNEL); | 674 | transfer_buffer = kmalloc(transfer_buffer_length, GFP_KERNEL); |
667 | if (! transfer_buffer) | 675 | if (! transfer_buffer) |
668 | return -ENOBUFS; | 676 | return -ENOBUFS; |
@@ -680,7 +688,7 @@ static int kobil_ioctl(struct usb_serial_port *port, struct file * file, unsigne | |||
680 | 688 | ||
681 | dbg("%s - port %d Send reset_all_queues (FLUSH) URB returns: %i", __func__, port->number, result); | 689 | dbg("%s - port %d Send reset_all_queues (FLUSH) URB returns: %i", __func__, port->number, result); |
682 | kfree(transfer_buffer); | 690 | kfree(transfer_buffer); |
683 | return (result < 0) ? -EFAULT : 0; | 691 | return (result < 0) ? -EIO: 0; |
684 | default: | 692 | default: |
685 | return -ENOIOCTLCMD; | 693 | return -ENOIOCTLCMD; |
686 | } | 694 | } |