diff options
Diffstat (limited to 'drivers/usb/serial/ftdi_sio.c')
-rw-r--r-- | drivers/usb/serial/ftdi_sio.c | 111 |
1 files changed, 97 insertions, 14 deletions
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 8a74b19f1283..15945e806f03 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c | |||
@@ -257,7 +257,7 @@ | |||
257 | #include <asm/uaccess.h> | 257 | #include <asm/uaccess.h> |
258 | #include <linux/usb.h> | 258 | #include <linux/usb.h> |
259 | #include <linux/serial.h> | 259 | #include <linux/serial.h> |
260 | #include "usb-serial.h" | 260 | #include <linux/usb/serial.h> |
261 | #include "ftdi_sio.h" | 261 | #include "ftdi_sio.h" |
262 | 262 | ||
263 | /* | 263 | /* |
@@ -306,6 +306,8 @@ static struct ftdi_sio_quirk ftdi_HE_TIRA1_quirk = { | |||
306 | 306 | ||
307 | 307 | ||
308 | static struct usb_device_id id_table_combined [] = { | 308 | static struct usb_device_id id_table_combined [] = { |
309 | { USB_DEVICE(FTDI_VID, FTDI_AMC232_PID) }, | ||
310 | { USB_DEVICE(FTDI_VID, FTDI_CANUSB_PID) }, | ||
309 | { USB_DEVICE(FTDI_VID, FTDI_ACTZWAVE_PID) }, | 311 | { USB_DEVICE(FTDI_VID, FTDI_ACTZWAVE_PID) }, |
310 | { USB_DEVICE(FTDI_VID, FTDI_IRTRANS_PID) }, | 312 | { USB_DEVICE(FTDI_VID, FTDI_IRTRANS_PID) }, |
311 | { USB_DEVICE(FTDI_VID, FTDI_IPLUS_PID) }, | 313 | { USB_DEVICE(FTDI_VID, FTDI_IPLUS_PID) }, |
@@ -313,6 +315,7 @@ static struct usb_device_id id_table_combined [] = { | |||
313 | { USB_DEVICE(FTDI_VID, FTDI_8U232AM_PID) }, | 315 | { USB_DEVICE(FTDI_VID, FTDI_8U232AM_PID) }, |
314 | { USB_DEVICE(FTDI_VID, FTDI_8U232AM_ALT_PID) }, | 316 | { USB_DEVICE(FTDI_VID, FTDI_8U232AM_ALT_PID) }, |
315 | { USB_DEVICE(FTDI_VID, FTDI_8U2232C_PID) }, | 317 | { USB_DEVICE(FTDI_VID, FTDI_8U2232C_PID) }, |
318 | { USB_DEVICE(FTDI_VID, FTDI_MICRO_CHAMELEON_PID) }, | ||
316 | { USB_DEVICE(FTDI_VID, FTDI_RELAIS_PID) }, | 319 | { USB_DEVICE(FTDI_VID, FTDI_RELAIS_PID) }, |
317 | { USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_IOBOARD_PID) }, | 320 | { USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_IOBOARD_PID) }, |
318 | { USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_MINI_IOBOARD_PID) }, | 321 | { USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_MINI_IOBOARD_PID) }, |
@@ -336,6 +339,7 @@ static struct usb_device_id id_table_combined [] = { | |||
336 | { USB_DEVICE(FTDI_VID, FTDI_MTXORB_6_PID) }, | 339 | { USB_DEVICE(FTDI_VID, FTDI_MTXORB_6_PID) }, |
337 | { USB_DEVICE(FTDI_VID, FTDI_PERLE_ULTRAPORT_PID) }, | 340 | { USB_DEVICE(FTDI_VID, FTDI_PERLE_ULTRAPORT_PID) }, |
338 | { USB_DEVICE(FTDI_VID, FTDI_PIEGROUP_PID) }, | 341 | { USB_DEVICE(FTDI_VID, FTDI_PIEGROUP_PID) }, |
342 | { USB_DEVICE(FTDI_VID, FTDI_TNC_X_PID) }, | ||
339 | { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2101_PID) }, | 343 | { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2101_PID) }, |
340 | { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2102_PID) }, | 344 | { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2102_PID) }, |
341 | { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2103_PID) }, | 345 | { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2103_PID) }, |
@@ -500,6 +504,8 @@ static struct usb_device_id id_table_combined [] = { | |||
500 | { USB_DEVICE(PAPOUCH_VID, PAPOUCH_TMU_PID) }, | 504 | { USB_DEVICE(PAPOUCH_VID, PAPOUCH_TMU_PID) }, |
501 | { USB_DEVICE(FTDI_VID, FTDI_ACG_HFDUAL_PID) }, | 505 | { USB_DEVICE(FTDI_VID, FTDI_ACG_HFDUAL_PID) }, |
502 | { USB_DEVICE(FTDI_VID, FTDI_YEI_SERVOCENTER31_PID) }, | 506 | { USB_DEVICE(FTDI_VID, FTDI_YEI_SERVOCENTER31_PID) }, |
507 | { USB_DEVICE(FTDI_VID, FTDI_THORLABS_PID) }, | ||
508 | { USB_DEVICE(TESTO_VID, TESTO_USB_INTERFACE_PID) }, | ||
503 | { }, /* Optional parameter entry */ | 509 | { }, /* Optional parameter entry */ |
504 | { } /* Terminating entry */ | 510 | { } /* Terminating entry */ |
505 | }; | 511 | }; |
@@ -548,11 +554,17 @@ struct ftdi_private { | |||
548 | spinlock_t rx_lock; /* spinlock for receive state */ | 554 | spinlock_t rx_lock; /* spinlock for receive state */ |
549 | struct work_struct rx_work; | 555 | struct work_struct rx_work; |
550 | int rx_processed; | 556 | int rx_processed; |
557 | unsigned long rx_bytes; | ||
551 | 558 | ||
552 | __u16 interface; /* FT2232C port interface (0 for FT232/245) */ | 559 | __u16 interface; /* FT2232C port interface (0 for FT232/245) */ |
553 | 560 | ||
554 | int force_baud; /* if non-zero, force the baud rate to this value */ | 561 | int force_baud; /* if non-zero, force the baud rate to this value */ |
555 | int force_rtscts; /* if non-zero, force RTS-CTS to always be enabled */ | 562 | int force_rtscts; /* if non-zero, force RTS-CTS to always be enabled */ |
563 | |||
564 | spinlock_t tx_lock; /* spinlock for transmit state */ | ||
565 | unsigned long tx_bytes; | ||
566 | unsigned long tx_outstanding_bytes; | ||
567 | unsigned long tx_outstanding_urbs; | ||
556 | }; | 568 | }; |
557 | 569 | ||
558 | /* Used for TIOCMIWAIT */ | 570 | /* Used for TIOCMIWAIT */ |
@@ -626,6 +638,9 @@ static struct usb_serial_driver ftdi_sio_device = { | |||
626 | #define HIGH 1 | 638 | #define HIGH 1 |
627 | #define LOW 0 | 639 | #define LOW 0 |
628 | 640 | ||
641 | /* number of outstanding urbs to prevent userspace DoS from happening */ | ||
642 | #define URB_UPPER_LIMIT 42 | ||
643 | |||
629 | /* | 644 | /* |
630 | * *************************************************************************** | 645 | * *************************************************************************** |
631 | * Utlity functions | 646 | * Utlity functions |
@@ -1156,6 +1171,7 @@ static int ftdi_sio_attach (struct usb_serial *serial) | |||
1156 | } | 1171 | } |
1157 | 1172 | ||
1158 | spin_lock_init(&priv->rx_lock); | 1173 | spin_lock_init(&priv->rx_lock); |
1174 | spin_lock_init(&priv->tx_lock); | ||
1159 | init_waitqueue_head(&priv->delta_msr_wait); | 1175 | init_waitqueue_head(&priv->delta_msr_wait); |
1160 | /* This will push the characters through immediately rather | 1176 | /* This will push the characters through immediately rather |
1161 | than queue a task to deliver them */ | 1177 | than queue a task to deliver them */ |
@@ -1270,6 +1286,13 @@ static int ftdi_open (struct usb_serial_port *port, struct file *filp) | |||
1270 | 1286 | ||
1271 | dbg("%s", __FUNCTION__); | 1287 | dbg("%s", __FUNCTION__); |
1272 | 1288 | ||
1289 | spin_lock_irqsave(&priv->tx_lock, flags); | ||
1290 | priv->tx_bytes = 0; | ||
1291 | spin_unlock_irqrestore(&priv->tx_lock, flags); | ||
1292 | spin_lock_irqsave(&priv->rx_lock, flags); | ||
1293 | priv->rx_bytes = 0; | ||
1294 | spin_unlock_irqrestore(&priv->rx_lock, flags); | ||
1295 | |||
1273 | if (port->tty) | 1296 | if (port->tty) |
1274 | port->tty->low_latency = (priv->flags & ASYNC_LOW_LATENCY) ? 1 : 0; | 1297 | port->tty->low_latency = (priv->flags & ASYNC_LOW_LATENCY) ? 1 : 0; |
1275 | 1298 | ||
@@ -1372,6 +1395,7 @@ static int ftdi_write (struct usb_serial_port *port, | |||
1372 | int data_offset ; /* will be 1 for the SIO and 0 otherwise */ | 1395 | int data_offset ; /* will be 1 for the SIO and 0 otherwise */ |
1373 | int status; | 1396 | int status; |
1374 | int transfer_size; | 1397 | int transfer_size; |
1398 | unsigned long flags; | ||
1375 | 1399 | ||
1376 | dbg("%s port %d, %d bytes", __FUNCTION__, port->number, count); | 1400 | dbg("%s port %d, %d bytes", __FUNCTION__, port->number, count); |
1377 | 1401 | ||
@@ -1379,6 +1403,13 @@ static int ftdi_write (struct usb_serial_port *port, | |||
1379 | dbg("write request of 0 bytes"); | 1403 | dbg("write request of 0 bytes"); |
1380 | return 0; | 1404 | return 0; |
1381 | } | 1405 | } |
1406 | spin_lock_irqsave(&priv->tx_lock, flags); | ||
1407 | if (priv->tx_outstanding_urbs > URB_UPPER_LIMIT) { | ||
1408 | spin_unlock_irqrestore(&priv->tx_lock, flags); | ||
1409 | dbg("%s - write limit hit\n", __FUNCTION__); | ||
1410 | return 0; | ||
1411 | } | ||
1412 | spin_unlock_irqrestore(&priv->tx_lock, flags); | ||
1382 | 1413 | ||
1383 | data_offset = priv->write_offset; | 1414 | data_offset = priv->write_offset; |
1384 | dbg("data_offset set to %d",data_offset); | 1415 | dbg("data_offset set to %d",data_offset); |
@@ -1445,6 +1476,12 @@ static int ftdi_write (struct usb_serial_port *port, | |||
1445 | err("%s - failed submitting write urb, error %d", __FUNCTION__, status); | 1476 | err("%s - failed submitting write urb, error %d", __FUNCTION__, status); |
1446 | count = status; | 1477 | count = status; |
1447 | kfree (buffer); | 1478 | kfree (buffer); |
1479 | } else { | ||
1480 | spin_lock_irqsave(&priv->tx_lock, flags); | ||
1481 | ++priv->tx_outstanding_urbs; | ||
1482 | priv->tx_outstanding_bytes += count; | ||
1483 | priv->tx_bytes += count; | ||
1484 | spin_unlock_irqrestore(&priv->tx_lock, flags); | ||
1448 | } | 1485 | } |
1449 | 1486 | ||
1450 | /* we are done with this urb, so let the host driver | 1487 | /* we are done with this urb, so let the host driver |
@@ -1460,7 +1497,11 @@ static int ftdi_write (struct usb_serial_port *port, | |||
1460 | 1497 | ||
1461 | static void ftdi_write_bulk_callback (struct urb *urb, struct pt_regs *regs) | 1498 | static void ftdi_write_bulk_callback (struct urb *urb, struct pt_regs *regs) |
1462 | { | 1499 | { |
1500 | unsigned long flags; | ||
1463 | struct usb_serial_port *port = (struct usb_serial_port *)urb->context; | 1501 | struct usb_serial_port *port = (struct usb_serial_port *)urb->context; |
1502 | struct ftdi_private *priv; | ||
1503 | int data_offset; /* will be 1 for the SIO and 0 otherwise */ | ||
1504 | unsigned long countback; | ||
1464 | 1505 | ||
1465 | /* free up the transfer buffer, as usb_free_urb() does not do this */ | 1506 | /* free up the transfer buffer, as usb_free_urb() does not do this */ |
1466 | kfree (urb->transfer_buffer); | 1507 | kfree (urb->transfer_buffer); |
@@ -1472,34 +1513,67 @@ static void ftdi_write_bulk_callback (struct urb *urb, struct pt_regs *regs) | |||
1472 | return; | 1513 | return; |
1473 | } | 1514 | } |
1474 | 1515 | ||
1516 | priv = usb_get_serial_port_data(port); | ||
1517 | if (!priv) { | ||
1518 | dbg("%s - bad port private data pointer - exiting", __FUNCTION__); | ||
1519 | return; | ||
1520 | } | ||
1521 | /* account for transferred data */ | ||
1522 | countback = urb->actual_length; | ||
1523 | data_offset = priv->write_offset; | ||
1524 | if (data_offset > 0) { | ||
1525 | /* Subtract the control bytes */ | ||
1526 | countback -= (data_offset * ((countback + (PKTSZ - 1)) / PKTSZ)); | ||
1527 | } | ||
1528 | spin_lock_irqsave(&priv->tx_lock, flags); | ||
1529 | --priv->tx_outstanding_urbs; | ||
1530 | priv->tx_outstanding_bytes -= countback; | ||
1531 | spin_unlock_irqrestore(&priv->tx_lock, flags); | ||
1532 | |||
1475 | usb_serial_port_softint(port); | 1533 | usb_serial_port_softint(port); |
1476 | } /* ftdi_write_bulk_callback */ | 1534 | } /* ftdi_write_bulk_callback */ |
1477 | 1535 | ||
1478 | 1536 | ||
1479 | static int ftdi_write_room( struct usb_serial_port *port ) | 1537 | static int ftdi_write_room( struct usb_serial_port *port ) |
1480 | { | 1538 | { |
1539 | struct ftdi_private *priv = usb_get_serial_port_data(port); | ||
1540 | int room; | ||
1541 | unsigned long flags; | ||
1542 | |||
1481 | dbg("%s - port %d", __FUNCTION__, port->number); | 1543 | dbg("%s - port %d", __FUNCTION__, port->number); |
1482 | 1544 | ||
1483 | /* | 1545 | spin_lock_irqsave(&priv->tx_lock, flags); |
1484 | * We really can take anything the user throws at us | 1546 | if (priv->tx_outstanding_urbs < URB_UPPER_LIMIT) { |
1485 | * but let's pick a nice big number to tell the tty | 1547 | /* |
1486 | * layer that we have lots of free space | 1548 | * We really can take anything the user throws at us |
1487 | */ | 1549 | * but let's pick a nice big number to tell the tty |
1488 | return 2048; | 1550 | * layer that we have lots of free space |
1551 | */ | ||
1552 | room = 2048; | ||
1553 | } else { | ||
1554 | room = 0; | ||
1555 | } | ||
1556 | spin_unlock_irqrestore(&priv->tx_lock, flags); | ||
1557 | return room; | ||
1489 | } /* ftdi_write_room */ | 1558 | } /* ftdi_write_room */ |
1490 | 1559 | ||
1491 | 1560 | ||
1492 | static int ftdi_chars_in_buffer (struct usb_serial_port *port) | 1561 | static int ftdi_chars_in_buffer (struct usb_serial_port *port) |
1493 | { /* ftdi_chars_in_buffer */ | 1562 | { /* ftdi_chars_in_buffer */ |
1563 | struct ftdi_private *priv = usb_get_serial_port_data(port); | ||
1564 | int buffered; | ||
1565 | unsigned long flags; | ||
1566 | |||
1494 | dbg("%s - port %d", __FUNCTION__, port->number); | 1567 | dbg("%s - port %d", __FUNCTION__, port->number); |
1495 | 1568 | ||
1496 | /* | 1569 | spin_lock_irqsave(&priv->tx_lock, flags); |
1497 | * We can't really account for how much data we | 1570 | buffered = (int)priv->tx_outstanding_bytes; |
1498 | * have sent out, but hasn't made it through to the | 1571 | spin_unlock_irqrestore(&priv->tx_lock, flags); |
1499 | * device, so just tell the tty layer that everything | 1572 | if (buffered < 0) { |
1500 | * is flushed. | 1573 | err("%s outstanding tx bytes is negative!", __FUNCTION__); |
1501 | */ | 1574 | buffered = 0; |
1502 | return 0; | 1575 | } |
1576 | return buffered; | ||
1503 | } /* ftdi_chars_in_buffer */ | 1577 | } /* ftdi_chars_in_buffer */ |
1504 | 1578 | ||
1505 | 1579 | ||
@@ -1509,6 +1583,8 @@ static void ftdi_read_bulk_callback (struct urb *urb, struct pt_regs *regs) | |||
1509 | struct usb_serial_port *port = (struct usb_serial_port *)urb->context; | 1583 | struct usb_serial_port *port = (struct usb_serial_port *)urb->context; |
1510 | struct tty_struct *tty; | 1584 | struct tty_struct *tty; |
1511 | struct ftdi_private *priv; | 1585 | struct ftdi_private *priv; |
1586 | unsigned long countread; | ||
1587 | unsigned long flags; | ||
1512 | 1588 | ||
1513 | if (urb->number_of_packets > 0) { | 1589 | if (urb->number_of_packets > 0) { |
1514 | err("%s transfer_buffer_length %d actual_length %d number of packets %d",__FUNCTION__, | 1590 | err("%s transfer_buffer_length %d actual_length %d number of packets %d",__FUNCTION__, |
@@ -1543,6 +1619,13 @@ static void ftdi_read_bulk_callback (struct urb *urb, struct pt_regs *regs) | |||
1543 | return; | 1619 | return; |
1544 | } | 1620 | } |
1545 | 1621 | ||
1622 | /* count data bytes, but not status bytes */ | ||
1623 | countread = urb->actual_length; | ||
1624 | countread -= 2 * ((countread + (PKTSZ - 1)) / PKTSZ); | ||
1625 | spin_lock_irqsave(&priv->rx_lock, flags); | ||
1626 | priv->rx_bytes += countread; | ||
1627 | spin_unlock_irqrestore(&priv->rx_lock, flags); | ||
1628 | |||
1546 | ftdi_process_read(port); | 1629 | ftdi_process_read(port); |
1547 | 1630 | ||
1548 | } /* ftdi_read_bulk_callback */ | 1631 | } /* ftdi_read_bulk_callback */ |