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