Skip to content

Commit 895f28b

Browse files
Mark Adamsongregkh
authored andcommitted
USB: ftdi_sio: fix hi-speed device packet size calculation
Added a function to set the packet size to be used based on the value from the device endpoint descriptor. The FT2232H and FT4232H hi-speed devices will have wMaxPacketSize of 512 bytes when connected to a USB 2.0 hi-speed host, but will use alternative descriptors with wMaxPacketSize of 64 bytes if connected to a USB 1.1 host or hub. All other FTDI devices have wMaxPacketSize of 64 bytes, except some FT232R and FT245R devices which customers have mistakenly programmed to have wMaxPacketSize of 0 - this is an error and will be overridden to use wMaxPacketSize of 64 bytes. The packet size used is important as it determines where the driver removes the status bytes from the incoming data. If it is incorrect, it will lead to data corruption. Signed-off-by: Mark J. Adamson <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 094c2e6 commit 895f28b

File tree

1 file changed

+48
-8
lines changed

1 file changed

+48
-8
lines changed

drivers/usb/serial/ftdi_sio.c

Lines changed: 48 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ struct ftdi_private {
9595
unsigned long tx_bytes;
9696
unsigned long tx_outstanding_bytes;
9797
unsigned long tx_outstanding_urbs;
98+
unsigned short max_packet_size;
9899
};
99100

100101
/* struct ftdi_sio_quirk is used by devices requiring special attention. */
@@ -703,7 +704,6 @@ static const char *ftdi_chip_name[] = {
703704

704705
/* Constants for read urb and write urb */
705706
#define BUFSZ 512
706-
#define PKTSZ 64
707707

708708
/* rx_flags */
709709
#define THROTTLED 0x01
@@ -1296,6 +1296,45 @@ static void ftdi_determine_type(struct usb_serial_port *port)
12961296
}
12971297

12981298

1299+
/* Determine the maximum packet size for the device. This depends on the chip
1300+
* type and the USB host capabilities. The value should be obtained from the
1301+
* device descriptor as the chip will use the appropriate values for the host.*/
1302+
static void ftdi_set_max_packet_size(struct usb_serial_port *port)
1303+
{
1304+
struct ftdi_private *priv = usb_get_serial_port_data(port);
1305+
struct usb_serial *serial = port->serial;
1306+
struct usb_device *udev = serial->dev;
1307+
1308+
struct usb_interface *interface = serial->interface;
1309+
struct usb_endpoint_descriptor *ep_desc = &interface->cur_altsetting->endpoint[1].desc;
1310+
1311+
unsigned num_endpoints;
1312+
int i = 0;
1313+
1314+
num_endpoints = interface->cur_altsetting->desc.bNumEndpoints;
1315+
dev_info(&udev->dev, "Number of endpoints %d\n", num_endpoints);
1316+
1317+
/* NOTE: some customers have programmed FT232R/FT245R devices
1318+
* with an endpoint size of 0 - not good. In this case, we
1319+
* want to override the endpoint descriptor setting and use a
1320+
* value of 64 for wMaxPacketSize */
1321+
for (i = 0; i < num_endpoints; i++) {
1322+
dev_info(&udev->dev, "Endpoint %d MaxPacketSize %d\n", i+1,
1323+
interface->cur_altsetting->endpoint[i].desc.wMaxPacketSize);
1324+
ep_desc = &interface->cur_altsetting->endpoint[i].desc;
1325+
if (ep_desc->wMaxPacketSize == 0) {
1326+
ep_desc->wMaxPacketSize = cpu_to_le16(0x40);
1327+
dev_info(&udev->dev, "Overriding wMaxPacketSize on endpoint %d\n", i);
1328+
}
1329+
}
1330+
1331+
/* set max packet size based on descriptor */
1332+
priv->max_packet_size = ep_desc->wMaxPacketSize;
1333+
1334+
dev_info(&udev->dev, "Setting MaxPacketSize %d\n", priv->max_packet_size);
1335+
}
1336+
1337+
12991338
/*
13001339
* ***************************************************************************
13011340
* Sysfs Attribute
@@ -1485,6 +1524,7 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port)
14851524
usb_set_serial_port_data(port, priv);
14861525

14871526
ftdi_determine_type(port);
1527+
ftdi_set_max_packet_size(port);
14881528
read_latency_timer(port);
14891529
create_sysfs_attrs(port);
14901530
return 0;
@@ -1740,8 +1780,8 @@ static int ftdi_write(struct tty_struct *tty, struct usb_serial_port *port,
17401780
if (data_offset > 0) {
17411781
/* Original sio needs control bytes too... */
17421782
transfer_size += (data_offset *
1743-
((count + (PKTSZ - 1 - data_offset)) /
1744-
(PKTSZ - data_offset)));
1783+
((count + (priv->max_packet_size - 1 - data_offset)) /
1784+
(priv->max_packet_size - data_offset)));
17451785
}
17461786

17471787
buffer = kmalloc(transfer_size, GFP_ATOMIC);
@@ -1763,7 +1803,7 @@ static int ftdi_write(struct tty_struct *tty, struct usb_serial_port *port,
17631803
if (data_offset > 0) {
17641804
/* Original sio requires control byte at start of
17651805
each packet. */
1766-
int user_pktsz = PKTSZ - data_offset;
1806+
int user_pktsz = priv->max_packet_size - data_offset;
17671807
int todo = count;
17681808
unsigned char *first_byte = buffer;
17691809
const unsigned char *current_position = buf;
@@ -1859,7 +1899,7 @@ static void ftdi_write_bulk_callback(struct urb *urb)
18591899
data_offset = priv->write_offset;
18601900
if (data_offset > 0) {
18611901
/* Subtract the control bytes */
1862-
countback -= (data_offset * DIV_ROUND_UP(countback, PKTSZ));
1902+
countback -= (data_offset * DIV_ROUND_UP(countback, priv->max_packet_size));
18631903
}
18641904
spin_lock_irqsave(&priv->tx_lock, flags);
18651905
--priv->tx_outstanding_urbs;
@@ -1961,7 +2001,7 @@ static void ftdi_read_bulk_callback(struct urb *urb)
19612001

19622002
/* count data bytes, but not status bytes */
19632003
countread = urb->actual_length;
1964-
countread -= 2 * DIV_ROUND_UP(countread, PKTSZ);
2004+
countread -= 2 * DIV_ROUND_UP(countread, priv->max_packet_size);
19652005
spin_lock_irqsave(&priv->rx_lock, flags);
19662006
priv->rx_bytes += countread;
19672007
spin_unlock_irqrestore(&priv->rx_lock, flags);
@@ -2034,7 +2074,7 @@ static void ftdi_process_read(struct work_struct *work)
20342074

20352075
need_flip = 0;
20362076
for (packet_offset = priv->rx_processed;
2037-
packet_offset < urb->actual_length; packet_offset += PKTSZ) {
2077+
packet_offset < urb->actual_length; packet_offset += priv->max_packet_size) {
20382078
int length;
20392079

20402080
/* Compare new line status to the old one, signal if different/
@@ -2049,7 +2089,7 @@ static void ftdi_process_read(struct work_struct *work)
20492089
priv->prev_status = new_status;
20502090
}
20512091

2052-
length = min_t(u32, PKTSZ, urb->actual_length-packet_offset)-2;
2092+
length = min_t(u32, priv->max_packet_size, urb->actual_length-packet_offset)-2;
20532093
if (length < 0) {
20542094
dev_err(&port->dev, "%s - bad packet length: %d\n",
20552095
__func__, length+2);

0 commit comments

Comments
 (0)