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