diff options
-rw-r--r-- | drivers/usb/serial/ftdi_sio.c | 118 |
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 |