>>>>> "Clifford" == Clifford Wolf <clifford@xxxxxxxxxxx> writes:
Clifford> Hi again, On Wed, Sep 30, 2009 at 08:07:15PM +0200, Clifford
Clifford> Wolf wrote:
>> > bash-3.2$ ./jtag-ft2232h -c > [***] my_ftdi_read_data gives up
>> polling. > IO Error: FTDI/USB read failed! > [***]
>> my_ftdi_read_data gives up polling. > IO Error: FTDI/USB read
>> failed! > Error while scanning JTAG chain.
>>
>> yes. this is the problem I've been talking about..
Clifford> Just fji: Updating the kernel from 2.6.22.1 to 2.6.31.3 solved
Clifford> the problem here now. The other PC (my laptop) on which the
Clifford> problem couldn't be reproduced was running a more or less up
Clifford> to date kernel the whole time. So I guess that was the problem
Clifford> after all...
I have tried to backport the ftdi_sio changes from 2.6.31 to 2.6.27. Find
the patch appended. I also tried to notify stable@xxxxxxxxxx about the need
for backporting these changes, but to no avail son long.
Despite that, there is still unexpected behaviour. I will report in another
mail.
Bye
--
Uwe Bonnes bon@xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Institut fuer Kernphysik Schlossgartenstrasse 9 64289 Darmstadt
--------- Tel. 06151 162516 -------- Fax. 06151 164321 ----------
--- linux/drivers/usb/serial/ftdi_sio.c.sav 2009-08-16 12:08:43.000000000
+0200
+++ linux/drivers/usb/serial/ftdi_sio.c 2009-10-04 15:09:49.000000000 +0200
@@ -47,7 +47,7 @@
/*
* Version Information
*/
-#define DRIVER_VERSION "v1.4.3"
+#define DRIVER_VERSION "v1.5.0"
#define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@xxxxxxxxx>, Bill Ryder
<bryder@xxxxxxx>, Kuba Ober <kuba@xxxxxxxxxxxxxxx>"
#define DRIVER_DESC "USB FTDI Serial Converters Driver"
@@ -56,6 +56,7 @@
static __u16 product;
struct ftdi_private {
+ struct kref kref;
ftdi_chip_type_t chip_type;
/* type of device, either SIO or FT8U232AM */
int baud_base; /* baud base clock for divisor setting */
@@ -81,7 +82,8 @@
int rx_processed;
unsigned long rx_bytes;
- __u16 interface; /* FT2232C port interface (0 for FT232/245) */
+ __u16 interface; /* FT2232C, FT2232H or FT4232H port interface
+ (0 for FT232/245) */
speed_t force_baud; /* if non-zero, force the baud rate to
this value */
@@ -92,6 +94,7 @@
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. */
@@ -161,6 +164,7 @@
{ USB_DEVICE(FTDI_VID, FTDI_8U232AM_ALT_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_232RL_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_8U2232C_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_4232H_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_MICRO_CHAMELEON_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_RELAIS_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_OPENDCC_PID) },
@@ -683,12 +687,13 @@
[FT232BM] = "FT232BM",
[FT2232C] = "FT2232C",
[FT232RL] = "FT232RL",
+ [FT2232H] = "FT2232H",
+ [FT4232H] = "FT4232H"
};
/* Constants for read urb and write urb */
#define BUFSZ 512
-#define PKTSZ 64
/* rx_flags */
#define THROTTLED 0x01
@@ -734,6 +739,8 @@
static unsigned short int ftdi_232am_baud_to_divisor(int baud);
static __u32 ftdi_232bm_baud_base_to_divisor(int baud, int base);
static __u32 ftdi_232bm_baud_to_divisor(int baud);
+static __u32 ftdi_2232h_baud_base_to_divisor(int baud, int base);
+static __u32 ftdi_2232h_baud_to_divisor(int baud);
static struct usb_serial_driver ftdi_sio_device = {
.driver = {
@@ -827,6 +834,36 @@
return ftdi_232bm_baud_base_to_divisor(baud, 48000000);
}
+static __u32 ftdi_2232h_baud_base_to_divisor(int baud, int base)
+{
+ static const unsigned char divfrac[8] = { 0, 3, 2, 4, 1, 5, 6, 7 };
+ __u32 divisor;
+ int divisor3;
+
+ /* hi-speed baud rate is 10-bit sampling instead of 16-bit */
+ divisor3 = (base / 10 / baud) * 8;
+
+ divisor = divisor3 >> 3;
+ divisor |= (__u32)divfrac[divisor3 & 0x7] << 14;
+ /* Deal with special cases for highest baud rates. */
+ if (divisor == 1)
+ divisor = 0;
+ else if (divisor == 0x4001)
+ divisor = 1;
+ /*
+ * Set this bit to turn off a divide by 2.5 on baud rate generator
+ * This enables baud rates up to 12Mbaud but cannot reach below 1200
+ * baud with this bit set
+ */
+ divisor |= 0x00020000;
+ return divisor;
+}
+
+static __u32 ftdi_2232h_baud_to_divisor(int baud)
+{
+ return ftdi_2232h_baud_base_to_divisor(baud, 120000000);
+}
+
#define set_mctrl(port, set) update_mctrl((port), (set), 0)
#define clear_mctrl(port, clear) update_mctrl((port), 0, (clear))
@@ -985,6 +1022,19 @@
baud = 9600;
}
break;
+ case FT2232H: /* FT2232H chip */
+ case FT4232H: /* FT4232H chip */
+ if ((baud <= 12000000) & (baud >= 1200)) {
+ div_value = ftdi_2232h_baud_to_divisor(baud);
+ } else if (baud < 1200) {
+ div_value = ftdi_232bm_baud_to_divisor(baud);
+ } else {
+ dbg("%s - Baud rate too high!", __func__);
+ div_value = ftdi_232bm_baud_to_divisor(9600);
+ div_okay = 0;
+ baud = 9600;
+ }
+ break;
} /* priv->chip_type */
if (div_okay) {
@@ -1128,14 +1178,29 @@
if (interfaces > 1) {
int inter;
- /* Multiple interfaces. Assume FT2232C. */
+ /* Multiple interfaces.*/
+ if (version == 0x0800) {
+ priv->chip_type = FT4232H;
+ /* Hi-speed - baud clock runs at 120MHz */
+ priv->baud_base = 120000000 / 2;
+ } else if (version == 0x0700) {
+ priv->chip_type = FT2232H;
+ /* Hi-speed - baud clock runs at 120MHz */
+ priv->baud_base = 120000000 / 2;
+ } else
priv->chip_type = FT2232C;
+
/* Determine interface code. */
inter = serial->interface->altsetting->desc.bInterfaceNumber;
- if (inter == 0)
- priv->interface = PIT_SIOA;
- else
- priv->interface = PIT_SIOB;
+ if (inter == 0) {
+ priv->interface = INTERFACE_A;
+ } else if (inter == 1) {
+ priv->interface = INTERFACE_B;
+ } else if (inter == 2) {
+ priv->interface = INTERFACE_C;
+ } else if (inter == 3) {
+ priv->interface = INTERFACE_D;
+ }
/* BM-type devices have a bug where bcdDevice gets set
* to 0x200 when iSerialNumber is 0. */
if (version < 0x500) {
@@ -1163,6 +1228,45 @@
}
+/* 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
@@ -1272,7 +1376,9 @@
if ((!retval) &&
(priv->chip_type == FT232BM ||
priv->chip_type == FT2232C ||
- priv->chip_type == FT232RL)) {
+ priv->chip_type == FT232RL ||
+ priv->chip_type == FT2232H ||
+ priv->chip_type == FT4232H)) {
retval = device_create_file(&port->dev,
&dev_attr_latency_timer);
}
@@ -1291,7 +1397,9 @@
device_remove_file(&port->dev, &dev_attr_event_char);
if (priv->chip_type == FT232BM ||
priv->chip_type == FT2232C ||
- priv->chip_type == FT232RL) {
+ priv->chip_type == FT232RL ||
+ priv->chip_type == FT2232H ||
+ priv->chip_type == FT4232H) {
device_remove_file(&port->dev, &dev_attr_latency_timer);
}
}
@@ -1337,6 +1445,7 @@
return -ENOMEM;
}
+ kref_init(&priv->kref);
spin_lock_init(&priv->rx_lock);
spin_lock_init(&priv->tx_lock);
init_waitqueue_head(&priv->delta_msr_wait);
@@ -1373,6 +1482,7 @@
usb_set_serial_port_data(port, priv);
ftdi_determine_type(port);
+ ftdi_set_max_packet_size(port);
create_sysfs_attrs(port);
return 0;
}
@@ -1451,6 +1561,13 @@
dbg("%s", __func__);
}
+static void ftdi_sio_priv_release(struct kref *k)
+{
+ struct ftdi_private *priv = container_of(k, struct ftdi_private, kref);
+
+ kfree(priv);
+}
+
static int ftdi_sio_port_remove(struct usb_serial_port *port)
{
struct ftdi_private *priv = usb_get_serial_port_data(port);
@@ -1459,14 +1576,7 @@
remove_sysfs_attrs(port);
- /* all open ports are closed at this point
- * (by usbserial.c:__serial_close, which calls ftdi_close)
- */
-
- if (priv) {
- usb_set_serial_port_data(port, NULL);
- kfree(priv);
- }
+ kref_put(&priv->kref, ftdi_sio_priv_release);
return 0;
}
@@ -1529,7 +1639,8 @@
if (result)
err("%s - failed submitting read urb, error %d",
__func__, result);
-
+ else
+ kref_get(&priv->kref);
return result;
} /* ftdi_open */
@@ -1571,11 +1682,11 @@
mutex_unlock(&port->serial->disc_mutex);
/* cancel any scheduled reading */
- cancel_delayed_work(&priv->rx_work);
- flush_scheduled_work();
+ cancel_delayed_work_sync(&priv->rx_work);
/* shutdown our bulk read */
usb_kill_urb(port->read_urb);
+ kref_put(&priv->kref, ftdi_sio_priv_release);
} /* ftdi_close */
@@ -1621,8 +1732,8 @@
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);
@@ -1643,7 +1754,7 @@
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;
@@ -1738,7 +1849,7 @@
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;
@@ -1838,7 +1949,7 @@
/* 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);
@@ -1910,7 +2021,7 @@
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/
@@ -1927,7 +2038,7 @@
}
}
- length = min(PKTSZ, urb->actual_length-packet_offset)-2;
+ length = min_t(u32, priv->max_packet_size,
urb->actual_length-packet_offset)-2;
if (length < 0) {
err("%s - bad packet length: %d", __func__, length+2);
length = 0;
@@ -2271,6 +2382,8 @@
case FT232BM:
case FT2232C:
case FT232RL:
+ case FT2232H:
+ case FT4232H:
/* the 8U232AM returns a two byte value (the sio is a 1 byte
value) - in the same format as the data returned from the in
point */
--
libftdi - see http://www.intra2net.com/en/developer/libftdi for details.
To unsubscribe send a mail to libftdi+unsubscribe@xxxxxxxxxxxxxxxxxxxxxxx
|