Commit 715a654b authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

Merge tag 'usb-serial-6.1-rc1' of...

Merge tag 'usb-serial-6.1-rc1' of https://git.kernel.org/pub/scm/linux/kernel/git/johan/usb-serial into usb-next

Johan writes:
  "USB-serial updates for 6.1-rc1

   Here are the USB-serial updates for 6.1-rc1, including:
    - a fix for a very long-standing FTDI SIO regression
    - a long-overdue cleanup of the FTDI type handling
    - support for new FTDI HP and HA devices

   Included are also various clean ups.

   All have been in linux-next with no reported issues."

* tag 'usb-serial-6.1-rc1' of https://git.kernel.org/pub/scm/linux/kernel/git/johan/usb-serial:
  USB: serial: ftdi_sio: clean up driver prefix
  USB: serial: ftdi_sio: move driver structure
  USB: serial: ftdi_sio: clean up attribute visibility logic
  USB: serial: console: move mutex_unlock() before usb_serial_put()
  USB: serial: ftdi_sio: convert to use dev_groups
  USB: serial: ftdi_sio: add support for HP and HA devices
  USB: serial: ftdi_sio: simplify divisor handling
  USB: serial: ftdi_sio: assume hi-speed type
  USB: serial: ftdi_sio: clean up baudrate request
  USB: serial: ftdi_sio: clean up attribute handling
  USB: serial: ftdi_sio: clean up modem-status handling
  USB: serial: ftdi_sio: tighten device-type detection
  USB: serial: ftdi_sio: rename channel index
  USB: serial: ftdi_sio: include FT2232D in type string
  USB: serial: ftdi_sio: rename chip types
  USB: serial: ftdi_sio: drop redundant chip type comments
  USB: serial: ftdi_sio: clean up chip type enum
  USB: serial: ftdi_sio: fix 300 bps rate for SIO
