aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/serial/ftdi_sio.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/serial/ftdi_sio.c')
-rw-r--r--drivers/usb/serial/ftdi_sio.c118
1 files changed, 55 insertions, 63 deletions
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index 0b8133d04023..4d85cc7fadcb 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -1546,89 +1546,73 @@ static int get_lsr_info(struct usb_serial_port *port,
return 0;
}
-
-/* Determine type of FTDI chip based on USB config and descriptor. */
-static void ftdi_determine_type(struct usb_serial_port *port)
+static int ftdi_determine_type(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;
- unsigned version;
- unsigned interfaces;
+ unsigned int version, ifnum;
+
+ version = le16_to_cpu(udev->descriptor.bcdDevice);
+ ifnum = serial->interface->cur_altsetting->desc.bInterfaceNumber;
- /* Assume it is not the original SIO device for now. */
priv->baud_base = 48000000 / 2;
+ priv->channel = 0;
- version = le16_to_cpu(udev->descriptor.bcdDevice);
- interfaces = udev->actconfig->desc.bNumInterfaces;
- dev_dbg(&port->dev, "%s: bcdDevice = 0x%x, bNumInterfaces = %u\n", __func__,
- version, interfaces);
- if (interfaces > 1) {
- struct usb_interface *intf = serial->interface;
- int ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
-
- /* 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;
-
- if (ifnum == 0)
- priv->channel = CHANNEL_A;
- else if (ifnum == 1)
- priv->channel = CHANNEL_B;
- else if (ifnum == 2)
- priv->channel = CHANNEL_C;
- else if (ifnum == 3)
- priv->channel = CHANNEL_D;
-
- /* BM-type devices have a bug where bcdDevice gets set
- * to 0x200 when iSerialNumber is 0. */
- if (version < 0x500) {
- dev_dbg(&port->dev,
- "%s: something fishy - bcdDevice too low for multi-interface device\n",
- __func__);
- }
- } else if (version < 0x200) {
- /* Old device. Assume it's the original SIO. */
- priv->chip_type = SIO;
- priv->baud_base = 12000000 / 16;
- } else if (version < 0x400) {
- /* Assume it's an FT8U232AM (or FT8U245AM) */
+ switch (version) {
+ case 0x200:
priv->chip_type = FT232A;
+
/*
- * It might be a BM type because of the iSerialNumber bug.
- * If iSerialNumber==0 and the latency timer is readable,
- * assume it is BM type.
+ * FT232B devices have a bug where bcdDevice gets set to 0x200
+ * when iSerialNumber is 0. Assume it is an FT232B in case the
+ * latency timer is readable.
*/
if (udev->descriptor.iSerialNumber == 0 &&
_read_latency_timer(port) >= 0) {
- dev_dbg(&port->dev,
- "%s: has latency timer so not an AM type\n",
- __func__);
priv->chip_type = FT232B;
}
- } else if (version < 0x600) {
- /* Assume it's an FT232BM (or FT245BM) */
+ break;
+ case 0x400:
priv->chip_type = FT232B;
- } else if (version < 0x900) {
- /* Assume it's an FT232RL */
+ break;
+ case 0x500:
+ priv->chip_type = FT2232C;
+ priv->channel = CHANNEL_A + ifnum;
+ break;
+ case 0x600:
priv->chip_type = FT232R;
- } else if (version < 0x1000) {
- /* Assume it's an FT232H */
+ break;
+ case 0x700:
+ priv->chip_type = FT2232H;
+ priv->channel = CHANNEL_A + ifnum;
+ priv->baud_base = 120000000 / 2;
+ break;
+ case 0x800:
+ priv->chip_type = FT4232H;
+ priv->channel = CHANNEL_A + ifnum;
+ priv->baud_base = 120000000 / 2;
+ break;
+ case 0x900:
priv->chip_type = FT232H;
- } else {
- /* Assume it's an FT-X series device */
+ priv->baud_base = 120000000 / 2;
+ break;
+ case 0x1000:
priv->chip_type = FTX;
+ break;
+ default:
+ if (version < 0x200) {
+ priv->chip_type = SIO;
+ priv->baud_base = 12000000 / 16;
+ } else {
+ dev_err(&port->dev, "unknown device type: 0x%02x\n", version);
+ return -ENODEV;
+ }
}
dev_info(&udev->dev, "Detected %s\n", ftdi_chip_name[priv->chip_type]);
+
+ return 0;
}
@@ -2255,7 +2239,10 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port)
usb_set_serial_port_data(port, priv);
- ftdi_determine_type(port);
+ result = ftdi_determine_type(port);
+ if (result)
+ goto err_free;
+
ftdi_set_max_packet_size(port);
if (read_latency_timer(port) < 0)
priv->latency = 16;
@@ -2270,6 +2257,11 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port)
}
return 0;
+
+err_free:
+ kfree(priv);
+
+ return result;
}
/* Setup for the USB-UIRT device, which requires hardwired