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. */
/* Constants for read urb and write urb */
#define BUFSZ 512
-#define PKTSZ 64
/* rx_flags */
#define THROTTLED 0x01
}
+/* 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
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;
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);
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;
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;
/* 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);
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/
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);