|
@@ -95,6 +95,7 @@ struct ftdi_private {
|
|
|
unsigned long tx_bytes;
|
|
|
unsigned long tx_outstanding_bytes;
|
|
|
unsigned long tx_outstanding_urbs;
|
|
|
+ unsigned short max_packet_size;
|
|
|
};
|
|
|
|
|
|
/* struct ftdi_sio_quirk is used by devices requiring special attention. */
|
|
@@ -703,7 +704,6 @@ static const char *ftdi_chip_name[] = {
|
|
|
|
|
|
/* Constants for read urb and write urb */
|
|
|
#define BUFSZ 512
|
|
|
-#define PKTSZ 64
|
|
|
|
|
|
/* rx_flags */
|
|
|
#define THROTTLED 0x01
|
|
@@ -1296,6 +1296,45 @@ static void ftdi_determine_type(struct usb_serial_port *port)
|
|
|
}
|
|
|
|
|
|
|
|
|
+/* Determine the maximum packet size for the device. This depends on the chip
|
|
|
+ * type and the USB host capabilities. The value should be obtained from the
|
|
|
+ * device descriptor as the chip will use the appropriate values for the host.*/
|
|
|
+static void ftdi_set_max_packet_size(struct usb_serial_port *port)
|
|
|
+{
|
|
|
+ struct ftdi_private *priv = usb_get_serial_port_data(port);
|
|
|
+ struct usb_serial *serial = port->serial;
|
|
|
+ struct usb_device *udev = serial->dev;
|
|
|
+
|
|
|
+ struct usb_interface *interface = serial->interface;
|
|
|
+ struct usb_endpoint_descriptor *ep_desc = &interface->cur_altsetting->endpoint[1].desc;
|
|
|
+
|
|
|
+ unsigned num_endpoints;
|
|
|
+ int i = 0;
|
|
|
+
|
|
|
+ num_endpoints = interface->cur_altsetting->desc.bNumEndpoints;
|
|
|
+ dev_info(&udev->dev, "Number of endpoints %d\n", num_endpoints);
|
|
|
+
|
|
|
+ /* NOTE: some customers have programmed FT232R/FT245R devices
|
|
|
+ * with an endpoint size of 0 - not good. In this case, we
|
|
|
+ * want to override the endpoint descriptor setting and use a
|
|
|
+ * value of 64 for wMaxPacketSize */
|
|
|
+ for (i = 0; i < num_endpoints; i++) {
|
|
|
+ dev_info(&udev->dev, "Endpoint %d MaxPacketSize %d\n", i+1,
|
|
|
+ interface->cur_altsetting->endpoint[i].desc.wMaxPacketSize);
|
|
|
+ ep_desc = &interface->cur_altsetting->endpoint[i].desc;
|
|
|
+ if (ep_desc->wMaxPacketSize == 0) {
|
|
|
+ ep_desc->wMaxPacketSize = cpu_to_le16(0x40);
|
|
|
+ dev_info(&udev->dev, "Overriding wMaxPacketSize on endpoint %d\n", i);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /* set max packet size based on descriptor */
|
|
|
+ priv->max_packet_size = ep_desc->wMaxPacketSize;
|
|
|
+
|
|
|
+ dev_info(&udev->dev, "Setting MaxPacketSize %d\n", priv->max_packet_size);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
/*
|
|
|
* ***************************************************************************
|
|
|
* Sysfs Attribute
|
|
@@ -1485,6 +1524,7 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port)
|
|
|
usb_set_serial_port_data(port, priv);
|
|
|
|
|
|
ftdi_determine_type(port);
|
|
|
+ ftdi_set_max_packet_size(port);
|
|
|
read_latency_timer(port);
|
|
|
create_sysfs_attrs(port);
|
|
|
return 0;
|
|
@@ -1740,8 +1780,8 @@ static int ftdi_write(struct tty_struct *tty, struct usb_serial_port *port,
|
|
|
if (data_offset > 0) {
|
|
|
/* Original sio needs control bytes too... */
|
|
|
transfer_size += (data_offset *
|
|
|
- ((count + (PKTSZ - 1 - data_offset)) /
|
|
|
- (PKTSZ - data_offset)));
|
|
|
+ ((count + (priv->max_packet_size - 1 - data_offset)) /
|
|
|
+ (priv->max_packet_size - data_offset)));
|
|
|
}
|
|
|
|
|
|
buffer = kmalloc(transfer_size, GFP_ATOMIC);
|
|
@@ -1763,7 +1803,7 @@ static int ftdi_write(struct tty_struct *tty, struct usb_serial_port *port,
|
|
|
if (data_offset > 0) {
|
|
|
/* Original sio requires control byte at start of
|
|
|
each packet. */
|
|
|
- int user_pktsz = PKTSZ - data_offset;
|
|
|
+ int user_pktsz = priv->max_packet_size - data_offset;
|
|
|
int todo = count;
|
|
|
unsigned char *first_byte = buffer;
|
|
|
const unsigned char *current_position = buf;
|
|
@@ -1859,7 +1899,7 @@ static void ftdi_write_bulk_callback(struct urb *urb)
|
|
|
data_offset = priv->write_offset;
|
|
|
if (data_offset > 0) {
|
|
|
/* Subtract the control bytes */
|
|
|
- countback -= (data_offset * DIV_ROUND_UP(countback, PKTSZ));
|
|
|
+ countback -= (data_offset * DIV_ROUND_UP(countback, priv->max_packet_size));
|
|
|
}
|
|
|
spin_lock_irqsave(&priv->tx_lock, flags);
|
|
|
--priv->tx_outstanding_urbs;
|
|
@@ -1961,7 +2001,7 @@ static void ftdi_read_bulk_callback(struct urb *urb)
|
|
|
|
|
|
/* count data bytes, but not status bytes */
|
|
|
countread = urb->actual_length;
|
|
|
- countread -= 2 * DIV_ROUND_UP(countread, PKTSZ);
|
|
|
+ countread -= 2 * DIV_ROUND_UP(countread, priv->max_packet_size);
|
|
|
spin_lock_irqsave(&priv->rx_lock, flags);
|
|
|
priv->rx_bytes += countread;
|
|
|
spin_unlock_irqrestore(&priv->rx_lock, flags);
|
|
@@ -2034,7 +2074,7 @@ static void ftdi_process_read(struct work_struct *work)
|
|
|
|
|
|
need_flip = 0;
|
|
|
for (packet_offset = priv->rx_processed;
|
|
|
- packet_offset < urb->actual_length; packet_offset += PKTSZ) {
|
|
|
+ packet_offset < urb->actual_length; packet_offset += priv->max_packet_size) {
|
|
|
int length;
|
|
|
|
|
|
/* Compare new line status to the old one, signal if different/
|
|
@@ -2049,7 +2089,7 @@ static void ftdi_process_read(struct work_struct *work)
|
|
|
priv->prev_status = new_status;
|
|
|
}
|
|
|
|
|
|
- length = min_t(u32, PKTSZ, urb->actual_length-packet_offset)-2;
|
|
|
+ length = min_t(u32, priv->max_packet_size, urb->actual_length-packet_offset)-2;
|
|
|
if (length < 0) {
|
|
|
dev_err(&port->dev, "%s - bad packet length: %d\n",
|
|
|
__func__, length+2);
|