parents 7eb2bf87 6b2fe3df
......@@ -189,8 +189,8 @@ static int usb_console_setup(struct console *co, char *options)
info->port = NULL;
usb_autopm_put_interface(serial->interface);
error_get_interface:
usb_serial_put(serial);
mutex_unlock(&serial->disc_mutex);
usb_serial_put(serial);
return retval;
}
......
......@@ -47,10 +47,27 @@
#define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>, Bill Ryder <bryder@sgi.com>, Kuba Ober <kuba@mareimbrium.org>, Andreas Mohr, Johan Hovold <jhovold@gmail.com>"
#define DRIVER_DESC "USB FTDI Serial Converters Driver"
enum ftdi_chip_type {
SIO,
FT232A,
FT232B,
FT2232C,
FT232R,
FT232H,
FT2232H,
FT4232H,
FT4232HA,
FT232HP,
FT233HP,
FT2232HP,
FT2233HP,
FT4232HP,
FT4233HP,
FTX,
};
struct ftdi_private {
enum ftdi_chip_type chip_type;
/* type of device, either SIO or FT8U232AM */
int baud_base; /* baud base clock for divisor setting */
int custom_divisor; /* custom_divisor kludge, this is for
baud_base (different from what goes to the
......@@ -62,8 +79,7 @@ struct ftdi_private {
unsigned long last_dtr_rts; /* saved modem control outputs */
char prev_status; /* Used for TIOCMIWAIT */
char transmit_empty; /* If transmitter is empty or not */
u16 interface; /* FT2232C, FT2232H or FT4232H port interface
(0 for FT232/245) */
u16 channel; /* channel index, or 0 for legacy types */
speed_t force_baud; /* if non-zero, force the baud rate to
this value */
......@@ -84,8 +100,7 @@ struct ftdi_private {
#endif
};
/* struct ftdi_sio_quirk is used by devices requiring special attention. */
struct ftdi_sio_quirk {
struct ftdi_quirk {
int (*probe)(struct usb_serial *);
/* Special settings for probed ports. */
void (*port_probe)(struct ftdi_private *);
......@@ -98,27 +113,27 @@ static int ftdi_8u2232c_probe(struct usb_serial *serial);
static void ftdi_USB_UIRT_setup(struct ftdi_private *priv);
static void ftdi_HE_TIRA1_setup(struct ftdi_private *priv);
static const struct ftdi_sio_quirk ftdi_jtag_quirk = {
static const struct ftdi_quirk ftdi_jtag_quirk = {
.probe = ftdi_jtag_probe,
};
static const struct ftdi_sio_quirk ftdi_NDI_device_quirk = {
static const struct ftdi_quirk ftdi_NDI_device_quirk = {
.probe = ftdi_NDI_device_setup,
};
static const struct ftdi_sio_quirk ftdi_USB_UIRT_quirk = {
static const struct ftdi_quirk ftdi_USB_UIRT_quirk = {
.port_probe = ftdi_USB_UIRT_setup,
};
static const struct ftdi_sio_quirk ftdi_HE_TIRA1_quirk = {
static const struct ftdi_quirk ftdi_HE_TIRA1_quirk = {
.port_probe = ftdi_HE_TIRA1_setup,
};
static const struct ftdi_sio_quirk ftdi_stmclite_quirk = {
static const struct ftdi_quirk ftdi_stmclite_quirk = {
.probe = ftdi_stmclite_probe,
};
static const struct ftdi_sio_quirk ftdi_8u2232c_quirk = {
static const struct ftdi_quirk ftdi_8u2232c_quirk = {
.probe = ftdi_8u2232c_probe,
};
......@@ -180,6 +195,13 @@ static const struct usb_device_id id_table_combined[] = {
{ USB_DEVICE(FTDI_VID, FTDI_4232H_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_232H_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_FTX_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_FT2233HP_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_FT4233HP_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_FT2232HP_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_FT4232HP_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_FT233HP_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_FT232HP_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_FT4232HA_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_MICRO_CHAMELEON_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_RELAIS_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_OPENDCC_PID) },
......@@ -1061,15 +1083,22 @@ static const struct usb_device_id id_table_combined[] = {
MODULE_DEVICE_TABLE(usb, id_table_combined);
static const char *ftdi_chip_name[] = {
[SIO] = "SIO", /* the serial part of FT8U100AX */
[FT8U232AM] = "FT8U232AM",
[FT232BM] = "FT232BM",
[FT2232C] = "FT2232C",
[FT232RL] = "FT232RL",
[FT2232H] = "FT2232H",
[FT4232H] = "FT4232H",
[FT232H] = "FT232H",
[FTX] = "FT-X"
[SIO] = "SIO", /* the serial part of FT8U100AX */
[FT232A] = "FT232A",
[FT232B] = "FT232B",
[FT2232C] = "FT2232C/D",
[FT232R] = "FT232R",
[FT232H] = "FT232H",
[FT2232H] = "FT2232H",
[FT4232H] = "FT4232H",
[FT4232HA] = "FT4232HA",
[FT232HP] = "FT232HP",
[FT233HP] = "FT233HP",
[FT2232HP] = "FT2232HP",
[FT2233HP] = "FT2233HP",
[FT4232HP] = "FT4232HP",
[FT4233HP] = "FT4233HP",
[FTX] = "FT-X",
};
......@@ -1078,74 +1107,11 @@ static const char *ftdi_chip_name[] = {
#define FTDI_STATUS_B1_MASK (FTDI_RS_BI)
/* End TIOCMIWAIT */
/* function prototypes for a FTDI serial converter */
static int ftdi_sio_probe(struct usb_serial *serial,
const struct usb_device_id *id);
static int ftdi_sio_port_probe(struct usb_serial_port *port);
static void ftdi_sio_port_remove(struct usb_serial_port *port);
static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port);
static void ftdi_dtr_rts(struct usb_serial_port *port, int on);
static void ftdi_process_read_urb(struct urb *urb);
static int ftdi_prepare_write_buffer(struct usb_serial_port *port,
void *dest, size_t size);
static void ftdi_set_termios(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios *old);
static int ftdi_tiocmget(struct tty_struct *tty);
static int ftdi_tiocmset(struct tty_struct *tty,
unsigned int set, unsigned int clear);
static int ftdi_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg);
static void get_serial_info(struct tty_struct *tty, struct serial_struct *ss);
static int set_serial_info(struct tty_struct *tty,
struct serial_struct *ss);
static void ftdi_break_ctl(struct tty_struct *tty, int break_state);
static bool ftdi_tx_empty(struct usb_serial_port *port);
static int ftdi_get_modem_status(struct usb_serial_port *port,
unsigned char status[2]);
static unsigned short int ftdi_232am_baud_base_to_divisor(int baud, int base);
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 = {
.owner = THIS_MODULE,
.name = "ftdi_sio",
},
.description = "FTDI USB Serial Device",
.id_table = id_table_combined,
.num_ports = 1,
.bulk_in_size = 512,
.bulk_out_size = 256,
.probe = ftdi_sio_probe,
.port_probe = ftdi_sio_port_probe,
.port_remove = ftdi_sio_port_remove,
.open = ftdi_open,
.dtr_rts = ftdi_dtr_rts,
.throttle = usb_serial_generic_throttle,
.unthrottle = usb_serial_generic_unthrottle,
.process_read_urb = ftdi_process_read_urb,
.prepare_write_buffer = ftdi_prepare_write_buffer,
.tiocmget = ftdi_tiocmget,
.tiocmset = ftdi_tiocmset,
.tiocmiwait = usb_serial_generic_tiocmiwait,
.get_icount = usb_serial_generic_get_icount,
.ioctl = ftdi_ioctl,
.get_serial = get_serial_info,
.set_serial = set_serial_info,
.set_termios = ftdi_set_termios,
.break_ctl = ftdi_break_ctl,
.tx_empty = ftdi_tx_empty,
};
static struct usb_serial_driver * const serial_drivers[] = {
&ftdi_sio_device, NULL
};
#define WDR_TIMEOUT 5000 /* default urb timeout */
#define WDR_SHORT_TIMEOUT 1000 /* shorter urb timeout */
......@@ -1261,7 +1227,7 @@ static int update_mctrl(struct usb_serial_port *port, unsigned int set,
usb_sndctrlpipe(port->serial->dev, 0),
FTDI_SIO_SET_MODEM_CTRL_REQUEST,
FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
value, priv->interface,
value, priv->channel,
NULL, 0, WDR_TIMEOUT);
if (rv < 0) {
dev_dbg(dev, "%s Error from MODEM_CTRL urb: DTR %s, RTS %s\n",
......@@ -1307,7 +1273,7 @@ static u32 get_ftdi_divisor(struct tty_struct *tty,
if (!baud)
baud = 9600;
switch (priv->chip_type) {
case SIO: /* SIO chip */
case SIO:
switch (baud) {
case 300: div_value = ftdi_sio_b300; break;
case 600: div_value = ftdi_sio_b600; break;
......@@ -1319,8 +1285,7 @@ static u32 get_ftdi_divisor(struct tty_struct *tty,
case 38400: div_value = ftdi_sio_b38400; break;
case 57600: div_value = ftdi_sio_b57600; break;
case 115200: div_value = ftdi_sio_b115200; break;
} /* baud */
if (div_value == 0) {
default:
dev_dbg(dev, "%s - Baudrate (%d) requested is not supported\n",
__func__, baud);
div_value = ftdi_sio_b9600;
......@@ -1328,7 +1293,7 @@ static u32 get_ftdi_divisor(struct tty_struct *tty,
div_okay = 0;
}
break;
case FT8U232AM: /* 8U232AM chip */
case FT232A:
if (baud <= 3000000) {
div_value = ftdi_232am_baud_to_divisor(baud);
} else {
......@@ -1338,10 +1303,10 @@ static u32 get_ftdi_divisor(struct tty_struct *tty,
div_okay = 0;
}
break;
case FT232BM: /* FT232BM chip */
case FT2232C: /* FT2232C chip */
case FT232RL: /* FT232RL chip */
case FTX: /* FT-X series */
case FT232B:
case FT2232C:
case FT232R:
case FTX:
if (baud <= 3000000) {
u16 product_id = le16_to_cpu(
port->serial->dev->descriptor.idProduct);
......@@ -1361,9 +1326,7 @@ static u32 get_ftdi_divisor(struct tty_struct *tty,
baud = 9600;
}
break;
case FT2232H: /* FT2232H chip */
case FT4232H: /* FT4232H chip */
case FT232H: /* FT232H chip */
default:
if ((baud <= 12000000) && (baud >= 1200)) {
div_value = ftdi_2232h_baud_to_divisor(baud);
} else if (baud < 1200) {
......@@ -1375,7 +1338,7 @@ static u32 get_ftdi_divisor(struct tty_struct *tty,
baud = 9600;
}
break;
} /* priv->chip_type */
}
if (div_okay) {
dev_dbg(dev, "%s - Baud rate set to %d (divisor 0x%lX) on chip %s\n",
......@@ -1398,13 +1361,8 @@ static int change_speed(struct tty_struct *tty, struct usb_serial_port *port)
index_value = get_ftdi_divisor(tty, port);
value = (u16)index_value;
index = (u16)(index_value >> 16);
if (priv->chip_type == FT2232C || priv->chip_type == FT2232H ||
priv->chip_type == FT4232H || priv->chip_type == FT232H ||
priv->chip_type == FTX) {
/* Probably the BM type needs the MSB of the encoded fractional
* divider also moved like for the chips above. Any infos? */
index = (u16)((index << 8) | priv->interface);
}
if (priv->channel)
index = (u16)((index << 8) | priv->channel);
rv = usb_control_msg(port->serial->dev,
usb_sndctrlpipe(port->serial->dev, 0),
......@@ -1422,7 +1380,7 @@ static int write_latency_timer(struct usb_serial_port *port)
int rv;
int l = priv->latency;
if (priv->chip_type == SIO || priv->chip_type == FT8U232AM)
if (priv->chip_type == SIO || priv->chip_type == FT232A)
return -EINVAL;
if (priv->flags & ASYNC_LOW_LATENCY)
......@@ -1434,7 +1392,7 @@ static int write_latency_timer(struct usb_serial_port *port)
usb_sndctrlpipe(udev, 0),
FTDI_SIO_SET_LATENCY_TIMER_REQUEST,
FTDI_SIO_SET_LATENCY_TIMER_REQUEST_TYPE,
l, priv->interface,
l, priv->channel,
NULL, 0, WDR_TIMEOUT);
if (rv < 0)
dev_err(&port->dev, "Unable to write latency timer: %i\n", rv);
......@@ -1450,7 +1408,7 @@ static int _read_latency_timer(struct usb_serial_port *port)
rv = usb_control_msg_recv(udev, 0, FTDI_SIO_GET_LATENCY_TIMER_REQUEST,
FTDI_SIO_GET_LATENCY_TIMER_REQUEST_TYPE, 0,
priv->interface, &buf, 1, WDR_TIMEOUT,
priv->channel, &buf, 1, WDR_TIMEOUT,
GFP_KERNEL);
if (rv == 0)
rv = buf;
......@@ -1463,7 +1421,7 @@ static int read_latency_timer(struct usb_serial_port *port)
struct ftdi_private *priv = usb_get_serial_port_data(port);
int rv;
if (priv->chip_type == SIO || priv->chip_type == FT8U232AM)
if (priv->chip_type == SIO || priv->chip_type == FT232A)
return -EINVAL;
rv = _read_latency_timer(port);
......@@ -1538,90 +1496,97 @@ 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;
/* Assume it is not the original SIO device for now. */
priv->baud_base = 48000000 / 2;
unsigned int version, ifnum;
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;
/* Determine interface code. */
if (ifnum == 0)
priv->interface = INTERFACE_A;
else if (ifnum == 1)
priv->interface = INTERFACE_B;
else if (ifnum == 2)
priv->interface = INTERFACE_C;
else if (ifnum == 3)
priv->interface = INTERFACE_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) */
priv->chip_type = FT8U232AM;
ifnum = serial->interface->cur_altsetting->desc.bInterfaceNumber;
/* Assume Hi-Speed type */
priv->baud_base = 120000000 / 2;
priv->channel = CHANNEL_A + ifnum;
switch (version) {
case 0x200:
priv->chip_type = FT232A;
priv->baud_base = 48000000 / 2;
priv->channel = 0;
/*
* 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 = FT232BM;
priv->chip_type = FT232B;
}
} else if (version < 0x600) {
/* Assume it's an FT232BM (or FT245BM) */
priv->chip_type = FT232BM;
} else if (version < 0x900) {
/* Assume it's an FT232RL */
priv->chip_type = FT232RL;
} else if (version < 0x1000) {
/* Assume it's an FT232H */
break;
case 0x400:
priv->chip_type = FT232B;
priv->baud_base = 48000000 / 2;
priv->channel = 0;
break;
case 0x500:
priv->chip_type = FT2232C;
priv->baud_base = 48000000 / 2;
break;
case 0x600:
priv->chip_type = FT232R;
priv->baud_base = 48000000 / 2;
priv->channel = 0;
break;
case 0x700:
priv->chip_type = FT2232H;
break;
case 0x800:
priv->chip_type = FT4232H;
break;
case 0x900:
priv->chip_type = FT232H;
} else {
/* Assume it's an FT-X series device */
break;
case 0x1000:
priv->chip_type = FTX;
priv->baud_base = 48000000 / 2;
break;
case 0x2800:
priv->chip_type = FT2233HP;
break;
case 0x2900:
priv->chip_type = FT4233HP;
break;
case 0x3000:
priv->chip_type = FT2232HP;
break;
case 0x3100:
priv->chip_type = FT4232HP;
break;
case 0x3200:
priv->chip_type = FT233HP;
break;
case 0x3300:
priv->chip_type = FT232HP;
break;
case 0x3600:
priv->chip_type = FT4232HA;
break;
default:
if (version < 0x200) {
priv->chip_type = SIO;
priv->baud_base = 12000000 / 16;
priv->channel = 0;
} 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;
}
......@@ -1720,7 +1685,7 @@ static ssize_t event_char_store(struct device *dev,
usb_sndctrlpipe(udev, 0),
FTDI_SIO_SET_EVENT_CHAR_REQUEST,
FTDI_SIO_SET_EVENT_CHAR_REQUEST_TYPE,
v, priv->interface,
v, priv->channel,
NULL, 0, WDR_TIMEOUT);
if (rv < 0) {
dev_dbg(&port->dev, "Unable to write event character: %i\n", rv);
......@@ -1731,51 +1696,42 @@ static ssize_t event_char_store(struct device *dev,
}
static DEVICE_ATTR_WO(event_char);
static int create_sysfs_attrs(struct usb_serial_port *port)
{
struct ftdi_private *priv = usb_get_serial_port_data(port);
int retval = 0;
/* XXX I've no idea if the original SIO supports the event_char
* sysfs parameter, so I'm playing it safe. */
if (priv->chip_type != SIO) {
dev_dbg(&port->dev, "sysfs attributes for %s\n", ftdi_chip_name[priv->chip_type]);
retval = device_create_file(&port->dev, &dev_attr_event_char);
if ((!retval) &&
(priv->chip_type == FT232BM ||
priv->chip_type == FT2232C ||
priv->chip_type == FT232RL ||
priv->chip_type == FT2232H ||
priv->chip_type == FT4232H ||
priv->chip_type == FT232H ||
priv->chip_type == FTX)) {
retval = device_create_file(&port->dev,
&dev_attr_latency_timer);
}
}
return retval;
}
static struct attribute *ftdi_attrs[] = {
&dev_attr_event_char.attr,
&dev_attr_latency_timer.attr,
NULL
};
static void remove_sysfs_attrs(struct usb_serial_port *port)
static umode_t ftdi_is_visible(struct kobject *kobj, struct attribute *attr, int idx)
{
struct device *dev = kobj_to_dev(kobj);
struct usb_serial_port *port = to_usb_serial_port(dev);
struct ftdi_private *priv = usb_get_serial_port_data(port);
enum ftdi_chip_type type = priv->chip_type;
/* XXX see create_sysfs_attrs */
if (priv->chip_type != SIO) {
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 == FT2232H ||
priv->chip_type == FT4232H ||
priv->chip_type == FT232H ||
priv->chip_type == FTX) {
device_remove_file(&port->dev, &dev_attr_latency_timer);
}
if (attr == &dev_attr_event_char.attr) {
if (type == SIO)
return 0;
}
if (attr == &dev_attr_latency_timer.attr) {
if (type == SIO || type == FT232A)
return 0;
}
return attr->mode;
}
static const struct attribute_group ftdi_group = {
.attrs = ftdi_attrs,
.is_visible = ftdi_is_visible,
};
static const struct attribute_group *ftdi_groups[] = {
&ftdi_group,
NULL
};
#ifdef CONFIG_GPIOLIB
static int ftdi_set_bitmode(struct usb_serial_port *port, u8 mode)
......@@ -1794,7 +1750,7 @@ static int ftdi_set_bitmode(struct usb_serial_port *port, u8 mode)
usb_sndctrlpipe(serial->dev, 0),
FTDI_SIO_SET_BITMODE_REQUEST,
FTDI_SIO_SET_BITMODE_REQUEST_TYPE, val,
priv->interface, NULL, 0, WDR_TIMEOUT);
priv->channel, NULL, 0, WDR_TIMEOUT);
if (result < 0) {
dev_err(&serial->interface->dev,
"bitmode request failed for value 0x%04x: %d\n",
......@@ -1858,7 +1814,7 @@ static int ftdi_read_cbus_pins(struct usb_serial_port *port)
result = usb_control_msg_recv(serial->dev, 0,
FTDI_SIO_READ_PINS_REQUEST,
FTDI_SIO_READ_PINS_REQUEST_TYPE, 0,
priv->interface, &buf, 1, WDR_TIMEOUT,
priv->channel, &buf, 1, WDR_TIMEOUT,
GFP_KERNEL);
if (result == 0)
result = buf;
......@@ -2143,7 +2099,7 @@ static int ftdi_gpio_init(struct usb_serial_port *port)
case FT232H:
result = ftdi_gpio_init_ft232h(port);
break;
case FT232RL:
case FT232R:
result = ftdi_gpio_init_ft232r(port);
break;
case FTX:
......@@ -2213,12 +2169,9 @@ static void ftdi_gpio_remove(struct usb_serial_port *port) { }
* ***************************************************************************
*/
/* Probe function to check for special devices */
static int ftdi_sio_probe(struct usb_serial *serial,
const struct usb_device_id *id)
static int ftdi_probe(struct usb_serial *serial, const struct usb_device_id *id)
{
const struct ftdi_sio_quirk *quirk =
(struct ftdi_sio_quirk *)id->driver_info;
const struct ftdi_quirk *quirk = (struct ftdi_quirk *)id->driver_info;
if (quirk && quirk->probe) {
int ret = quirk->probe(serial);
......@@ -2231,10 +2184,10 @@ static int ftdi_sio_probe(struct usb_serial *serial,
return 0;
}
static int ftdi_sio_port_probe(struct usb_serial_port *port)
static int ftdi_port_probe(struct usb_serial_port *port)
{
const struct ftdi_quirk *quirk = usb_get_serial_data(port->serial);
struct ftdi_private *priv;
const struct ftdi_sio_quirk *quirk = usb_get_serial_data(port->serial);
int result;
priv = kzalloc(sizeof(struct ftdi_private), GFP_KERNEL);
......@@ -2248,12 +2201,14 @@ 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;
write_latency_timer(port);
create_sysfs_attrs(port);
result = ftdi_gpio_init(port);
if (result < 0) {
......@@ -2263,6 +2218,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
......@@ -2373,14 +2333,12 @@ static int ftdi_stmclite_probe(struct usb_serial *serial)
return 0;
}
static void ftdi_sio_port_remove(struct usb_serial_port *port)
static void ftdi_port_remove(struct usb_serial_port *port)
{
struct ftdi_private *priv = usb_get_serial_port_data(port);
ftdi_gpio_remove(port);
remove_sysfs_attrs(port);
kfree(priv);
}
......@@ -2394,7 +2352,7 @@ static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port)
usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE,
FTDI_SIO_RESET_SIO,
priv->interface, NULL, 0, WDR_TIMEOUT);
priv->channel, NULL, 0, WDR_TIMEOUT);
/* Termios defaults are set by usb_serial_init. We don't change
port->tty->termios - this would lose speed settings, etc.
......@@ -2417,7 +2375,7 @@ static void ftdi_dtr_rts(struct usb_serial_port *port, int on)
usb_sndctrlpipe(port->serial->dev, 0),
FTDI_SIO_SET_FLOW_CTRL_REQUEST,
FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
0, priv->interface, NULL, 0,
0, priv->channel, NULL, 0,
WDR_TIMEOUT) < 0) {
dev_err(&port->dev, "error from flowcontrol urb\n");
}
......@@ -2610,7 +2568,7 @@ static void ftdi_break_ctl(struct tty_struct *tty, int break_state)
usb_sndctrlpipe(port->serial->dev, 0),
FTDI_SIO_SET_DATA_REQUEST,
FTDI_SIO_SET_DATA_REQUEST_TYPE,
value , priv->interface,
value, priv->channel,
NULL, 0, WDR_TIMEOUT) < 0) {
dev_err(&port->dev, "%s FAILED to enable/disable break state (state was %d)\n",
__func__, break_state);
......@@ -2746,7 +2704,7 @@ static void ftdi_set_termios(struct tty_struct *tty,
if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
FTDI_SIO_SET_DATA_REQUEST,
FTDI_SIO_SET_DATA_REQUEST_TYPE,
value , priv->interface,
value, priv->channel,
NULL, 0, WDR_SHORT_TIMEOUT) < 0) {
dev_err(ddev, "%s FAILED to set databits/stopbits/parity\n",
__func__);
......@@ -2759,7 +2717,7 @@ static void ftdi_set_termios(struct tty_struct *tty,
if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
FTDI_SIO_SET_FLOW_CTRL_REQUEST,
FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
0, priv->interface,
0, priv->channel,
NULL, 0, WDR_TIMEOUT) < 0) {
dev_err(ddev, "%s error from disable flowcontrol urb\n",
__func__);
......@@ -2793,7 +2751,7 @@ static void ftdi_set_termios(struct tty_struct *tty,
index = FTDI_SIO_DISABLE_FLOW_CTRL;
}
index |= priv->interface;
index |= priv->channel;
ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
FTDI_SIO_SET_FLOW_CTRL_REQUEST,
......@@ -2821,33 +2779,19 @@ static int ftdi_get_modem_status(struct usb_serial_port *port,
if (!buf)
return -ENOMEM;
/*
* The 8U232AM returns a two byte value (the SIO a 1 byte value) in
* the same format as the data returned from the in point.
* The device returns a two byte value (the SIO a 1 byte value) in the
* same format as the data returned from the IN endpoint.
*/
switch (priv->chip_type) {
case SIO:
if (priv->chip_type == SIO)
len = 1;
break;
case FT8U232AM:
case FT232BM:
case FT2232C:
case FT232RL:
case FT2232H:
case FT4232H:
case FT232H:
case FTX:
else
len = 2;
break;
default:
ret = -EFAULT;
goto out;
}
ret = usb_control_msg(port->serial->dev,
usb_rcvctrlpipe(port->serial->dev, 0),
FTDI_SIO_GET_MODEM_STATUS_REQUEST,
FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE,
0, priv->interface,
0, priv->channel,
buf, len, WDR_TIMEOUT);
/* NOTE: We allow short responses and handle that below. */
......@@ -2917,6 +2861,41 @@ static int ftdi_ioctl(struct tty_struct *tty,
return -ENOIOCTLCMD;
}
static struct usb_serial_driver ftdi_device = {
.driver = {
.owner = THIS_MODULE,
.name = "ftdi_sio",
.dev_groups = ftdi_groups,
},
.description = "FTDI USB Serial Device",
.id_table = id_table_combined,
.num_ports = 1,
.bulk_in_size = 512,
.bulk_out_size = 256,
.probe = ftdi_probe,
.port_probe = ftdi_port_probe,
.port_remove = ftdi_port_remove,
.open = ftdi_open,
.dtr_rts = ftdi_dtr_rts,
.throttle = usb_serial_generic_throttle,
.unthrottle = usb_serial_generic_unthrottle,
.process_read_urb = ftdi_process_read_urb,
.prepare_write_buffer = ftdi_prepare_write_buffer,
.tiocmget = ftdi_tiocmget,
.tiocmset = ftdi_tiocmset,
.tiocmiwait = usb_serial_generic_tiocmiwait,
.get_icount = usb_serial_generic_get_icount,
.ioctl = ftdi_ioctl,
.get_serial = get_serial_info,
.set_serial = set_serial_info,
.set_termios = ftdi_set_termios,
.break_ctl = ftdi_break_ctl,
.tx_empty = ftdi_tx_empty,
};
static struct usb_serial_driver * const serial_drivers[] = {
&ftdi_device, NULL
};
module_usb_serial_driver(serial_drivers, id_table_combined);
MODULE_AUTHOR(DRIVER_AUTHOR);
......
......@@ -40,11 +40,11 @@
#define FTDI_SIO_READ_PINS 0x0c /* Read immediate value of pins */
#define FTDI_SIO_READ_EEPROM 0x90 /* Read EEPROM */
/* Interface indices for FT2232, FT2232H and FT4232H devices */
#define INTERFACE_A 1
#define INTERFACE_B 2
#define INTERFACE_C 3
#define INTERFACE_D 4
/* Channel indices for FT2232, FT2232H and FT4232H devices */
#define CHANNEL_A 1
#define CHANNEL_B 2
#define CHANNEL_C 3
#define CHANNEL_D 4
/*
......@@ -153,18 +153,6 @@
* not supported by the FT8U232AM).
*/
enum ftdi_chip_type {
SIO = 1,
FT8U232AM = 2,
FT232BM = 3,
FT2232C = 4,
FT232RL = 5,
FT2232H = 6,
FT4232H = 7,
FT232H = 8,
FTX = 9,
};
enum ftdi_sio_baudrate {
ftdi_sio_b300 = 0,
ftdi_sio_b600 = 1,
......
......@@ -25,6 +25,13 @@
#define FTDI_4232H_PID 0x6011 /* Quad channel hi-speed device */
#define FTDI_232H_PID 0x6014 /* Single channel hi-speed device */
#define FTDI_FTX_PID 0x6015 /* FT-X series (FT201X, FT230X, FT231X, etc) */
#define FTDI_FT2233HP_PID 0x6040 /* Dual channel hi-speed device with PD */
#define FTDI_FT4233HP_PID 0x6041 /* Quad channel hi-speed device with PD */
#define FTDI_FT2232HP_PID 0x6042 /* Dual channel hi-speed device with PD */
#define FTDI_FT4232HP_PID 0x6043 /* Quad channel hi-speed device with PD */
#define FTDI_FT233HP_PID 0x6044 /* Dual channel hi-speed device with PD */
#define FTDI_FT232HP_PID 0x6045 /* Dual channel hi-speed device with PD */
#define FTDI_FT4232HA_PID 0x6048 /* Quad channel automotive grade hi-speed device */
#define FTDI_SIO_PID 0x8372 /* Product Id SIO application of 8U100AX */
#define FTDI_232RL_PID 0xFBFA /* Product ID for FT232RL */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment