From 335f8514f200e63d689113d29cb7253a5c282967 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Thu, 11 Jun 2009 12:26:29 +0100 Subject: tty: Bring the usb tty port structure into more use This allows us to clean stuff up, but is probably also going to cause some app breakage with buggy apps as we now implement proper POSIX behaviour for USB ports matching all the other ports. This does also mean other apps that break on USB will now work properly. Signed-off-by: Alan Cox Signed-off-by: Linus Torvalds --- drivers/usb/serial/ftdi_sio.c | 50 ++++++++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 22 deletions(-) (limited to 'drivers/usb/serial/ftdi_sio.c') diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index d9fcdaedf38..d9d87111f9a 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -719,8 +719,8 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port); static int ftdi_sio_port_remove(struct usb_serial_port *port); static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port, struct file *filp); -static void ftdi_close(struct tty_struct *tty, - struct usb_serial_port *port, struct file *filp); +static void ftdi_close(struct usb_serial_port *port); +static void ftdi_dtr_rts(struct usb_serial_port *port, int on); static int ftdi_write(struct tty_struct *tty, struct usb_serial_port *port, const unsigned char *buf, int count); static int ftdi_write_room(struct tty_struct *tty); @@ -758,6 +758,7 @@ static struct usb_serial_driver ftdi_sio_device = { .port_remove = ftdi_sio_port_remove, .open = ftdi_open, .close = ftdi_close, + .dtr_rts = ftdi_dtr_rts, .throttle = ftdi_throttle, .unthrottle = ftdi_unthrottle, .write = ftdi_write, @@ -1558,6 +1559,30 @@ static int ftdi_open(struct tty_struct *tty, } /* ftdi_open */ +static void ftdi_dtr_rts(struct usb_serial_port *port, int on) +{ + struct ftdi_private *priv = usb_get_serial_port_data(port); + char buf[1]; + + mutex_lock(&port->serial->disc_mutex); + if (!port->serial->disconnected) { + /* Disable flow control */ + if (!on && usb_control_msg(port->serial->dev, + usb_sndctrlpipe(port->serial->dev, 0), + FTDI_SIO_SET_FLOW_CTRL_REQUEST, + FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, + 0, priv->interface, buf, 0, + WDR_TIMEOUT) < 0) { + dev_err(&port->dev, "error from flowcontrol urb\n"); + } + /* drop RTS and DTR */ + if (on) + set_mctrl(port, TIOCM_DTR | TIOCM_RTS); + else + clear_mctrl(port, TIOCM_DTR | TIOCM_RTS); + } + mutex_unlock(&port->serial->disc_mutex); +} /* * usbserial:__serial_close only calls ftdi_close if the point is open @@ -1567,31 +1592,12 @@ static int ftdi_open(struct tty_struct *tty, * */ -static void ftdi_close(struct tty_struct *tty, - struct usb_serial_port *port, struct file *filp) +static void ftdi_close(struct usb_serial_port *port) { /* ftdi_close */ - unsigned int c_cflag = tty->termios->c_cflag; struct ftdi_private *priv = usb_get_serial_port_data(port); - char buf[1]; dbg("%s", __func__); - mutex_lock(&port->serial->disc_mutex); - if (c_cflag & HUPCL && !port->serial->disconnected) { - /* Disable flow control */ - if (usb_control_msg(port->serial->dev, - usb_sndctrlpipe(port->serial->dev, 0), - FTDI_SIO_SET_FLOW_CTRL_REQUEST, - FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, - 0, priv->interface, buf, 0, - WDR_TIMEOUT) < 0) { - dev_err(&port->dev, "error from flowcontrol urb\n"); - } - - /* drop RTS and DTR */ - clear_mctrl(port, TIOCM_DTR | TIOCM_RTS); - } /* Note change no line if hupcl is off */ - mutex_unlock(&port->serial->disc_mutex); /* cancel any scheduled reading */ cancel_delayed_work_sync(&priv->rx_work); -- cgit v1.2.3-70-g09d2 From 557aaa7ffab639d0190b935a041b16ae44606342 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Thu, 11 Jun 2009 13:55:34 +0100 Subject: ft232: support the ASYNC_LOW_LATENCY flag This allows users to use the standard setserial command with this FT232 feature as well as obscure chip specific interfaces we have now. We keep track of and respect the sysfs value for non-low-latency cases. In theory we could do smart stuff with VTIME and the like but this seems of questionable worth. Closes-bug: http://bugzilla.kernel.org/show_bug.cgi?id=9120 Signed-off-by: Alan Cox --- drivers/usb/serial/ftdi_sio.c | 94 +++++++++++++++++++++++++++---------------- 1 file changed, 60 insertions(+), 34 deletions(-) (limited to 'drivers/usb/serial/ftdi_sio.c') diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index d9d87111f9a..21c053c31b9 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -89,6 +89,7 @@ struct ftdi_private { int force_rtscts; /* if non-zero, force RTS-CTS to always be enabled */ + unsigned int latency; /* latency setting in use */ spinlock_t tx_lock; /* spinlock for transmit state */ unsigned long tx_bytes; unsigned long tx_outstanding_bytes; @@ -1038,7 +1039,54 @@ static int change_speed(struct tty_struct *tty, struct usb_serial_port *port) return rv; } +static int write_latency_timer(struct usb_serial_port *port) +{ + struct ftdi_private *priv = usb_get_serial_port_data(port); + struct usb_device *udev = port->serial->dev; + char buf[1]; + int rv = 0; + int l = priv->latency; + + if (priv->flags & ASYNC_LOW_LATENCY) + l = 1; + + dbg("%s: setting latency timer = %i", __func__, l); + + rv = usb_control_msg(udev, + usb_sndctrlpipe(udev, 0), + FTDI_SIO_SET_LATENCY_TIMER_REQUEST, + FTDI_SIO_SET_LATENCY_TIMER_REQUEST_TYPE, + l, priv->interface, + buf, 0, WDR_TIMEOUT); + if (rv < 0) + dev_err(&port->dev, "Unable to write latency timer: %i\n", rv); + return rv; +} + +static int read_latency_timer(struct usb_serial_port *port) +{ + struct ftdi_private *priv = usb_get_serial_port_data(port); + struct usb_device *udev = port->serial->dev; + unsigned short latency = 0; + int rv = 0; + + + dbg("%s", __func__); + + rv = usb_control_msg(udev, + usb_rcvctrlpipe(udev, 0), + FTDI_SIO_GET_LATENCY_TIMER_REQUEST, + FTDI_SIO_GET_LATENCY_TIMER_REQUEST_TYPE, + 0, priv->interface, + (char *) &latency, 1, WDR_TIMEOUT); + + if (rv < 0) { + dev_err(&port->dev, "Unable to read latency timer: %i\n", rv); + return -EIO; + } + return latency; +} static int get_serial_info(struct usb_serial_port *port, struct serial_struct __user *retinfo) @@ -1098,6 +1146,7 @@ static int set_serial_info(struct tty_struct *tty, priv->custom_divisor = new_serial.custom_divisor; tty->low_latency = (priv->flags & ASYNC_LOW_LATENCY) ? 1 : 0; + write_latency_timer(port); check_and_exit: if ((old_priv.flags & ASYNC_SPD_MASK) != @@ -1193,27 +1242,13 @@ static ssize_t show_latency_timer(struct device *dev, { struct usb_serial_port *port = to_usb_serial_port(dev); struct ftdi_private *priv = usb_get_serial_port_data(port); - struct usb_device *udev = port->serial->dev; - unsigned short latency = 0; - int rv = 0; - - - dbg("%s", __func__); - - rv = usb_control_msg(udev, - usb_rcvctrlpipe(udev, 0), - FTDI_SIO_GET_LATENCY_TIMER_REQUEST, - FTDI_SIO_GET_LATENCY_TIMER_REQUEST_TYPE, - 0, priv->interface, - (char *) &latency, 1, WDR_TIMEOUT); - - if (rv < 0) { - dev_err(dev, "Unable to read latency timer: %i\n", rv); - return -EIO; - } - return sprintf(buf, "%i\n", latency); + if (priv->flags & ASYNC_LOW_LATENCY) + return sprintf(buf, "1\n"); + else + return sprintf(buf, "%i\n", priv->latency); } + /* Write a new value of the latency timer, in units of milliseconds. */ static ssize_t store_latency_timer(struct device *dev, struct device_attribute *attr, const char *valbuf, @@ -1221,25 +1256,13 @@ static ssize_t store_latency_timer(struct device *dev, { struct usb_serial_port *port = to_usb_serial_port(dev); struct ftdi_private *priv = usb_get_serial_port_data(port); - struct usb_device *udev = port->serial->dev; - char buf[1]; int v = simple_strtoul(valbuf, NULL, 10); int rv = 0; - dbg("%s: setting latency timer = %i", __func__, v); - - rv = usb_control_msg(udev, - usb_sndctrlpipe(udev, 0), - FTDI_SIO_SET_LATENCY_TIMER_REQUEST, - FTDI_SIO_SET_LATENCY_TIMER_REQUEST_TYPE, - v, priv->interface, - buf, 0, WDR_TIMEOUT); - - if (rv < 0) { - dev_err(dev, "Unable to write latency timer: %i\n", rv); + priv->latency = v; + rv = write_latency_timer(port); + if (rv < 0) return -EIO; - } - return count; } @@ -1393,6 +1416,7 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port) usb_set_serial_port_data(port, priv); ftdi_determine_type(port); + read_latency_timer(port); create_sysfs_attrs(port); return 0; } @@ -1515,6 +1539,8 @@ static int ftdi_open(struct tty_struct *tty, if (tty) tty->low_latency = (priv->flags & ASYNC_LOW_LATENCY) ? 1 : 0; + write_latency_timer(port); + /* No error checking for this (will get errors later anyway) */ /* See ftdi_sio.h for description of what is reset */ usb_control_msg(dev, usb_sndctrlpipe(dev, 0), -- cgit v1.2.3-70-g09d2 From 7e9cd3a617414cfe74342659ceeb4e92975c1efa Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Thu, 11 Jun 2009 13:57:01 +0100 Subject: ftdi_sio: don't override modem bits The new open/close logic handles DTR and friends, so don't do it in our own open routine as well. Signed-off-by: Alan Cox Signed-off-by: Linus Torvalds --- drivers/usb/serial/ftdi_sio.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers/usb/serial/ftdi_sio.c') diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 21c053c31b9..683304d6061 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1556,11 +1556,6 @@ static int ftdi_open(struct tty_struct *tty, if (tty) ftdi_set_termios(tty, port, tty->termios); - /* FIXME: Flow control might be enabled, so it should be checked - - we have no control of defaults! */ - /* Turn on RTS and DTR since we are not flow controlling by default */ - set_mctrl(port, TIOCM_DTR | TIOCM_RTS); - /* Not throttled */ spin_lock_irqsave(&priv->rx_lock, flags); priv->rx_flags &= ~(THROTTLED | ACTUALLY_THROTTLED); -- cgit v1.2.3-70-g09d2 From d46130ab3ed3716db22bdd9881a60ec7e4365b63 Mon Sep 17 00:00:00 2001 From: Daniel Suchy Date: Wed, 13 May 2009 10:05:48 +0200 Subject: USB: FTDI-SIO new device ids I would like to have added new device to usbserial/ftdi_sio driver. These ids used USB track device (http://www.l-and-b.dk/access_alt.html). They use differend device IDs, but it works as standard usb-serial conventer. From: Daniel Suchy Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 1 + drivers/usb/serial/ftdi_sio.h | 3 +++ 2 files changed, 4 insertions(+) (limited to 'drivers/usb/serial/ftdi_sio.c') diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 683304d6061..59c7501840c 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -673,6 +673,7 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(JETI_VID, JETI_SPC1201_PID) }, { USB_DEVICE(MARVELL_VID, MARVELL_SHEEVAPLUG_PID), .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, + { USB_DEVICE(LARSENBRUSGAARD_VID, LB_ALTITRACK_PID) }, { }, /* Optional parameter entry */ { } /* Terminating entry */ }; diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h index 12330fa1c09..0a09118f315 100644 --- a/drivers/usb/serial/ftdi_sio.h +++ b/drivers/usb/serial/ftdi_sio.h @@ -33,6 +33,9 @@ #define FTDI_NF_RIC_PID 0x0001 /* Product Id */ #define FTDI_USBX_707_PID 0xF857 /* ADSTech IR Blaster USBX-707 */ +/* Larsen and Brusgaard AltiTrack/USBtrack */ +#define LARSENBRUSGAARD_VID 0x0FD8 +#define LB_ALTITRACK_PID 0x0001 /* www.canusb.com Lawicel CANUSB device */ #define FTDI_CANUSB_PID 0xFFA8 /* Product Id */ -- cgit v1.2.3-70-g09d2 From 094c2e6db4be381f708ad8a2e0532d7782f05ea4 Mon Sep 17 00:00:00 2001 From: Mark Adamson Date: Thu, 9 Apr 2009 15:03:09 +0100 Subject: USB: serial: FTDI: add high speed device support Added support for FTDI's USB 2.0 hi-speed devices - FT2232H (2 interfaces) and FT4232H (4 interfaces), including a new baud rate calculation for these devices which can now achieve up to 12Mbaud by turning off a divide by 2.5 in the baud rate generator of the chips. In order to achieve baud rates of <1200 baud, the divide by 2.5 must be active. The default product ID of the FT2232H is 0x6010 (same as the FT2232C IC). The default PID of the FT4232H is 0x6011. Signed-off-by: Mark J. Adamson Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 90 ++++++++++++++++++++++++++++++++++++++----- drivers/usb/serial/ftdi_sio.h | 10 ++++- 2 files changed, 89 insertions(+), 11 deletions(-) (limited to 'drivers/usb/serial/ftdi_sio.c') diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 59c7501840c..80ccfa13e0b 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -47,7 +47,7 @@ /* * Version Information */ -#define DRIVER_VERSION "v1.4.3" +#define DRIVER_VERSION "v1.5.0" #define DRIVER_AUTHOR "Greg Kroah-Hartman , Bill Ryder , Kuba Ober " #define DRIVER_DESC "USB FTDI Serial Converters Driver" @@ -82,7 +82,8 @@ struct ftdi_private { int rx_processed; unsigned long rx_bytes; - __u16 interface; /* FT2232C port interface (0 for FT232/245) */ + __u16 interface; /* FT2232C, FT2232H or FT4232H port interface + (0 for FT232/245) */ speed_t force_baud; /* if non-zero, force the baud rate to this value */ @@ -164,6 +165,7 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_8U232AM_ALT_PID) }, { USB_DEVICE(FTDI_VID, FTDI_232RL_PID) }, { USB_DEVICE(FTDI_VID, FTDI_8U2232C_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_4232H_PID) }, { USB_DEVICE(FTDI_VID, FTDI_MICRO_CHAMELEON_PID) }, { USB_DEVICE(FTDI_VID, FTDI_RELAIS_PID) }, { USB_DEVICE(FTDI_VID, FTDI_OPENDCC_PID) }, @@ -694,6 +696,8 @@ static const char *ftdi_chip_name[] = { [FT232BM] = "FT232BM", [FT2232C] = "FT2232C", [FT232RL] = "FT232RL", + [FT2232H] = "FT2232H", + [FT4232H] = "FT4232H" }; @@ -745,6 +749,8 @@ static unsigned short int ftdi_232am_baud_base_to_divisor(int baud, int base); static unsigned short int ftdi_232am_baud_to_divisor(int baud); static __u32 ftdi_232bm_baud_base_to_divisor(int baud, int base); static __u32 ftdi_232bm_baud_to_divisor(int baud); +static __u32 ftdi_2232h_baud_base_to_divisor(int baud, int base); +static __u32 ftdi_2232h_baud_to_divisor(int baud); static struct usb_serial_driver ftdi_sio_device = { .driver = { @@ -839,6 +845,36 @@ static __u32 ftdi_232bm_baud_to_divisor(int baud) return ftdi_232bm_baud_base_to_divisor(baud, 48000000); } +static __u32 ftdi_2232h_baud_base_to_divisor(int baud, int base) +{ + static const unsigned char divfrac[8] = { 0, 3, 2, 4, 1, 5, 6, 7 }; + __u32 divisor; + int divisor3; + + /* hi-speed baud rate is 10-bit sampling instead of 16-bit */ + divisor3 = (base / 10 / baud) * 8; + + divisor = divisor3 >> 3; + divisor |= (__u32)divfrac[divisor3 & 0x7] << 14; + /* Deal with special cases for highest baud rates. */ + if (divisor == 1) + divisor = 0; + else if (divisor == 0x4001) + divisor = 1; + /* + * Set this bit to turn off a divide by 2.5 on baud rate generator + * This enables baud rates up to 12Mbaud but cannot reach below 1200 + * baud with this bit set + */ + divisor |= 0x00020000; + return divisor; +} + +static __u32 ftdi_2232h_baud_to_divisor(int baud) +{ + return ftdi_2232h_baud_base_to_divisor(baud, 120000000); +} + #define set_mctrl(port, set) update_mctrl((port), (set), 0) #define clear_mctrl(port, clear) update_mctrl((port), 0, (clear)) @@ -997,6 +1033,19 @@ static __u32 get_ftdi_divisor(struct tty_struct *tty, baud = 9600; } break; + case FT2232H: /* FT2232H chip */ + case FT4232H: /* FT4232H chip */ + if ((baud <= 12000000) & (baud >= 1200)) { + div_value = ftdi_2232h_baud_to_divisor(baud); + } else if (baud < 1200) { + div_value = ftdi_232bm_baud_to_divisor(baud); + } else { + dbg("%s - Baud rate too high!", __func__); + div_value = ftdi_232bm_baud_to_divisor(9600); + div_okay = 0; + baud = 9600; + } + break; } /* priv->chip_type */ if (div_okay) { @@ -1197,14 +1246,29 @@ static void ftdi_determine_type(struct usb_serial_port *port) if (interfaces > 1) { int inter; - /* Multiple interfaces. Assume FT2232C. */ - priv->chip_type = FT2232C; + /* Multiple interfaces.*/ + if (version == 0x0800) { + priv->chip_type = FT4232H; + /* Hi-speed - baud clock runs at 120MHz */ + priv->baud_base = 120000000 / 2; + } else if (version == 0x0700) { + priv->chip_type = FT2232H; + /* Hi-speed - baud clock runs at 120MHz */ + priv->baud_base = 120000000 / 2; + } else + priv->chip_type = FT2232C; + /* Determine interface code. */ inter = serial->interface->altsetting->desc.bInterfaceNumber; - if (inter == 0) - priv->interface = PIT_SIOA; - else - priv->interface = PIT_SIOB; + if (inter == 0) { + priv->interface = INTERFACE_A; + } else if (inter == 1) { + priv->interface = INTERFACE_B; + } else if (inter == 2) { + priv->interface = INTERFACE_C; + } else if (inter == 3) { + priv->interface = INTERFACE_D; + } /* BM-type devices have a bug where bcdDevice gets set * to 0x200 when iSerialNumber is 0. */ if (version < 0x500) { @@ -1315,7 +1379,9 @@ static int create_sysfs_attrs(struct usb_serial_port *port) if ((!retval) && (priv->chip_type == FT232BM || priv->chip_type == FT2232C || - priv->chip_type == FT232RL)) { + priv->chip_type == FT232RL || + priv->chip_type == FT2232H || + priv->chip_type == FT4232H)) { retval = device_create_file(&port->dev, &dev_attr_latency_timer); } @@ -1334,7 +1400,9 @@ static void remove_sysfs_attrs(struct usb_serial_port *port) device_remove_file(&port->dev, &dev_attr_event_char); if (priv->chip_type == FT232BM || priv->chip_type == FT2232C || - priv->chip_type == FT232RL) { + priv->chip_type == FT232RL || + priv->chip_type == FT2232H || + priv->chip_type == FT4232H) { device_remove_file(&port->dev, &dev_attr_latency_timer); } } @@ -2333,6 +2401,8 @@ static int ftdi_tiocmget(struct tty_struct *tty, struct file *file) case FT232BM: case FT2232C: case FT232RL: + case FT2232H: + case FT4232H: /* the 8U232AM returns a two byte value (the sio is a 1 byte value) - in the same format as the data returned from the in point */ diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h index 0a09118f315..f1d440a728a 100644 --- a/drivers/usb/serial/ftdi_sio.h +++ b/drivers/usb/serial/ftdi_sio.h @@ -10,7 +10,7 @@ * The device is based on the FTDI FT8U100AX chip. It has a DB25 on one side, * USB on the other. * - * Thanx to FTDI (http://www.ftdi.co.uk) for so kindly providing details + * Thanx to FTDI (http://www.ftdichip.com) for so kindly providing details * of the protocol required to talk to the device and ongoing assistence * during development. * @@ -28,6 +28,7 @@ #define FTDI_8U232AM_ALT_PID 0x6006 /* FTDI's alternate PID for above */ #define FTDI_8U2232C_PID 0x6010 /* Dual channel device */ #define FTDI_232RL_PID 0xFBFA /* Product ID for FT232RL */ +#define FTDI_4232H_PID 0x6011 /* Quad channel hi-speed device */ #define FTDI_RELAIS_PID 0xFA10 /* Relais device from Rudolf Gugler */ #define FTDI_NF_RIC_VID 0x0DCD /* Vendor Id */ #define FTDI_NF_RIC_PID 0x0001 /* Product Id */ @@ -876,6 +877,11 @@ #define FTDI_SIO_SET_LATENCY_TIMER 9 /* Set the latency timer */ #define FTDI_SIO_GET_LATENCY_TIMER 10 /* Get the latency timer */ +/* Interface indicies for FT2232, FT2232H and FT4232H devices*/ +#define INTERFACE_A 1 +#define INTERFACE_B 2 +#define INTERFACE_C 3 +#define INTERFACE_D 4 /* * FIC / OpenMoko, Inc. http://wiki.openmoko.org/wiki/Neo1973_Debug_Board_v3 @@ -1039,6 +1045,8 @@ typedef enum { FT232BM = 3, FT2232C = 4, FT232RL = 5, + FT2232H = 6, + FT4232H = 7 } ftdi_chip_type_t; typedef enum { -- cgit v1.2.3-70-g09d2 From 895f28badce96cd903026b0076966e3571b6968e Mon Sep 17 00:00:00 2001 From: Mark Adamson Date: Fri, 1 May 2009 11:48:45 +0100 Subject: USB: ftdi_sio: fix hi-speed device packet size calculation Added a function to set the packet size to be used based on the value from the device endpoint descriptor. The FT2232H and FT4232H hi-speed devices will have wMaxPacketSize of 512 bytes when connected to a USB 2.0 hi-speed host, but will use alternative descriptors with wMaxPacketSize of 64 bytes if connected to a USB 1.1 host or hub. All other FTDI devices have wMaxPacketSize of 64 bytes, except some FT232R and FT245R devices which customers have mistakenly programmed to have wMaxPacketSize of 0 - this is an error and will be overridden to use wMaxPacketSize of 64 bytes. The packet size used is important as it determines where the driver removes the status bytes from the incoming data. If it is incorrect, it will lead to data corruption. Signed-off-by: Mark J. Adamson Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 56 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 48 insertions(+), 8 deletions(-) (limited to 'drivers/usb/serial/ftdi_sio.c') diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 80ccfa13e0b..74cc3c83160 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -95,6 +95,7 @@ struct ftdi_private { unsigned long tx_bytes; unsigned long tx_outstanding_bytes; unsigned long tx_outstanding_urbs; + unsigned short max_packet_size; }; /* struct ftdi_sio_quirk is used by devices requiring special attention. */ @@ -703,7 +704,6 @@ static const char *ftdi_chip_name[] = { /* Constants for read urb and write urb */ #define BUFSZ 512 -#define PKTSZ 64 /* rx_flags */ #define THROTTLED 0x01 @@ -1296,6 +1296,45 @@ static void ftdi_determine_type(struct usb_serial_port *port) } +/* Determine the maximum packet size for the device. This depends on the chip + * type and the USB host capabilities. The value should be obtained from the + * device descriptor as the chip will use the appropriate values for the host.*/ +static void ftdi_set_max_packet_size(struct usb_serial_port *port) +{ + struct ftdi_private *priv = usb_get_serial_port_data(port); + struct usb_serial *serial = port->serial; + struct usb_device *udev = serial->dev; + + struct usb_interface *interface = serial->interface; + struct usb_endpoint_descriptor *ep_desc = &interface->cur_altsetting->endpoint[1].desc; + + unsigned num_endpoints; + int i = 0; + + num_endpoints = interface->cur_altsetting->desc.bNumEndpoints; + dev_info(&udev->dev, "Number of endpoints %d\n", num_endpoints); + + /* NOTE: some customers have programmed FT232R/FT245R devices + * with an endpoint size of 0 - not good. In this case, we + * want to override the endpoint descriptor setting and use a + * value of 64 for wMaxPacketSize */ + for (i = 0; i < num_endpoints; i++) { + dev_info(&udev->dev, "Endpoint %d MaxPacketSize %d\n", i+1, + interface->cur_altsetting->endpoint[i].desc.wMaxPacketSize); + ep_desc = &interface->cur_altsetting->endpoint[i].desc; + if (ep_desc->wMaxPacketSize == 0) { + ep_desc->wMaxPacketSize = cpu_to_le16(0x40); + dev_info(&udev->dev, "Overriding wMaxPacketSize on endpoint %d\n", i); + } + } + + /* set max packet size based on descriptor */ + priv->max_packet_size = ep_desc->wMaxPacketSize; + + dev_info(&udev->dev, "Setting MaxPacketSize %d\n", priv->max_packet_size); +} + + /* * *************************************************************************** * Sysfs Attribute @@ -1485,6 +1524,7 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port) usb_set_serial_port_data(port, priv); ftdi_determine_type(port); + ftdi_set_max_packet_size(port); read_latency_timer(port); create_sysfs_attrs(port); return 0; @@ -1740,8 +1780,8 @@ static int ftdi_write(struct tty_struct *tty, struct usb_serial_port *port, if (data_offset > 0) { /* Original sio needs control bytes too... */ transfer_size += (data_offset * - ((count + (PKTSZ - 1 - data_offset)) / - (PKTSZ - data_offset))); + ((count + (priv->max_packet_size - 1 - data_offset)) / + (priv->max_packet_size - data_offset))); } buffer = kmalloc(transfer_size, GFP_ATOMIC); @@ -1763,7 +1803,7 @@ static int ftdi_write(struct tty_struct *tty, struct usb_serial_port *port, if (data_offset > 0) { /* Original sio requires control byte at start of each packet. */ - int user_pktsz = PKTSZ - data_offset; + int user_pktsz = priv->max_packet_size - data_offset; int todo = count; unsigned char *first_byte = buffer; const unsigned char *current_position = buf; @@ -1859,7 +1899,7 @@ static void ftdi_write_bulk_callback(struct urb *urb) data_offset = priv->write_offset; if (data_offset > 0) { /* Subtract the control bytes */ - countback -= (data_offset * DIV_ROUND_UP(countback, PKTSZ)); + countback -= (data_offset * DIV_ROUND_UP(countback, priv->max_packet_size)); } spin_lock_irqsave(&priv->tx_lock, flags); --priv->tx_outstanding_urbs; @@ -1961,7 +2001,7 @@ static void ftdi_read_bulk_callback(struct urb *urb) /* count data bytes, but not status bytes */ countread = urb->actual_length; - countread -= 2 * DIV_ROUND_UP(countread, PKTSZ); + countread -= 2 * DIV_ROUND_UP(countread, priv->max_packet_size); spin_lock_irqsave(&priv->rx_lock, flags); priv->rx_bytes += countread; spin_unlock_irqrestore(&priv->rx_lock, flags); @@ -2034,7 +2074,7 @@ static void ftdi_process_read(struct work_struct *work) need_flip = 0; for (packet_offset = priv->rx_processed; - packet_offset < urb->actual_length; packet_offset += PKTSZ) { + packet_offset < urb->actual_length; packet_offset += priv->max_packet_size) { int length; /* Compare new line status to the old one, signal if different/ @@ -2049,7 +2089,7 @@ static void ftdi_process_read(struct work_struct *work) priv->prev_status = new_status; } - length = min_t(u32, PKTSZ, urb->actual_length-packet_offset)-2; + length = min_t(u32, priv->max_packet_size, urb->actual_length-packet_offset)-2; if (length < 0) { dev_err(&port->dev, "%s - bad packet length: %d\n", __func__, length+2); -- cgit v1.2.3-70-g09d2 From 87c1edd217a6742e48028db6664d7763de0449f6 Mon Sep 17 00:00:00 2001 From: Jason Wessel Date: Mon, 11 May 2009 15:24:08 -0500 Subject: USB: serial: ftd_sio usb: move status check Alan Stern commented that the private driver counts must be updated regard less of the status return on the urb when the write call back is executed. This patch alters the behavior to update the private driver counts by simply moving the status check to after the driver count update. Signed-off-by: Jason Wessel Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/usb/serial/ftdi_sio.c') diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 74cc3c83160..fc527de7346 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1884,11 +1884,6 @@ static void ftdi_write_bulk_callback(struct urb *urb) dbg("%s - port %d", __func__, port->number); - if (status) { - dbg("nonzero write bulk status received: %d", status); - return; - } - priv = usb_get_serial_port_data(port); if (!priv) { dbg("%s - bad port private data pointer - exiting", __func__); @@ -1906,6 +1901,11 @@ static void ftdi_write_bulk_callback(struct urb *urb) priv->tx_outstanding_bytes -= countback; spin_unlock_irqrestore(&priv->tx_lock, flags); + if (status) { + dbg("nonzero write bulk status received: %d", status); + return; + } + usb_serial_port_softint(port); } /* ftdi_write_bulk_callback */ -- cgit v1.2.3-70-g09d2 From 72fda3ca6fc14662bb385d1e39e9e00af15b200d Mon Sep 17 00:00:00 2001 From: Jason Wessel Date: Mon, 11 May 2009 15:24:10 -0500 Subject: USB: serial: ftd_sio: implement sysrq handling on break Change driver to make use of the new functions in include/linux/usb/serial.h so as to allow the driver to handle the sysrq Signed-off-by: Jason Wessel Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers/usb/serial/ftdi_sio.c') diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index fc527de7346..fc423583eed 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -2120,6 +2120,7 @@ static void ftdi_process_read(struct work_struct *work) if (data[packet_offset+1] & FTDI_RS_BI) { error_flag = TTY_BREAK; dbg("BREAK received"); + usb_serial_handle_break(port); } if (data[packet_offset+1] & FTDI_RS_PE) { error_flag = TTY_PARITY; @@ -2134,8 +2135,11 @@ static void ftdi_process_read(struct work_struct *work) /* Note that the error flag is duplicated for every character received since we don't know which character it applied to */ - tty_insert_flip_char(tty, - data[packet_offset + i], error_flag); + if (!usb_serial_handle_sysrq_char(port, + data[packet_offset + i])) + tty_insert_flip_char(tty, + data[packet_offset + i], + error_flag); } need_flip = 1; } -- cgit v1.2.3-70-g09d2 From f9c99bb8b3a1ec81af68d484a551307326c2e933 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 2 Jun 2009 11:53:55 -0400 Subject: USB: usb-serial: replace shutdown with disconnect, release This patch (as1254) splits up the shutdown method of usb_serial_driver into a disconnect and a release method. The problem is that the usb-serial core was calling shutdown during disconnect handling, but drivers didn't expect it to be called until after all the open file references had been closed. The result was an oops when the close method tried to use memory that had been deallocated by shutdown. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/staging/uc2322/aten2011.c | 4 ++-- drivers/usb/serial/aircable.c | 5 ++--- drivers/usb/serial/belkin_sa.c | 7 +++--- drivers/usb/serial/cp210x.c | 6 ++--- drivers/usb/serial/cyberjack.c | 20 ++++++++++++----- drivers/usb/serial/cypress_m8.c | 11 +++++---- drivers/usb/serial/digi_acceleport.c | 20 ++++++++++++----- drivers/usb/serial/empeg.c | 8 ------- drivers/usb/serial/ftdi_sio.c | 14 ------------ drivers/usb/serial/garmin_gps.c | 16 ++++++++++--- drivers/usb/serial/generic.c | 9 ++++++-- drivers/usb/serial/io_edgeport.c | 29 ++++++++++++++++-------- drivers/usb/serial/io_tables.h | 12 ++++++---- drivers/usb/serial/io_ti.c | 22 +++++++++++++----- drivers/usb/serial/ipaq.c | 7 ------ drivers/usb/serial/iuu_phoenix.c | 6 ++--- drivers/usb/serial/keyspan.c | 13 ++++++++++- drivers/usb/serial/keyspan.h | 12 ++++++---- drivers/usb/serial/keyspan_pda.c | 4 ++-- drivers/usb/serial/kl5kusb105.c | 39 ++++++++++++++++++-------------- drivers/usb/serial/kobil_sct.c | 12 ++++------ drivers/usb/serial/mct_u232.c | 13 +++++------ drivers/usb/serial/mos7720.c | 9 +++----- drivers/usb/serial/mos7840.c | 42 ++++++++++++++++++++++++++++++----- drivers/usb/serial/omninet.c | 19 ++++++++++++---- drivers/usb/serial/opticon.c | 14 +++++++++--- drivers/usb/serial/option.c | 17 +++++++++----- drivers/usb/serial/oti6858.c | 7 +++--- drivers/usb/serial/pl2303.c | 5 ++--- drivers/usb/serial/sierra.c | 4 ++-- drivers/usb/serial/spcp8x5.c | 5 ++--- drivers/usb/serial/symbolserial.c | 14 +++++++++--- drivers/usb/serial/ti_usb_3410_5052.c | 10 ++++----- drivers/usb/serial/usb-serial.c | 29 +++++++++++------------- drivers/usb/serial/visor.c | 13 +++++------ drivers/usb/serial/whiteheat.c | 6 ++--- include/linux/usb/serial.h | 12 ++++++---- 37 files changed, 297 insertions(+), 198 deletions(-) (limited to 'drivers/usb/serial/ftdi_sio.c') diff --git a/drivers/staging/uc2322/aten2011.c b/drivers/staging/uc2322/aten2011.c index 9c62f787cc9..39d0926d1a9 100644 --- a/drivers/staging/uc2322/aten2011.c +++ b/drivers/staging/uc2322/aten2011.c @@ -2336,7 +2336,7 @@ static int ATEN2011_startup(struct usb_serial *serial) return 0; } -static void ATEN2011_shutdown(struct usb_serial *serial) +static void ATEN2011_release(struct usb_serial *serial) { int i; struct ATENINTL_port *ATEN2011_port; @@ -2382,7 +2382,7 @@ static struct usb_serial_driver aten_serial_driver = { .tiocmget = ATEN2011_tiocmget, .tiocmset = ATEN2011_tiocmset, .attach = ATEN2011_startup, - .shutdown = ATEN2011_shutdown, + .release = ATEN2011_release, .read_bulk_callback = ATEN2011_bulk_in_callback, .read_int_callback = ATEN2011_interrupt_callback, }; diff --git a/drivers/usb/serial/aircable.c b/drivers/usb/serial/aircable.c index 6d106e74265..2cbfab3716e 100644 --- a/drivers/usb/serial/aircable.c +++ b/drivers/usb/serial/aircable.c @@ -364,7 +364,7 @@ static int aircable_attach(struct usb_serial *serial) return 0; } -static void aircable_shutdown(struct usb_serial *serial) +static void aircable_release(struct usb_serial *serial) { struct usb_serial_port *port = serial->port[0]; @@ -375,7 +375,6 @@ static void aircable_shutdown(struct usb_serial *serial) if (priv) { serial_buf_free(priv->tx_buf); serial_buf_free(priv->rx_buf); - usb_set_serial_port_data(port, NULL); kfree(priv); } } @@ -601,7 +600,7 @@ static struct usb_serial_driver aircable_device = { .num_ports = 1, .attach = aircable_attach, .probe = aircable_probe, - .shutdown = aircable_shutdown, + .release = aircable_release, .write = aircable_write, .write_room = aircable_write_room, .write_bulk_callback = aircable_write_bulk_callback, diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c index 2bfd6dd85b5..7033b031b44 100644 --- a/drivers/usb/serial/belkin_sa.c +++ b/drivers/usb/serial/belkin_sa.c @@ -90,7 +90,7 @@ static int debug; /* function prototypes for a Belkin USB Serial Adapter F5U103 */ static int belkin_sa_startup(struct usb_serial *serial); -static void belkin_sa_shutdown(struct usb_serial *serial); +static void belkin_sa_release(struct usb_serial *serial); static int belkin_sa_open(struct tty_struct *tty, struct usb_serial_port *port, struct file *filp); static void belkin_sa_close(struct usb_serial_port *port); @@ -142,7 +142,7 @@ static struct usb_serial_driver belkin_device = { .tiocmget = belkin_sa_tiocmget, .tiocmset = belkin_sa_tiocmset, .attach = belkin_sa_startup, - .shutdown = belkin_sa_shutdown, + .release = belkin_sa_release, }; @@ -197,14 +197,13 @@ static int belkin_sa_startup(struct usb_serial *serial) } -static void belkin_sa_shutdown(struct usb_serial *serial) +static void belkin_sa_release(struct usb_serial *serial) { struct belkin_sa_private *priv; int i; dbg("%s", __func__); - /* stop reads and writes on all ports */ for (i = 0; i < serial->num_ports; ++i) { /* My special items, the standard routines free my urbs */ priv = usb_get_serial_port_data(serial->port[i]); diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index 16a154d3b2f..2b9eeda62bf 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -50,7 +50,7 @@ static int cp210x_tiocmset_port(struct usb_serial_port *port, struct file *, unsigned int, unsigned int); static void cp210x_break_ctl(struct tty_struct *, int); static int cp210x_startup(struct usb_serial *); -static void cp210x_shutdown(struct usb_serial *); +static void cp210x_disconnect(struct usb_serial *); static int debug; @@ -137,7 +137,7 @@ static struct usb_serial_driver cp210x_device = { .tiocmget = cp210x_tiocmget, .tiocmset = cp210x_tiocmset, .attach = cp210x_startup, - .shutdown = cp210x_shutdown, + .disconnect = cp210x_disconnect, }; /* Config request types */ @@ -792,7 +792,7 @@ static int cp210x_startup(struct usb_serial *serial) return 0; } -static void cp210x_shutdown(struct usb_serial *serial) +static void cp210x_disconnect(struct usb_serial *serial) { int i; diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c index 933ba913e66..336523fd736 100644 --- a/drivers/usb/serial/cyberjack.c +++ b/drivers/usb/serial/cyberjack.c @@ -58,7 +58,8 @@ static int debug; /* Function prototypes */ static int cyberjack_startup(struct usb_serial *serial); -static void cyberjack_shutdown(struct usb_serial *serial); +static void cyberjack_disconnect(struct usb_serial *serial); +static void cyberjack_release(struct usb_serial *serial); static int cyberjack_open(struct tty_struct *tty, struct usb_serial_port *port, struct file *filp); static void cyberjack_close(struct usb_serial_port *port); @@ -94,7 +95,8 @@ static struct usb_serial_driver cyberjack_device = { .id_table = id_table, .num_ports = 1, .attach = cyberjack_startup, - .shutdown = cyberjack_shutdown, + .disconnect = cyberjack_disconnect, + .release = cyberjack_release, .open = cyberjack_open, .close = cyberjack_close, .write = cyberjack_write, @@ -148,17 +150,25 @@ static int cyberjack_startup(struct usb_serial *serial) return 0; } -static void cyberjack_shutdown(struct usb_serial *serial) +static void cyberjack_disconnect(struct usb_serial *serial) { int i; dbg("%s", __func__); - for (i = 0; i < serial->num_ports; ++i) { + for (i = 0; i < serial->num_ports; ++i) usb_kill_urb(serial->port[i]->interrupt_in_urb); +} + +static void cyberjack_release(struct usb_serial *serial) +{ + int i; + + dbg("%s", __func__); + + for (i = 0; i < serial->num_ports; ++i) { /* My special items, the standard routines free my urbs */ kfree(usb_get_serial_port_data(serial->port[i])); - usb_set_serial_port_data(serial->port[i], NULL); } } diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c index 669f9384853..9734085fd2f 100644 --- a/drivers/usb/serial/cypress_m8.c +++ b/drivers/usb/serial/cypress_m8.c @@ -171,7 +171,7 @@ struct cypress_buf { static int cypress_earthmate_startup(struct usb_serial *serial); static int cypress_hidcom_startup(struct usb_serial *serial); static int cypress_ca42v2_startup(struct usb_serial *serial); -static void cypress_shutdown(struct usb_serial *serial); +static void cypress_release(struct usb_serial *serial); static int cypress_open(struct tty_struct *tty, struct usb_serial_port *port, struct file *filp); static void cypress_close(struct usb_serial_port *port); @@ -215,7 +215,7 @@ static struct usb_serial_driver cypress_earthmate_device = { .id_table = id_table_earthmate, .num_ports = 1, .attach = cypress_earthmate_startup, - .shutdown = cypress_shutdown, + .release = cypress_release, .open = cypress_open, .close = cypress_close, .dtr_rts = cypress_dtr_rts, @@ -242,7 +242,7 @@ static struct usb_serial_driver cypress_hidcom_device = { .id_table = id_table_cyphidcomrs232, .num_ports = 1, .attach = cypress_hidcom_startup, - .shutdown = cypress_shutdown, + .release = cypress_release, .open = cypress_open, .close = cypress_close, .dtr_rts = cypress_dtr_rts, @@ -269,7 +269,7 @@ static struct usb_serial_driver cypress_ca42v2_device = { .id_table = id_table_nokiaca42v2, .num_ports = 1, .attach = cypress_ca42v2_startup, - .shutdown = cypress_shutdown, + .release = cypress_release, .open = cypress_open, .close = cypress_close, .dtr_rts = cypress_dtr_rts, @@ -616,7 +616,7 @@ static int cypress_ca42v2_startup(struct usb_serial *serial) } /* cypress_ca42v2_startup */ -static void cypress_shutdown(struct usb_serial *serial) +static void cypress_release(struct usb_serial *serial) { struct cypress_private *priv; @@ -629,7 +629,6 @@ static void cypress_shutdown(struct usb_serial *serial) if (priv) { cypress_buf_free(priv->buf); kfree(priv); - usb_set_serial_port_data(serial->port[0], NULL); } } diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c index 30f5140eff0..f4808091c47 100644 --- a/drivers/usb/serial/digi_acceleport.c +++ b/drivers/usb/serial/digi_acceleport.c @@ -460,7 +460,8 @@ static int digi_carrier_raised(struct usb_serial_port *port); static void digi_dtr_rts(struct usb_serial_port *port, int on); static int digi_startup_device(struct usb_serial *serial); static int digi_startup(struct usb_serial *serial); -static void digi_shutdown(struct usb_serial *serial); +static void digi_disconnect(struct usb_serial *serial); +static void digi_release(struct usb_serial *serial); static void digi_read_bulk_callback(struct urb *urb); static int digi_read_inb_callback(struct urb *urb); static int digi_read_oob_callback(struct urb *urb); @@ -524,7 +525,8 @@ static struct usb_serial_driver digi_acceleport_2_device = { .tiocmget = digi_tiocmget, .tiocmset = digi_tiocmset, .attach = digi_startup, - .shutdown = digi_shutdown, + .disconnect = digi_disconnect, + .release = digi_release, }; static struct usb_serial_driver digi_acceleport_4_device = { @@ -550,7 +552,8 @@ static struct usb_serial_driver digi_acceleport_4_device = { .tiocmget = digi_tiocmget, .tiocmset = digi_tiocmset, .attach = digi_startup, - .shutdown = digi_shutdown, + .disconnect = digi_disconnect, + .release = digi_release, }; @@ -1556,16 +1559,23 @@ static int digi_startup(struct usb_serial *serial) } -static void digi_shutdown(struct usb_serial *serial) +static void digi_disconnect(struct usb_serial *serial) { int i; - dbg("digi_shutdown: TOP, in_interrupt()=%ld", in_interrupt()); + dbg("digi_disconnect: TOP, in_interrupt()=%ld", in_interrupt()); /* stop reads and writes on all ports */ for (i = 0; i < serial->type->num_ports + 1; i++) { usb_kill_urb(serial->port[i]->read_urb); usb_kill_urb(serial->port[i]->write_urb); } +} + + +static void digi_release(struct usb_serial *serial) +{ + int i; + dbg("digi_release: TOP, in_interrupt()=%ld", in_interrupt()); /* free the private data structures for all ports */ /* number of regular ports + 1 for the out-of-band port */ diff --git a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c index 2b141ccb0cd..80cb3471adb 100644 --- a/drivers/usb/serial/empeg.c +++ b/drivers/usb/serial/empeg.c @@ -90,7 +90,6 @@ static int empeg_chars_in_buffer(struct tty_struct *tty); static void empeg_throttle(struct tty_struct *tty); static void empeg_unthrottle(struct tty_struct *tty); static int empeg_startup(struct usb_serial *serial); -static void empeg_shutdown(struct usb_serial *serial); static void empeg_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old_termios); static void empeg_write_bulk_callback(struct urb *urb); @@ -124,7 +123,6 @@ static struct usb_serial_driver empeg_device = { .throttle = empeg_throttle, .unthrottle = empeg_unthrottle, .attach = empeg_startup, - .shutdown = empeg_shutdown, .set_termios = empeg_set_termios, .write = empeg_write, .write_room = empeg_write_room, @@ -427,12 +425,6 @@ static int empeg_startup(struct usb_serial *serial) } -static void empeg_shutdown(struct usb_serial *serial) -{ - dbg("%s", __func__); -} - - static void empeg_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old_termios) { diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index fc423583eed..3dc3768ca71 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -720,7 +720,6 @@ static const char *ftdi_chip_name[] = { /* function prototypes for a FTDI serial converter */ static int ftdi_sio_probe(struct usb_serial *serial, const struct usb_device_id *id); -static void ftdi_shutdown(struct usb_serial *serial); static int ftdi_sio_port_probe(struct usb_serial_port *port); static int ftdi_sio_port_remove(struct usb_serial_port *port); static int ftdi_open(struct tty_struct *tty, @@ -779,7 +778,6 @@ static struct usb_serial_driver ftdi_sio_device = { .ioctl = ftdi_ioctl, .set_termios = ftdi_set_termios, .break_ctl = ftdi_break_ctl, - .shutdown = ftdi_shutdown, }; @@ -1594,18 +1592,6 @@ static int ftdi_mtxorb_hack_setup(struct usb_serial *serial) return 0; } -/* ftdi_shutdown is called from usbserial:usb_serial_disconnect - * it is called when the usb device is disconnected - * - * usbserial:usb_serial_disconnect - * calls __serial_close for each open of the port - * shutdown is called then (ie ftdi_shutdown) - */ -static void ftdi_shutdown(struct usb_serial *serial) -{ - dbg("%s", __func__); -} - static void ftdi_sio_priv_release(struct kref *k) { struct ftdi_private *priv = container_of(k, struct ftdi_private, kref); diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c index 5092d6aba65..8839f1c70b7 100644 --- a/drivers/usb/serial/garmin_gps.c +++ b/drivers/usb/serial/garmin_gps.c @@ -1475,7 +1475,7 @@ static int garmin_attach(struct usb_serial *serial) } -static void garmin_shutdown(struct usb_serial *serial) +static void garmin_disconnect(struct usb_serial *serial) { struct usb_serial_port *port = serial->port[0]; struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); @@ -1484,8 +1484,17 @@ static void garmin_shutdown(struct usb_serial *serial) usb_kill_urb(port->interrupt_in_urb); del_timer_sync(&garmin_data_p->timer); +} + + +static void garmin_release(struct usb_serial *serial) +{ + struct usb_serial_port *port = serial->port[0]; + struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); + + dbg("%s", __func__); + kfree(garmin_data_p); - usb_set_serial_port_data(port, NULL); } @@ -1504,7 +1513,8 @@ static struct usb_serial_driver garmin_device = { .throttle = garmin_throttle, .unthrottle = garmin_unthrottle, .attach = garmin_attach, - .shutdown = garmin_shutdown, + .disconnect = garmin_disconnect, + .release = garmin_release, .write = garmin_write, .write_room = garmin_write_room, .write_bulk_callback = garmin_write_bulk_callback, diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c index 8dabac1929b..932d6241b78 100644 --- a/drivers/usb/serial/generic.c +++ b/drivers/usb/serial/generic.c @@ -63,7 +63,8 @@ struct usb_serial_driver usb_serial_generic_device = { .id_table = generic_device_ids, .usb_driver = &generic_driver, .num_ports = 1, - .shutdown = usb_serial_generic_shutdown, + .disconnect = usb_serial_generic_disconnect, + .release = usb_serial_generic_release, .throttle = usb_serial_generic_throttle, .unthrottle = usb_serial_generic_unthrottle, .resume = usb_serial_generic_resume, @@ -551,7 +552,7 @@ int usb_serial_handle_break(struct usb_serial_port *port) } EXPORT_SYMBOL_GPL(usb_serial_handle_break); -void usb_serial_generic_shutdown(struct usb_serial *serial) +void usb_serial_generic_disconnect(struct usb_serial *serial) { int i; @@ -562,3 +563,7 @@ void usb_serial_generic_shutdown(struct usb_serial *serial) generic_cleanup(serial->port[i]); } +void usb_serial_generic_release(struct usb_serial *serial) +{ + dbg("%s", __func__); +} diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c index 53ef5996e33..0191693625d 100644 --- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c @@ -224,7 +224,8 @@ static int edge_tiocmget(struct tty_struct *tty, struct file *file); static int edge_tiocmset(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear); static int edge_startup(struct usb_serial *serial); -static void edge_shutdown(struct usb_serial *serial); +static void edge_disconnect(struct usb_serial *serial); +static void edge_release(struct usb_serial *serial); #include "io_tables.h" /* all of the devices that this driver supports */ @@ -3193,21 +3194,16 @@ static int edge_startup(struct usb_serial *serial) /**************************************************************************** - * edge_shutdown + * edge_disconnect * This function is called whenever the device is removed from the usb bus. ****************************************************************************/ -static void edge_shutdown(struct usb_serial *serial) +static void edge_disconnect(struct usb_serial *serial) { struct edgeport_serial *edge_serial = usb_get_serial_data(serial); - int i; dbg("%s", __func__); /* stop reads and writes on all ports */ - for (i = 0; i < serial->num_ports; ++i) { - kfree(usb_get_serial_port_data(serial->port[i])); - usb_set_serial_port_data(serial->port[i], NULL); - } /* free up our endpoint stuff */ if (edge_serial->is_epic) { usb_kill_urb(edge_serial->interrupt_read_urb); @@ -3218,9 +3214,24 @@ static void edge_shutdown(struct usb_serial *serial) usb_free_urb(edge_serial->read_urb); kfree(edge_serial->bulk_in_buffer); } +} + + +/**************************************************************************** + * edge_release + * This function is called when the device structure is deallocated. + ****************************************************************************/ +static void edge_release(struct usb_serial *serial) +{ + struct edgeport_serial *edge_serial = usb_get_serial_data(serial); + int i; + + dbg("%s", __func__); + + for (i = 0; i < serial->num_ports; ++i) + kfree(usb_get_serial_port_data(serial->port[i])); kfree(edge_serial); - usb_set_serial_data(serial, NULL); } diff --git a/drivers/usb/serial/io_tables.h b/drivers/usb/serial/io_tables.h index 7eb9d67b81b..9241d314751 100644 --- a/drivers/usb/serial/io_tables.h +++ b/drivers/usb/serial/io_tables.h @@ -117,7 +117,8 @@ static struct usb_serial_driver edgeport_2port_device = { .throttle = edge_throttle, .unthrottle = edge_unthrottle, .attach = edge_startup, - .shutdown = edge_shutdown, + .disconnect = edge_disconnect, + .release = edge_release, .ioctl = edge_ioctl, .set_termios = edge_set_termios, .tiocmget = edge_tiocmget, @@ -145,7 +146,8 @@ static struct usb_serial_driver edgeport_4port_device = { .throttle = edge_throttle, .unthrottle = edge_unthrottle, .attach = edge_startup, - .shutdown = edge_shutdown, + .disconnect = edge_disconnect, + .release = edge_release, .ioctl = edge_ioctl, .set_termios = edge_set_termios, .tiocmget = edge_tiocmget, @@ -173,7 +175,8 @@ static struct usb_serial_driver edgeport_8port_device = { .throttle = edge_throttle, .unthrottle = edge_unthrottle, .attach = edge_startup, - .shutdown = edge_shutdown, + .disconnect = edge_disconnect, + .release = edge_release, .ioctl = edge_ioctl, .set_termios = edge_set_termios, .tiocmget = edge_tiocmget, @@ -200,7 +203,8 @@ static struct usb_serial_driver epic_device = { .throttle = edge_throttle, .unthrottle = edge_unthrottle, .attach = edge_startup, - .shutdown = edge_shutdown, + .disconnect = edge_disconnect, + .release = edge_release, .ioctl = edge_ioctl, .set_termios = edge_set_termios, .tiocmget = edge_tiocmget, diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index db964db42d3..e8bc42f92e7 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -2663,7 +2663,7 @@ cleanup: return -ENOMEM; } -static void edge_shutdown(struct usb_serial *serial) +static void edge_disconnect(struct usb_serial *serial) { int i; struct edgeport_port *edge_port; @@ -2673,12 +2673,22 @@ static void edge_shutdown(struct usb_serial *serial) for (i = 0; i < serial->num_ports; ++i) { edge_port = usb_get_serial_port_data(serial->port[i]); edge_remove_sysfs_attrs(edge_port->port); + } +} + +static void edge_release(struct usb_serial *serial) +{ + int i; + struct edgeport_port *edge_port; + + dbg("%s", __func__); + + for (i = 0; i < serial->num_ports; ++i) { + edge_port = usb_get_serial_port_data(serial->port[i]); edge_buf_free(edge_port->ep_out_buf); kfree(edge_port); - usb_set_serial_port_data(serial->port[i], NULL); } kfree(usb_get_serial_data(serial)); - usb_set_serial_data(serial, NULL); } @@ -2915,7 +2925,8 @@ static struct usb_serial_driver edgeport_1port_device = { .throttle = edge_throttle, .unthrottle = edge_unthrottle, .attach = edge_startup, - .shutdown = edge_shutdown, + .disconnect = edge_disconnect, + .release = edge_release, .port_probe = edge_create_sysfs_attrs, .ioctl = edge_ioctl, .set_termios = edge_set_termios, @@ -2944,7 +2955,8 @@ static struct usb_serial_driver edgeport_2port_device = { .throttle = edge_throttle, .unthrottle = edge_unthrottle, .attach = edge_startup, - .shutdown = edge_shutdown, + .disconnect = edge_disconnect, + .release = edge_release, .port_probe = edge_create_sysfs_attrs, .ioctl = edge_ioctl, .set_termios = edge_set_termios, diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c index c610a99fa47..2545d45ce16 100644 --- a/drivers/usb/serial/ipaq.c +++ b/drivers/usb/serial/ipaq.c @@ -79,7 +79,6 @@ static int ipaq_open(struct tty_struct *tty, static void ipaq_close(struct usb_serial_port *port); static int ipaq_calc_num_ports(struct usb_serial *serial); static int ipaq_startup(struct usb_serial *serial); -static void ipaq_shutdown(struct usb_serial *serial); static int ipaq_write(struct tty_struct *tty, struct usb_serial_port *port, const unsigned char *buf, int count); static int ipaq_write_bulk(struct usb_serial_port *port, @@ -576,7 +575,6 @@ static struct usb_serial_driver ipaq_device = { .close = ipaq_close, .attach = ipaq_startup, .calc_num_ports = ipaq_calc_num_ports, - .shutdown = ipaq_shutdown, .write = ipaq_write, .write_room = ipaq_write_room, .chars_in_buffer = ipaq_chars_in_buffer, @@ -990,11 +988,6 @@ static int ipaq_startup(struct usb_serial *serial) return usb_reset_configuration(serial->dev); } -static void ipaq_shutdown(struct usb_serial *serial) -{ - dbg("%s", __func__); -} - static int __init ipaq_init(void) { int retval; diff --git a/drivers/usb/serial/iuu_phoenix.c b/drivers/usb/serial/iuu_phoenix.c index 76a3cc327bb..96873a7a32b 100644 --- a/drivers/usb/serial/iuu_phoenix.c +++ b/drivers/usb/serial/iuu_phoenix.c @@ -121,8 +121,8 @@ static int iuu_startup(struct usb_serial *serial) return 0; } -/* Shutdown function */ -static void iuu_shutdown(struct usb_serial *serial) +/* Release function */ +static void iuu_release(struct usb_serial *serial) { struct usb_serial_port *port = serial->port[0]; struct iuu_private *priv = usb_get_serial_port_data(port); @@ -1202,7 +1202,7 @@ static struct usb_serial_driver iuu_device = { .tiocmset = iuu_tiocmset, .set_termios = iuu_set_termios, .attach = iuu_startup, - .shutdown = iuu_shutdown, + .release = iuu_release, }; static int __init iuu_init(void) diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c index f1195a98f31..2594b8743d3 100644 --- a/drivers/usb/serial/keyspan.c +++ b/drivers/usb/serial/keyspan.c @@ -2689,7 +2689,7 @@ static int keyspan_startup(struct usb_serial *serial) return 0; } -static void keyspan_shutdown(struct usb_serial *serial) +static void keyspan_disconnect(struct usb_serial *serial) { int i, j; struct usb_serial_port *port; @@ -2729,6 +2729,17 @@ static void keyspan_shutdown(struct usb_serial *serial) usb_free_urb(p_priv->out_urbs[j]); } } +} + +static void keyspan_release(struct usb_serial *serial) +{ + int i; + struct usb_serial_port *port; + struct keyspan_serial_private *s_priv; + + dbg("%s", __func__); + + s_priv = usb_get_serial_data(serial); /* dbg("Freeing serial->private."); */ kfree(s_priv); diff --git a/drivers/usb/serial/keyspan.h b/drivers/usb/serial/keyspan.h index 0d4569b6076..3107ed15af6 100644 --- a/drivers/usb/serial/keyspan.h +++ b/drivers/usb/serial/keyspan.h @@ -41,7 +41,8 @@ static int keyspan_open (struct tty_struct *tty, static void keyspan_close (struct usb_serial_port *port); static void keyspan_dtr_rts (struct usb_serial_port *port, int on); static int keyspan_startup (struct usb_serial *serial); -static void keyspan_shutdown (struct usb_serial *serial); +static void keyspan_disconnect (struct usb_serial *serial); +static void keyspan_release (struct usb_serial *serial); static int keyspan_write_room (struct tty_struct *tty); static int keyspan_write (struct tty_struct *tty, @@ -569,7 +570,8 @@ static struct usb_serial_driver keyspan_1port_device = { .tiocmget = keyspan_tiocmget, .tiocmset = keyspan_tiocmset, .attach = keyspan_startup, - .shutdown = keyspan_shutdown, + .disconnect = keyspan_disconnect, + .release = keyspan_release, }; static struct usb_serial_driver keyspan_2port_device = { @@ -590,7 +592,8 @@ static struct usb_serial_driver keyspan_2port_device = { .tiocmget = keyspan_tiocmget, .tiocmset = keyspan_tiocmset, .attach = keyspan_startup, - .shutdown = keyspan_shutdown, + .disconnect = keyspan_disconnect, + .release = keyspan_release, }; static struct usb_serial_driver keyspan_4port_device = { @@ -611,7 +614,8 @@ static struct usb_serial_driver keyspan_4port_device = { .tiocmget = keyspan_tiocmget, .tiocmset = keyspan_tiocmset, .attach = keyspan_startup, - .shutdown = keyspan_shutdown, + .disconnect = keyspan_disconnect, + .release = keyspan_release, }; #endif diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c index ab769dbea1b..d0b12e40c2b 100644 --- a/drivers/usb/serial/keyspan_pda.c +++ b/drivers/usb/serial/keyspan_pda.c @@ -809,7 +809,7 @@ static int keyspan_pda_startup(struct usb_serial *serial) return 0; } -static void keyspan_pda_shutdown(struct usb_serial *serial) +static void keyspan_pda_release(struct usb_serial *serial) { dbg("%s", __func__); @@ -869,7 +869,7 @@ static struct usb_serial_driver keyspan_pda_device = { .tiocmget = keyspan_pda_tiocmget, .tiocmset = keyspan_pda_tiocmset, .attach = keyspan_pda_startup, - .shutdown = keyspan_pda_shutdown, + .release = keyspan_pda_release, }; diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c index fa817c66b3e..0f44bb8e8d4 100644 --- a/drivers/usb/serial/kl5kusb105.c +++ b/drivers/usb/serial/kl5kusb105.c @@ -73,7 +73,8 @@ static int debug; * Function prototypes */ static int klsi_105_startup(struct usb_serial *serial); -static void klsi_105_shutdown(struct usb_serial *serial); +static void klsi_105_disconnect(struct usb_serial *serial); +static void klsi_105_release(struct usb_serial *serial); static int klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port, struct file *filp); static void klsi_105_close(struct usb_serial_port *port); @@ -131,7 +132,8 @@ static struct usb_serial_driver kl5kusb105d_device = { .tiocmget = klsi_105_tiocmget, .tiocmset = klsi_105_tiocmset, .attach = klsi_105_startup, - .shutdown = klsi_105_shutdown, + .disconnect = klsi_105_disconnect, + .release = klsi_105_release, .throttle = klsi_105_throttle, .unthrottle = klsi_105_unthrottle, }; @@ -315,7 +317,7 @@ err_cleanup: } /* klsi_105_startup */ -static void klsi_105_shutdown(struct usb_serial *serial) +static void klsi_105_disconnect(struct usb_serial *serial) { int i; @@ -325,33 +327,36 @@ static void klsi_105_shutdown(struct usb_serial *serial) for (i = 0; i < serial->num_ports; ++i) { struct klsi_105_private *priv = usb_get_serial_port_data(serial->port[i]); - unsigned long flags; if (priv) { /* kill our write urb pool */ int j; struct urb **write_urbs = priv->write_urb_pool; - spin_lock_irqsave(&priv->lock, flags); for (j = 0; j < NUM_URBS; j++) { if (write_urbs[j]) { - /* FIXME - uncomment the following - * usb_kill_urb call when the host - * controllers get fixed to set - * urb->dev = NULL after the urb is - * finished. Otherwise this call - * oopses. */ - /* usb_kill_urb(write_urbs[j]); */ - kfree(write_urbs[j]->transfer_buffer); + usb_kill_urb(write_urbs[j]); usb_free_urb(write_urbs[j]); } } - spin_unlock_irqrestore(&priv->lock, flags); - kfree(priv); - usb_set_serial_port_data(serial->port[i], NULL); } } -} /* klsi_105_shutdown */ +} /* klsi_105_disconnect */ + + +static void klsi_105_release(struct usb_serial *serial) +{ + int i; + + dbg("%s", __func__); + + for (i = 0; i < serial->num_ports; ++i) { + struct klsi_105_private *priv = + usb_get_serial_port_data(serial->port[i]); + + kfree(priv); + } +} /* klsi_105_release */ static int klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port, struct file *filp) diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c index 6b570498287..6db0e561f68 100644 --- a/drivers/usb/serial/kobil_sct.c +++ b/drivers/usb/serial/kobil_sct.c @@ -69,7 +69,7 @@ static int debug; /* Function prototypes */ static int kobil_startup(struct usb_serial *serial); -static void kobil_shutdown(struct usb_serial *serial); +static void kobil_release(struct usb_serial *serial); static int kobil_open(struct tty_struct *tty, struct usb_serial_port *port, struct file *filp); static void kobil_close(struct usb_serial_port *port); @@ -117,7 +117,7 @@ static struct usb_serial_driver kobil_device = { .id_table = id_table, .num_ports = 1, .attach = kobil_startup, - .shutdown = kobil_shutdown, + .release = kobil_release, .ioctl = kobil_ioctl, .set_termios = kobil_set_termios, .tiocmget = kobil_tiocmget, @@ -201,17 +201,13 @@ static int kobil_startup(struct usb_serial *serial) } -static void kobil_shutdown(struct usb_serial *serial) +static void kobil_release(struct usb_serial *serial) { int i; dbg("%s - port %d", __func__, serial->port[0]->number); - for (i = 0; i < serial->num_ports; ++i) { - while (serial->port[i]->port.count > 0) - kobil_close(serial->port[i]); + for (i = 0; i < serial->num_ports; ++i) kfree(usb_get_serial_port_data(serial->port[i])); - usb_set_serial_port_data(serial->port[i], NULL); - } } diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c index 873795548fc..d8825e159aa 100644 --- a/drivers/usb/serial/mct_u232.c +++ b/drivers/usb/serial/mct_u232.c @@ -92,7 +92,7 @@ static int debug; * Function prototypes */ static int mct_u232_startup(struct usb_serial *serial); -static void mct_u232_shutdown(struct usb_serial *serial); +static void mct_u232_release(struct usb_serial *serial); static int mct_u232_open(struct tty_struct *tty, struct usb_serial_port *port, struct file *filp); static void mct_u232_close(struct usb_serial_port *port); @@ -149,7 +149,7 @@ static struct usb_serial_driver mct_u232_device = { .tiocmget = mct_u232_tiocmget, .tiocmset = mct_u232_tiocmset, .attach = mct_u232_startup, - .shutdown = mct_u232_shutdown, + .release = mct_u232_release, }; @@ -407,7 +407,7 @@ static int mct_u232_startup(struct usb_serial *serial) } /* mct_u232_startup */ -static void mct_u232_shutdown(struct usb_serial *serial) +static void mct_u232_release(struct usb_serial *serial) { struct mct_u232_private *priv; int i; @@ -417,12 +417,9 @@ static void mct_u232_shutdown(struct usb_serial *serial) for (i = 0; i < serial->num_ports; ++i) { /* My special items, the standard routines free my urbs */ priv = usb_get_serial_port_data(serial->port[i]); - if (priv) { - usb_set_serial_port_data(serial->port[i], NULL); - kfree(priv); - } + kfree(priv); } -} /* mct_u232_shutdown */ +} /* mct_u232_release */ static int mct_u232_open(struct tty_struct *tty, struct usb_serial_port *port, struct file *filp) diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c index 9e1a013ee7f..bfc5ce000ef 100644 --- a/drivers/usb/serial/mos7720.c +++ b/drivers/usb/serial/mos7720.c @@ -1521,19 +1521,16 @@ static int mos7720_startup(struct usb_serial *serial) return 0; } -static void mos7720_shutdown(struct usb_serial *serial) +static void mos7720_release(struct usb_serial *serial) { int i; /* free private structure allocated for serial port */ - for (i = 0; i < serial->num_ports; ++i) { + for (i = 0; i < serial->num_ports; ++i) kfree(usb_get_serial_port_data(serial->port[i])); - usb_set_serial_port_data(serial->port[i], NULL); - } /* free private structure allocated for serial device */ kfree(usb_get_serial_data(serial)); - usb_set_serial_data(serial, NULL); } static struct usb_driver usb_driver = { @@ -1558,7 +1555,7 @@ static struct usb_serial_driver moschip7720_2port_driver = { .throttle = mos7720_throttle, .unthrottle = mos7720_unthrottle, .attach = mos7720_startup, - .shutdown = mos7720_shutdown, + .release = mos7720_release, .ioctl = mos7720_ioctl, .set_termios = mos7720_set_termios, .write = mos7720_write, diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index 5fe9fe3df77..c40f95c1951 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -2633,16 +2633,16 @@ error: } /**************************************************************************** - * mos7840_shutdown + * mos7840_disconnect * This function is called whenever the device is removed from the usb bus. ****************************************************************************/ -static void mos7840_shutdown(struct usb_serial *serial) +static void mos7840_disconnect(struct usb_serial *serial) { int i; unsigned long flags; struct moschip_port *mos7840_port; - dbg("%s", " shutdown :entering.........."); + dbg("%s", " disconnect :entering.........."); if (!serial) { dbg("%s", "Invalid Handler"); @@ -2662,11 +2662,42 @@ static void mos7840_shutdown(struct usb_serial *serial) mos7840_port->zombie = 1; spin_unlock_irqrestore(&mos7840_port->pool_lock, flags); usb_kill_urb(mos7840_port->control_urb); + } + } + + dbg("%s", "Thank u :: "); + +} + +/**************************************************************************** + * mos7840_release + * This function is called when the usb_serial structure is freed. + ****************************************************************************/ + +static void mos7840_release(struct usb_serial *serial) +{ + int i; + struct moschip_port *mos7840_port; + dbg("%s", " release :entering.........."); + + if (!serial) { + dbg("%s", "Invalid Handler"); + return; + } + + /* check for the ports to be closed,close the ports and disconnect */ + + /* free private structure allocated for serial port * + * stop reads and writes on all ports */ + + for (i = 0; i < serial->num_ports; ++i) { + mos7840_port = mos7840_get_port_private(serial->port[i]); + dbg("mos7840_port %d = %p", i, mos7840_port); + if (mos7840_port) { kfree(mos7840_port->ctrl_buf); kfree(mos7840_port->dr); kfree(mos7840_port); } - mos7840_set_port_private(serial->port[i], NULL); } dbg("%s", "Thank u :: "); @@ -2707,7 +2738,8 @@ static struct usb_serial_driver moschip7840_4port_device = { .tiocmget = mos7840_tiocmget, .tiocmset = mos7840_tiocmset, .attach = mos7840_startup, - .shutdown = mos7840_shutdown, + .disconnect = mos7840_disconnect, + .release = mos7840_release, .read_bulk_callback = mos7840_bulk_in_callback, .read_int_callback = mos7840_interrupt_callback, }; diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c index 1104617334f..56857ddbd70 100644 --- a/drivers/usb/serial/omninet.c +++ b/drivers/usb/serial/omninet.c @@ -72,7 +72,8 @@ static void omninet_write_bulk_callback(struct urb *urb); static int omninet_write(struct tty_struct *tty, struct usb_serial_port *port, const unsigned char *buf, int count); static int omninet_write_room(struct tty_struct *tty); -static void omninet_shutdown(struct usb_serial *serial); +static void omninet_disconnect(struct usb_serial *serial); +static void omninet_release(struct usb_serial *serial); static int omninet_attach(struct usb_serial *serial); static struct usb_device_id id_table[] = { @@ -108,7 +109,8 @@ static struct usb_serial_driver zyxel_omninet_device = { .write_room = omninet_write_room, .read_bulk_callback = omninet_read_bulk_callback, .write_bulk_callback = omninet_write_bulk_callback, - .shutdown = omninet_shutdown, + .disconnect = omninet_disconnect, + .release = omninet_release, }; @@ -345,13 +347,22 @@ static void omninet_write_bulk_callback(struct urb *urb) } -static void omninet_shutdown(struct usb_serial *serial) +static void omninet_disconnect(struct usb_serial *serial) { struct usb_serial_port *wport = serial->port[1]; - struct usb_serial_port *port = serial->port[0]; + dbg("%s", __func__); usb_kill_urb(wport->write_urb); +} + + +static void omninet_release(struct usb_serial *serial) +{ + struct usb_serial_port *port = serial->port[0]; + + dbg("%s", __func__); + kfree(usb_get_serial_port_data(port)); } diff --git a/drivers/usb/serial/opticon.c b/drivers/usb/serial/opticon.c index c20480aa975..336bba79ad3 100644 --- a/drivers/usb/serial/opticon.c +++ b/drivers/usb/serial/opticon.c @@ -463,7 +463,7 @@ error: return retval; } -static void opticon_shutdown(struct usb_serial *serial) +static void opticon_disconnect(struct usb_serial *serial) { struct opticon_private *priv = usb_get_serial_data(serial); @@ -471,9 +471,16 @@ static void opticon_shutdown(struct usb_serial *serial) usb_kill_urb(priv->bulk_read_urb); usb_free_urb(priv->bulk_read_urb); +} + +static void opticon_release(struct usb_serial *serial) +{ + struct opticon_private *priv = usb_get_serial_data(serial); + + dbg("%s", __func__); + kfree(priv->bulk_in_buffer); kfree(priv); - usb_set_serial_data(serial, NULL); } static int opticon_suspend(struct usb_interface *intf, pm_message_t message) @@ -524,7 +531,8 @@ static struct usb_serial_driver opticon_device = { .close = opticon_close, .write = opticon_write, .write_room = opticon_write_room, - .shutdown = opticon_shutdown, + .disconnect = opticon_disconnect, + .release = opticon_release, .throttle = opticon_throttle, .unthrottle = opticon_unthrottle, .ioctl = opticon_ioctl, diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index a38971cc373..575816e6ba3 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -51,7 +51,8 @@ static void option_close(struct usb_serial_port *port); static void option_dtr_rts(struct usb_serial_port *port, int on); static int option_startup(struct usb_serial *serial); -static void option_shutdown(struct usb_serial *serial); +static void option_disconnect(struct usb_serial *serial); +static void option_release(struct usb_serial *serial); static int option_write_room(struct tty_struct *tty); static void option_instat_callback(struct urb *urb); @@ -568,7 +569,8 @@ static struct usb_serial_driver option_1port_device = { .tiocmget = option_tiocmget, .tiocmset = option_tiocmset, .attach = option_startup, - .shutdown = option_shutdown, + .disconnect = option_disconnect, + .release = option_release, .read_int_callback = option_instat_callback, .suspend = option_suspend, .resume = option_resume, @@ -1149,7 +1151,14 @@ static void stop_read_write_urbs(struct usb_serial *serial) } } -static void option_shutdown(struct usb_serial *serial) +static void option_disconnect(struct usb_serial *serial) +{ + dbg("%s", __func__); + + stop_read_write_urbs(serial); +} + +static void option_release(struct usb_serial *serial) { int i, j; struct usb_serial_port *port; @@ -1157,8 +1166,6 @@ static void option_shutdown(struct usb_serial *serial) dbg("%s", __func__); - stop_read_write_urbs(serial); - /* Now free them */ for (i = 0; i < serial->num_ports; ++i) { port = serial->port[i]; diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c index 7de54781fe6..3cece27325e 100644 --- a/drivers/usb/serial/oti6858.c +++ b/drivers/usb/serial/oti6858.c @@ -159,7 +159,7 @@ static int oti6858_tiocmget(struct tty_struct *tty, struct file *file); static int oti6858_tiocmset(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear); static int oti6858_startup(struct usb_serial *serial); -static void oti6858_shutdown(struct usb_serial *serial); +static void oti6858_release(struct usb_serial *serial); /* functions operating on buffers */ static struct oti6858_buf *oti6858_buf_alloc(unsigned int size); @@ -194,7 +194,7 @@ static struct usb_serial_driver oti6858_device = { .write_room = oti6858_write_room, .chars_in_buffer = oti6858_chars_in_buffer, .attach = oti6858_startup, - .shutdown = oti6858_shutdown, + .release = oti6858_release, }; struct oti6858_private { @@ -782,7 +782,7 @@ static int oti6858_ioctl(struct tty_struct *tty, struct file *file, } -static void oti6858_shutdown(struct usb_serial *serial) +static void oti6858_release(struct usb_serial *serial) { struct oti6858_private *priv; int i; @@ -794,7 +794,6 @@ static void oti6858_shutdown(struct usb_serial *serial) if (priv) { oti6858_buf_free(priv->buf); kfree(priv); - usb_set_serial_port_data(serial->port[i], NULL); } } } diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index 6357b57f628..ec6c132a25b 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -878,7 +878,7 @@ static void pl2303_break_ctl(struct tty_struct *tty, int break_state) dbg("%s - error sending break = %d", __func__, result); } -static void pl2303_shutdown(struct usb_serial *serial) +static void pl2303_release(struct usb_serial *serial) { int i; struct pl2303_private *priv; @@ -890,7 +890,6 @@ static void pl2303_shutdown(struct usb_serial *serial) if (priv) { pl2303_buf_free(priv->buf); kfree(priv); - usb_set_serial_port_data(serial->port[i], NULL); } } } @@ -1123,7 +1122,7 @@ static struct usb_serial_driver pl2303_device = { .write_room = pl2303_write_room, .chars_in_buffer = pl2303_chars_in_buffer, .attach = pl2303_startup, - .shutdown = pl2303_shutdown, + .release = pl2303_release, }; static int __init pl2303_init(void) diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c index a88cde95016..032f7aeb40a 100644 --- a/drivers/usb/serial/sierra.c +++ b/drivers/usb/serial/sierra.c @@ -814,7 +814,7 @@ static int sierra_startup(struct usb_serial *serial) return 0; } -static void sierra_shutdown(struct usb_serial *serial) +static void sierra_disconnect(struct usb_serial *serial) { int i; struct usb_serial_port *port; @@ -853,7 +853,7 @@ static struct usb_serial_driver sierra_device = { .tiocmget = sierra_tiocmget, .tiocmset = sierra_tiocmset, .attach = sierra_startup, - .shutdown = sierra_shutdown, + .disconnect = sierra_disconnect, .read_int_callback = sierra_instat_callback, }; diff --git a/drivers/usb/serial/spcp8x5.c b/drivers/usb/serial/spcp8x5.c index 8f7ed8f1399..3c249d8e8b8 100644 --- a/drivers/usb/serial/spcp8x5.c +++ b/drivers/usb/serial/spcp8x5.c @@ -356,7 +356,7 @@ cleanup: } /* call when the device plug out. free all the memory alloced by probe */ -static void spcp8x5_shutdown(struct usb_serial *serial) +static void spcp8x5_release(struct usb_serial *serial) { int i; struct spcp8x5_private *priv; @@ -366,7 +366,6 @@ static void spcp8x5_shutdown(struct usb_serial *serial) if (priv) { free_ringbuf(priv->buf); kfree(priv); - usb_set_serial_port_data(serial->port[i] , NULL); } } } @@ -1020,7 +1019,7 @@ static struct usb_serial_driver spcp8x5_device = { .write_bulk_callback = spcp8x5_write_bulk_callback, .chars_in_buffer = spcp8x5_chars_in_buffer, .attach = spcp8x5_startup, - .shutdown = spcp8x5_shutdown, + .release = spcp8x5_release, }; static int __init spcp8x5_init(void) diff --git a/drivers/usb/serial/symbolserial.c b/drivers/usb/serial/symbolserial.c index 8b07ebc6bae..6157fac9366 100644 --- a/drivers/usb/serial/symbolserial.c +++ b/drivers/usb/serial/symbolserial.c @@ -267,7 +267,7 @@ error: return retval; } -static void symbol_shutdown(struct usb_serial *serial) +static void symbol_disconnect(struct usb_serial *serial) { struct symbol_private *priv = usb_get_serial_data(serial); @@ -275,9 +275,16 @@ static void symbol_shutdown(struct usb_serial *serial) usb_kill_urb(priv->int_urb); usb_free_urb(priv->int_urb); +} + +static void symbol_release(struct usb_serial *serial) +{ + struct symbol_private *priv = usb_get_serial_data(serial); + + dbg("%s", __func__); + kfree(priv->int_buffer); kfree(priv); - usb_set_serial_data(serial, NULL); } static struct usb_driver symbol_driver = { @@ -299,7 +306,8 @@ static struct usb_serial_driver symbol_device = { .attach = symbol_startup, .open = symbol_open, .close = symbol_close, - .shutdown = symbol_shutdown, + .disconnect = symbol_disconnect, + .release = symbol_release, .throttle = symbol_throttle, .unthrottle = symbol_unthrottle, }; diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index 42cb04c403b..991d8232e37 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -97,7 +97,7 @@ struct ti_device { /* Function Declarations */ static int ti_startup(struct usb_serial *serial); -static void ti_shutdown(struct usb_serial *serial); +static void ti_release(struct usb_serial *serial); static int ti_open(struct tty_struct *tty, struct usb_serial_port *port, struct file *file); static void ti_close(struct usb_serial_port *port); @@ -230,7 +230,7 @@ static struct usb_serial_driver ti_1port_device = { .id_table = ti_id_table_3410, .num_ports = 1, .attach = ti_startup, - .shutdown = ti_shutdown, + .release = ti_release, .open = ti_open, .close = ti_close, .write = ti_write, @@ -258,7 +258,7 @@ static struct usb_serial_driver ti_2port_device = { .id_table = ti_id_table_5052, .num_ports = 2, .attach = ti_startup, - .shutdown = ti_shutdown, + .release = ti_release, .open = ti_open, .close = ti_close, .write = ti_write, @@ -473,7 +473,7 @@ free_tdev: } -static void ti_shutdown(struct usb_serial *serial) +static void ti_release(struct usb_serial *serial) { int i; struct ti_device *tdev = usb_get_serial_data(serial); @@ -486,12 +486,10 @@ static void ti_shutdown(struct usb_serial *serial) if (tport) { ti_buf_free(tport->tp_write_buf); kfree(tport); - usb_set_serial_port_data(serial->port[i], NULL); } } kfree(tdev); - usb_set_serial_data(serial, NULL); } diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index da890f030fa..d595aa5586a 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -141,6 +141,14 @@ static void destroy_serial(struct kref *kref) if (serial->minor != SERIAL_TTY_NO_MINOR) return_serial(serial); + serial->type->release(serial); + + for (i = 0; i < serial->num_ports; ++i) { + port = serial->port[i]; + if (port) + put_device(&port->dev); + } + /* If this is a "fake" port, we have to clean it up here, as it will * not get cleaned up in port_release() as it was never registered with * the driver core */ @@ -148,9 +156,8 @@ static void destroy_serial(struct kref *kref) for (i = serial->num_ports; i < serial->num_port_pointers; ++i) { port = serial->port[i]; - if (!port) - continue; - port_free(port); + if (port) + port_free(port); } } @@ -1118,10 +1125,6 @@ void usb_serial_disconnect(struct usb_interface *interface) serial->disconnected = 1; mutex_unlock(&serial->disc_mutex); - /* Unfortunately, many of the sub-drivers expect the port structures - * to exist when their shutdown method is called, so we have to go - * through this awkward two-step unregistration procedure. - */ for (i = 0; i < serial->num_ports; ++i) { port = serial->port[i]; if (port) { @@ -1153,14 +1156,7 @@ void usb_serial_disconnect(struct usb_interface *interface) } } } - serial->type->shutdown(serial); - for (i = 0; i < serial->num_ports; ++i) { - port = serial->port[i]; - if (port) { - put_device(&port->dev); - serial->port[i] = NULL; - } - } + serial->type->disconnect(serial); /* let the last holder of this object * cause it to be cleaned up */ @@ -1338,7 +1334,8 @@ static void fixup_generic(struct usb_serial_driver *device) set_to_generic_if_null(device, chars_in_buffer); set_to_generic_if_null(device, read_bulk_callback); set_to_generic_if_null(device, write_bulk_callback); - set_to_generic_if_null(device, shutdown); + set_to_generic_if_null(device, disconnect); + set_to_generic_if_null(device, release); } int usb_serial_register(struct usb_serial_driver *driver) diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c index b15f1c0e1d4..f5d0f64dcc5 100644 --- a/drivers/usb/serial/visor.c +++ b/drivers/usb/serial/visor.c @@ -47,7 +47,7 @@ static void visor_unthrottle(struct tty_struct *tty); static int visor_probe(struct usb_serial *serial, const struct usb_device_id *id); static int visor_calc_num_ports(struct usb_serial *serial); -static void visor_shutdown(struct usb_serial *serial); +static void visor_release(struct usb_serial *serial); static void visor_write_bulk_callback(struct urb *urb); static void visor_read_bulk_callback(struct urb *urb); static void visor_read_int_callback(struct urb *urb); @@ -202,7 +202,7 @@ static struct usb_serial_driver handspring_device = { .attach = treo_attach, .probe = visor_probe, .calc_num_ports = visor_calc_num_ports, - .shutdown = visor_shutdown, + .release = visor_release, .write = visor_write, .write_room = visor_write_room, .write_bulk_callback = visor_write_bulk_callback, @@ -227,7 +227,7 @@ static struct usb_serial_driver clie_5_device = { .attach = clie_5_attach, .probe = visor_probe, .calc_num_ports = visor_calc_num_ports, - .shutdown = visor_shutdown, + .release = visor_release, .write = visor_write, .write_room = visor_write_room, .write_bulk_callback = visor_write_bulk_callback, @@ -918,7 +918,7 @@ static int clie_5_attach(struct usb_serial *serial) return generic_startup(serial); } -static void visor_shutdown(struct usb_serial *serial) +static void visor_release(struct usb_serial *serial) { struct visor_private *priv; int i; @@ -927,10 +927,7 @@ static void visor_shutdown(struct usb_serial *serial) for (i = 0; i < serial->num_ports; i++) { priv = usb_get_serial_port_data(serial->port[i]); - if (priv) { - usb_set_serial_port_data(serial->port[i], NULL); - kfree(priv); - } + kfree(priv); } } diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c index 7c7295d09f3..8d126dd7a02 100644 --- a/drivers/usb/serial/whiteheat.c +++ b/drivers/usb/serial/whiteheat.c @@ -144,7 +144,7 @@ static int whiteheat_firmware_attach(struct usb_serial *serial); /* function prototypes for the Connect Tech WhiteHEAT serial converter */ static int whiteheat_attach(struct usb_serial *serial); -static void whiteheat_shutdown(struct usb_serial *serial); +static void whiteheat_release(struct usb_serial *serial); static int whiteheat_open(struct tty_struct *tty, struct usb_serial_port *port, struct file *filp); static void whiteheat_close(struct usb_serial_port *port); @@ -189,7 +189,7 @@ static struct usb_serial_driver whiteheat_device = { .id_table = id_table_std, .num_ports = 4, .attach = whiteheat_attach, - .shutdown = whiteheat_shutdown, + .release = whiteheat_release, .open = whiteheat_open, .close = whiteheat_close, .write = whiteheat_write, @@ -617,7 +617,7 @@ no_command_buffer: } -static void whiteheat_shutdown(struct usb_serial *serial) +static void whiteheat_release(struct usb_serial *serial) { struct usb_serial_port *command_port; struct usb_serial_port *port; diff --git a/include/linux/usb/serial.h b/include/linux/usb/serial.h index ed4aa0fa7ed..44801d26a37 100644 --- a/include/linux/usb/serial.h +++ b/include/linux/usb/serial.h @@ -194,8 +194,10 @@ static inline void usb_set_serial_data(struct usb_serial *serial, void *data) * This will be called when the struct usb_serial structure is fully set * set up. Do any local initialization of the device, or any private * memory structure allocation at this point in time. - * @shutdown: pointer to the driver's shutdown function. This will be - * called when the device is removed from the system. + * @disconnect: pointer to the driver's disconnect function. This will be + * called when the device is unplugged or unbound from the driver. + * @release: pointer to the driver's release function. This will be called + * when the usb_serial data structure is about to be destroyed. * @usb_driver: pointer to the struct usb_driver that controls this * device. This is necessary to allow dynamic ids to be added to * the driver from sysfs. @@ -226,7 +228,8 @@ struct usb_serial_driver { int (*attach)(struct usb_serial *serial); int (*calc_num_ports) (struct usb_serial *serial); - void (*shutdown)(struct usb_serial *serial); + void (*disconnect)(struct usb_serial *serial); + void (*release)(struct usb_serial *serial); int (*port_probe)(struct usb_serial_port *port); int (*port_remove)(struct usb_serial_port *port); @@ -308,7 +311,8 @@ extern void usb_serial_generic_read_bulk_callback(struct urb *urb); extern void usb_serial_generic_write_bulk_callback(struct urb *urb); extern void usb_serial_generic_throttle(struct tty_struct *tty); extern void usb_serial_generic_unthrottle(struct tty_struct *tty); -extern void usb_serial_generic_shutdown(struct usb_serial *serial); +extern void usb_serial_generic_disconnect(struct usb_serial *serial); +extern void usb_serial_generic_release(struct usb_serial *serial); extern int usb_serial_generic_register(int debug); extern void usb_serial_generic_deregister(void); extern void usb_serial_generic_resubmit_read_urb(struct usb_serial_port *port, -- cgit v1.2.3-70-g09d2