Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

USB: ftdi_sio: fix oops due to processing workarounds too early

Fix an oops that happens in relation with applying work arounds for buggy
ftdi_sio devices. The quirks were handled too early because due to changes in
the initialisation of usb serial devices the device was not fully initialised
when the old hook was called.

Addresses bug 8564

Cc: <stable@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

authored by

Oliver Neukum and committed by
Greg Kroah-Hartman
0ffbbe25 a69228de

+44 -60
+44 -60
drivers/usb/serial/ftdi_sio.c
··· 271 271 static __u16 vendor = FTDI_VID; 272 272 static __u16 product; 273 273 274 + struct ftdi_private { 275 + ftdi_chip_type_t chip_type; 276 + /* type of the device, either SIO or FT8U232AM */ 277 + int baud_base; /* baud base clock for divisor setting */ 278 + int custom_divisor; /* custom_divisor kludge, this is for baud_base (different from what goes to the chip!) */ 279 + __u16 last_set_data_urb_value ; 280 + /* the last data state set - needed for doing a break */ 281 + int write_offset; /* This is the offset in the usb data block to write the serial data - 282 + * it is different between devices 283 + */ 284 + int flags; /* some ASYNC_xxxx flags are supported */ 285 + unsigned long last_dtr_rts; /* saved modem control outputs */ 286 + wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */ 287 + char prev_status, diff_status; /* Used for TIOCMIWAIT */ 288 + __u8 rx_flags; /* receive state flags (throttling) */ 289 + spinlock_t rx_lock; /* spinlock for receive state */ 290 + struct delayed_work rx_work; 291 + struct usb_serial_port *port; 292 + int rx_processed; 293 + unsigned long rx_bytes; 294 + 295 + __u16 interface; /* FT2232C port interface (0 for FT232/245) */ 296 + 297 + int force_baud; /* if non-zero, force the baud rate to this value */ 298 + int force_rtscts; /* if non-zero, force RTS-CTS to always be enabled */ 299 + 300 + spinlock_t tx_lock; /* spinlock for transmit state */ 301 + unsigned long tx_bytes; 302 + unsigned long tx_outstanding_bytes; 303 + unsigned long tx_outstanding_urbs; 304 + }; 305 + 274 306 /* struct ftdi_sio_quirk is used by devices requiring special attention. */ 275 307 struct ftdi_sio_quirk { 276 308 int (*probe)(struct usb_serial *); 277 - void (*setup)(struct usb_serial *); /* Special settings during startup. */ 309 + void (*port_probe)(struct ftdi_private *); /* Special settings for probed ports. */ 278 310 }; 279 311 280 312 static int ftdi_olimex_probe (struct usb_serial *serial); 281 - static void ftdi_USB_UIRT_setup (struct usb_serial *serial); 282 - static void ftdi_HE_TIRA1_setup (struct usb_serial *serial); 313 + static void ftdi_USB_UIRT_setup (struct ftdi_private *priv); 314 + static void ftdi_HE_TIRA1_setup (struct ftdi_private *priv); 283 315 284 316 static struct ftdi_sio_quirk ftdi_olimex_quirk = { 285 317 .probe = ftdi_olimex_probe, 286 318 }; 287 319 288 320 static struct ftdi_sio_quirk ftdi_USB_UIRT_quirk = { 289 - .setup = ftdi_USB_UIRT_setup, 321 + .port_probe = ftdi_USB_UIRT_setup, 290 322 }; 291 323 292 324 static struct ftdi_sio_quirk ftdi_HE_TIRA1_quirk = { 293 - .setup = ftdi_HE_TIRA1_setup, 325 + .port_probe = ftdi_HE_TIRA1_setup, 294 326 }; 295 327 296 328 /* ··· 599 567 #define THROTTLED 0x01 600 568 #define ACTUALLY_THROTTLED 0x02 601 569 602 - struct ftdi_private { 603 - ftdi_chip_type_t chip_type; 604 - /* type of the device, either SIO or FT8U232AM */ 605 - int baud_base; /* baud base clock for divisor setting */ 606 - int custom_divisor; /* custom_divisor kludge, this is for baud_base (different from what goes to the chip!) */ 607 - __u16 last_set_data_urb_value ; 608 - /* the last data state set - needed for doing a break */ 609 - int write_offset; /* This is the offset in the usb data block to write the serial data - 610 - * it is different between devices 611 - */ 612 - int flags; /* some ASYNC_xxxx flags are supported */ 613 - unsigned long last_dtr_rts; /* saved modem control outputs */ 614 - wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */ 615 - char prev_status, diff_status; /* Used for TIOCMIWAIT */ 616 - __u8 rx_flags; /* receive state flags (throttling) */ 617 - spinlock_t rx_lock; /* spinlock for receive state */ 618 - struct delayed_work rx_work; 619 - struct usb_serial_port *port; 620 - int rx_processed; 621 - unsigned long rx_bytes; 622 - 623 - __u16 interface; /* FT2232C port interface (0 for FT232/245) */ 624 - 625 - int force_baud; /* if non-zero, force the baud rate to this value */ 626 - int force_rtscts; /* if non-zero, force RTS-CTS to always be enabled */ 627 - 628 - spinlock_t tx_lock; /* spinlock for transmit state */ 629 - unsigned long tx_bytes; 630 - unsigned long tx_outstanding_bytes; 631 - unsigned long tx_outstanding_urbs; 632 - }; 633 - 634 570 /* Used for TIOCMIWAIT */ 635 571 #define FTDI_STATUS_B0_MASK (FTDI_RS0_CTS | FTDI_RS0_DSR | FTDI_RS0_RI | FTDI_RS0_RLSD) 636 572 #define FTDI_STATUS_B1_MASK (FTDI_RS_BI) ··· 609 609 610 610 /* function prototypes for a FTDI serial converter */ 611 611 static int ftdi_sio_probe (struct usb_serial *serial, const struct usb_device_id *id); 612 - static int ftdi_sio_attach (struct usb_serial *serial); 613 612 static void ftdi_shutdown (struct usb_serial *serial); 614 613 static int ftdi_sio_port_probe (struct usb_serial_port *port); 615 614 static int ftdi_sio_port_remove (struct usb_serial_port *port); ··· 662 663 .ioctl = ftdi_ioctl, 663 664 .set_termios = ftdi_set_termios, 664 665 .break_ctl = ftdi_break_ctl, 665 - .attach = ftdi_sio_attach, 666 666 .shutdown = ftdi_shutdown, 667 667 }; 668 668 ··· 1198 1200 static int ftdi_sio_port_probe(struct usb_serial_port *port) 1199 1201 { 1200 1202 struct ftdi_private *priv; 1203 + struct ftdi_sio_quirk *quirk = usb_get_serial_data(port->serial); 1204 + 1201 1205 1202 1206 dbg("%s",__FUNCTION__); 1203 1207 ··· 1215 1215 /* This will push the characters through immediately rather 1216 1216 than queue a task to deliver them */ 1217 1217 priv->flags = ASYNC_LOW_LATENCY; 1218 + 1219 + if (quirk && quirk->port_probe) 1220 + quirk->port_probe(priv); 1218 1221 1219 1222 /* Increase the size of read buffers */ 1220 1223 kfree(port->bulk_in_buffer); ··· 1249 1246 return 0; 1250 1247 } 1251 1248 1252 - /* attach subroutine */ 1253 - static int ftdi_sio_attach (struct usb_serial *serial) 1254 - { 1255 - /* Check for device requiring special set up. */ 1256 - struct ftdi_sio_quirk *quirk = usb_get_serial_data(serial); 1257 - 1258 - if (quirk && quirk->setup) 1259 - quirk->setup(serial); 1260 - 1261 - return 0; 1262 - } /* ftdi_sio_attach */ 1263 - 1264 - 1265 1249 /* Setup for the USB-UIRT device, which requires hardwired 1266 1250 * baudrate (38400 gets mapped to 312500) */ 1267 1251 /* Called from usbserial:serial_probe */ 1268 - static void ftdi_USB_UIRT_setup (struct usb_serial *serial) 1252 + static void ftdi_USB_UIRT_setup (struct ftdi_private *priv) 1269 1253 { 1270 - struct ftdi_private *priv; 1271 - 1272 1254 dbg("%s",__FUNCTION__); 1273 1255 1274 - priv = usb_get_serial_port_data(serial->port[0]); 1275 1256 priv->flags |= ASYNC_SPD_CUST; 1276 1257 priv->custom_divisor = 77; 1277 1258 priv->force_baud = B38400; ··· 1263 1276 1264 1277 /* Setup for the HE-TIRA1 device, which requires hardwired 1265 1278 * baudrate (38400 gets mapped to 100000) and RTS-CTS enabled. */ 1266 - static void ftdi_HE_TIRA1_setup (struct usb_serial *serial) 1279 + static void ftdi_HE_TIRA1_setup (struct ftdi_private *priv) 1267 1280 { 1268 - struct ftdi_private *priv; 1269 - 1270 1281 dbg("%s",__FUNCTION__); 1271 1282 1272 - priv = usb_get_serial_port_data(serial->port[0]); 1273 1283 priv->flags |= ASYNC_SPD_CUST; 1274 1284 priv->custom_divisor = 240; 1275 1285 priv->force_baud = B38400;