| From oliver@neukum.org Mon Jul 2 07:20:32 2007 |
| From: Oliver Neukum <oliver@neukum.org> |
| Date: Mon, 2 Jul 2007 16:20:25 +0200 |
| Subject: USB: fix for ftdi_sio quirk handling |
| To: gregkh@suse.de, linux-usb-devel@lists.sourceforge.net |
| Message-ID: <200707021620.25672.oliver@neukum.org> |
| Content-Disposition: inline |
| |
| From: Oliver Neukum <oliver@neukum.org> |
| |
| this one fixes an oops with quirky ftdi_sio devices. As it fixes a |
| regression, I propose that it be included in 2.6.22 |
| |
| Signed-off-by: Oliver Neukum <oneukum@suse.de> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> |
| |
| --- |
| drivers/usb/serial/ftdi_sio.c | 104 +++++++++++++++++------------------------- |
| 1 file changed, 44 insertions(+), 60 deletions(-) |
| |
| --- a/drivers/usb/serial/ftdi_sio.c |
| +++ b/drivers/usb/serial/ftdi_sio.c |
| @@ -271,26 +271,58 @@ static int debug; |
| static __u16 vendor = FTDI_VID; |
| static __u16 product; |
| |
| +struct ftdi_private { |
| + ftdi_chip_type_t chip_type; |
| + /* type of the device, either SIO or FT8U232AM */ |
| + int baud_base; /* baud base clock for divisor setting */ |
| + int custom_divisor; /* custom_divisor kludge, this is for baud_base (different from what goes to the chip!) */ |
| + __u16 last_set_data_urb_value ; |
| + /* the last data state set - needed for doing a break */ |
| + int write_offset; /* This is the offset in the usb data block to write the serial data - |
| + * it is different between devices |
| + */ |
| + int flags; /* some ASYNC_xxxx flags are supported */ |
| + unsigned long last_dtr_rts; /* saved modem control outputs */ |
| + wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */ |
| + char prev_status, diff_status; /* Used for TIOCMIWAIT */ |
| + __u8 rx_flags; /* receive state flags (throttling) */ |
| + spinlock_t rx_lock; /* spinlock for receive state */ |
| + struct delayed_work rx_work; |
| + struct usb_serial_port *port; |
| + int rx_processed; |
| + unsigned long rx_bytes; |
| + |
| + __u16 interface; /* FT2232C port interface (0 for FT232/245) */ |
| + |
| + int force_baud; /* if non-zero, force the baud rate to this value */ |
| + int force_rtscts; /* if non-zero, force RTS-CTS to always be enabled */ |
| + |
| + spinlock_t tx_lock; /* spinlock for transmit state */ |
| + unsigned long tx_bytes; |
| + unsigned long tx_outstanding_bytes; |
| + unsigned long tx_outstanding_urbs; |
| +}; |
| + |
| /* struct ftdi_sio_quirk is used by devices requiring special attention. */ |
| struct ftdi_sio_quirk { |
| int (*probe)(struct usb_serial *); |
| - void (*setup)(struct usb_serial *); /* Special settings during startup. */ |
| + void (*port_probe)(struct ftdi_private *); /* Special settings for probed ports. */ |
| }; |
| |
| static int ftdi_olimex_probe (struct usb_serial *serial); |
| -static void ftdi_USB_UIRT_setup (struct usb_serial *serial); |
| -static void ftdi_HE_TIRA1_setup (struct usb_serial *serial); |
| +static void ftdi_USB_UIRT_setup (struct ftdi_private *priv); |
| +static void ftdi_HE_TIRA1_setup (struct ftdi_private *priv); |
| |
| static struct ftdi_sio_quirk ftdi_olimex_quirk = { |
| .probe = ftdi_olimex_probe, |
| }; |
| |
| static struct ftdi_sio_quirk ftdi_USB_UIRT_quirk = { |
| - .setup = ftdi_USB_UIRT_setup, |
| + .port_probe = ftdi_USB_UIRT_setup, |
| }; |
| |
| static struct ftdi_sio_quirk ftdi_HE_TIRA1_quirk = { |
| - .setup = ftdi_HE_TIRA1_setup, |
| + .port_probe = ftdi_HE_TIRA1_setup, |
| }; |
| |
| /* |
| @@ -567,38 +599,6 @@ static const char *ftdi_chip_name[] = { |
| #define THROTTLED 0x01 |
| #define ACTUALLY_THROTTLED 0x02 |
| |
| -struct ftdi_private { |
| - ftdi_chip_type_t chip_type; |
| - /* type of the device, either SIO or FT8U232AM */ |
| - int baud_base; /* baud base clock for divisor setting */ |
| - int custom_divisor; /* custom_divisor kludge, this is for baud_base (different from what goes to the chip!) */ |
| - __u16 last_set_data_urb_value ; |
| - /* the last data state set - needed for doing a break */ |
| - int write_offset; /* This is the offset in the usb data block to write the serial data - |
| - * it is different between devices |
| - */ |
| - int flags; /* some ASYNC_xxxx flags are supported */ |
| - unsigned long last_dtr_rts; /* saved modem control outputs */ |
| - wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */ |
| - char prev_status, diff_status; /* Used for TIOCMIWAIT */ |
| - __u8 rx_flags; /* receive state flags (throttling) */ |
| - spinlock_t rx_lock; /* spinlock for receive state */ |
| - struct delayed_work rx_work; |
| - struct usb_serial_port *port; |
| - int rx_processed; |
| - unsigned long rx_bytes; |
| - |
| - __u16 interface; /* FT2232C port interface (0 for FT232/245) */ |
| - |
| - int force_baud; /* if non-zero, force the baud rate to this value */ |
| - int force_rtscts; /* if non-zero, force RTS-CTS to always be enabled */ |
| - |
| - spinlock_t tx_lock; /* spinlock for transmit state */ |
| - unsigned long tx_bytes; |
| - unsigned long tx_outstanding_bytes; |
| - unsigned long tx_outstanding_urbs; |
| -}; |
| - |
| /* Used for TIOCMIWAIT */ |
| #define FTDI_STATUS_B0_MASK (FTDI_RS0_CTS | FTDI_RS0_DSR | FTDI_RS0_RI | FTDI_RS0_RLSD) |
| #define FTDI_STATUS_B1_MASK (FTDI_RS_BI) |
| @@ -609,7 +609,6 @@ struct ftdi_private { |
| |
| /* function prototypes for a FTDI serial converter */ |
| static int ftdi_sio_probe (struct usb_serial *serial, const struct usb_device_id *id); |
| -static int ftdi_sio_attach (struct usb_serial *serial); |
| 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); |
| @@ -663,7 +662,6 @@ static struct usb_serial_driver ftdi_sio |
| .ioctl = ftdi_ioctl, |
| .set_termios = ftdi_set_termios, |
| .break_ctl = ftdi_break_ctl, |
| - .attach = ftdi_sio_attach, |
| .shutdown = ftdi_shutdown, |
| }; |
| |
| @@ -1198,6 +1196,8 @@ static int ftdi_sio_probe (struct usb_se |
| static int ftdi_sio_port_probe(struct usb_serial_port *port) |
| { |
| struct ftdi_private *priv; |
| + struct ftdi_sio_quirk *quirk = usb_get_serial_data(port->serial); |
| + |
| |
| dbg("%s",__FUNCTION__); |
| |
| @@ -1214,6 +1214,9 @@ static int ftdi_sio_port_probe(struct us |
| than queue a task to deliver them */ |
| priv->flags = ASYNC_LOW_LATENCY; |
| |
| + if (quirk && quirk->port_probe) |
| + quirk->port_probe(priv); |
| + |
| /* Increase the size of read buffers */ |
| kfree(port->bulk_in_buffer); |
| port->bulk_in_buffer = kmalloc (BUFSZ, GFP_KERNEL); |
| @@ -1244,29 +1247,13 @@ static int ftdi_sio_port_probe(struct us |
| return 0; |
| } |
| |
| -/* attach subroutine */ |
| -static int ftdi_sio_attach (struct usb_serial *serial) |
| -{ |
| - /* Check for device requiring special set up. */ |
| - struct ftdi_sio_quirk *quirk = usb_get_serial_data(serial); |
| - |
| - if (quirk && quirk->setup) |
| - quirk->setup(serial); |
| - |
| - return 0; |
| -} /* ftdi_sio_attach */ |
| - |
| - |
| /* Setup for the USB-UIRT device, which requires hardwired |
| * baudrate (38400 gets mapped to 312500) */ |
| /* Called from usbserial:serial_probe */ |
| -static void ftdi_USB_UIRT_setup (struct usb_serial *serial) |
| +static void ftdi_USB_UIRT_setup (struct ftdi_private *priv) |
| { |
| - struct ftdi_private *priv; |
| - |
| dbg("%s",__FUNCTION__); |
| |
| - priv = usb_get_serial_port_data(serial->port[0]); |
| priv->flags |= ASYNC_SPD_CUST; |
| priv->custom_divisor = 77; |
| priv->force_baud = B38400; |
| @@ -1274,13 +1261,10 @@ static void ftdi_USB_UIRT_setup (struct |
| |
| /* Setup for the HE-TIRA1 device, which requires hardwired |
| * baudrate (38400 gets mapped to 100000) and RTS-CTS enabled. */ |
| -static void ftdi_HE_TIRA1_setup (struct usb_serial *serial) |
| +static void ftdi_HE_TIRA1_setup (struct ftdi_private *priv) |
| { |
| - struct ftdi_private *priv; |
| - |
| dbg("%s",__FUNCTION__); |
| |
| - priv = usb_get_serial_port_data(serial->port[0]); |
| priv->flags |= ASYNC_SPD_CUST; |
| priv->custom_divisor = 240; |
| priv->force_baud = B38400; |