forked from luck/tmp_suning_uos_patched
USB-serial updates for v4.10-rc1
These updates include a new driver for Fintek F8153x devices, support for the GPIO functionality on CP2105 devices, and improved support for CH34X devices. Included are also some clean ups and fixes for various minor issues. Signed-off-by: Johan Hovold <johan@kernel.org> -----BEGIN PGP SIGNATURE----- iQIuBAABCAAYBQJYQARNERxqb2hhbkBrZXJuZWwub3JnAAoJEEEN5E/e4bSVPxIP /i7OTbUIXqh0J/CMUAwRkCK4zrrXhwHCG77uReAiuiFhglR/wAMbPimumV7Daker S14XFtyhi7oFBu1A9LkFFI2CTuaOFLnnrYc9Bqxfw8vKnCVMBOfqW7hasumkKY1g XWF/IBNQZR3OWqePTefbTgZNXXKe2MMn02XAdswsaxSHXca95eLSu623Rp869H6o voJDzj7RLBJCqLSH/IA0MZcdjcQphEVlpFV5wOfx2+4nvhSBQynLPeH79581eUM2 WsM0lVH9d04AuP5s1CN17cPezBL/cA1dnYThwDXMOC8MI+5resLXP7TalsK5e7pr 2qezrAiD9bwvqM+8nrEz46qpFLBbT+kM7qmlrHc9QNqm0XLtCdGy268z+omYLGuP 1cLA/IOFvn9t/o4NiN9+XgQM90MEBSaKdzsdXuIKgHIlHhT057b6K6Kw7oF4kBmO S3soInK3edIFnaDEOOvp9UANEw/R6bPjmSMAgQsOZcd1T5OI+WNBhM9kBy/w8XfY wLfBLMguoQJbK/06JcKZHL/RDC1VTIjHmUE0ZSu+kjXKweRQJVeYo84438W5QENI c2MBxG/7hC+J40LYfWEHUg/HaPVomJV0qRdhx16JtMghXxUBPk1qQqBrlT28CsXh N1EqwiK4dn+Jmi7XxoKTk8QFeAn0EQOI4obeNFIy7kNd =FChe -----END PGP SIGNATURE----- Merge tag 'usb-serial-4.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/johan/usb-serial into usb-next Johan writes: USB-serial updates for v4.10-rc1 These updates include a new driver for Fintek F8153x devices, support for the GPIO functionality on CP2105 devices, and improved support for CH34X devices. Included are also some clean ups and fixes for various minor issues. Signed-off-by: Johan Hovold <johan@kernel.org>
This commit is contained in:
commit
66c79319f8
@ -255,6 +255,16 @@ config USB_SERIAL_F81232
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called f81232.
|
||||
|
||||
config USB_SERIAL_F8153X
|
||||
tristate "USB Fintek F81532/534 Multi-Ports Serial Driver"
|
||||
help
|
||||
Say Y here if you want to use the Fintek F81532/534 Multi-Ports
|
||||
USB to serial adapter.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called f81534.
|
||||
|
||||
|
||||
config USB_SERIAL_GARMIN
|
||||
tristate "USB Garmin GPS driver"
|
||||
help
|
||||
|
@ -23,6 +23,7 @@ obj-$(CONFIG_USB_SERIAL_EDGEPORT) += io_edgeport.o
|
||||
obj-$(CONFIG_USB_SERIAL_EDGEPORT_TI) += io_ti.o
|
||||
obj-$(CONFIG_USB_SERIAL_EMPEG) += empeg.o
|
||||
obj-$(CONFIG_USB_SERIAL_F81232) += f81232.o
|
||||
obj-$(CONFIG_USB_SERIAL_F8153X) += f81534.o
|
||||
obj-$(CONFIG_USB_SERIAL_FTDI_SIO) += ftdi_sio.o
|
||||
obj-$(CONFIG_USB_SERIAL_GARMIN) += garmin_gps.o
|
||||
obj-$(CONFIG_USB_SERIAL_IPAQ) += ipaq.o
|
||||
|
@ -61,13 +61,26 @@
|
||||
* the Net/FreeBSD uchcom.c driver by Takanori Watanabe. Domo arigato.
|
||||
*/
|
||||
|
||||
#define CH341_REQ_READ_VERSION 0x5F
|
||||
#define CH341_REQ_WRITE_REG 0x9A
|
||||
#define CH341_REQ_READ_REG 0x95
|
||||
#define CH341_REG_BREAK1 0x05
|
||||
#define CH341_REG_BREAK2 0x18
|
||||
#define CH341_NBREAK_BITS_REG1 0x01
|
||||
#define CH341_NBREAK_BITS_REG2 0x40
|
||||
#define CH341_REQ_SERIAL_INIT 0xA1
|
||||
#define CH341_REQ_MODEM_CTRL 0xA4
|
||||
|
||||
#define CH341_REG_BREAK 0x05
|
||||
#define CH341_REG_LCR 0x18
|
||||
#define CH341_NBREAK_BITS 0x01
|
||||
|
||||
#define CH341_LCR_ENABLE_RX 0x80
|
||||
#define CH341_LCR_ENABLE_TX 0x40
|
||||
#define CH341_LCR_MARK_SPACE 0x20
|
||||
#define CH341_LCR_PAR_EVEN 0x10
|
||||
#define CH341_LCR_ENABLE_PAR 0x08
|
||||
#define CH341_LCR_STOP_BITS_2 0x04
|
||||
#define CH341_LCR_CS8 0x03
|
||||
#define CH341_LCR_CS7 0x02
|
||||
#define CH341_LCR_CS6 0x01
|
||||
#define CH341_LCR_CS5 0x00
|
||||
|
||||
static const struct usb_device_id id_table[] = {
|
||||
{ USB_DEVICE(0x4348, 0x5523) },
|
||||
@ -119,10 +132,10 @@ static int ch341_control_in(struct usb_device *dev,
|
||||
return r;
|
||||
}
|
||||
|
||||
static int ch341_set_baudrate(struct usb_device *dev,
|
||||
struct ch341_private *priv)
|
||||
static int ch341_init_set_baudrate(struct usb_device *dev,
|
||||
struct ch341_private *priv, unsigned ctrl)
|
||||
{
|
||||
short a, b;
|
||||
short a;
|
||||
int r;
|
||||
unsigned long factor;
|
||||
short divisor;
|
||||
@ -142,18 +155,17 @@ static int ch341_set_baudrate(struct usb_device *dev,
|
||||
|
||||
factor = 0x10000 - factor;
|
||||
a = (factor & 0xff00) | divisor;
|
||||
b = factor & 0xff;
|
||||
|
||||
r = ch341_control_out(dev, 0x9a, 0x1312, a);
|
||||
if (!r)
|
||||
r = ch341_control_out(dev, 0x9a, 0x0f2c, b);
|
||||
/* 0x9c is "enable SFR_UART Control register and timer" */
|
||||
r = ch341_control_out(dev, CH341_REQ_SERIAL_INIT,
|
||||
0x9c | (ctrl << 8), a | 0x80);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int ch341_set_handshake(struct usb_device *dev, u8 control)
|
||||
{
|
||||
return ch341_control_out(dev, 0xa4, ~control, 0);
|
||||
return ch341_control_out(dev, CH341_REQ_MODEM_CTRL, ~control, 0);
|
||||
}
|
||||
|
||||
static int ch341_get_status(struct usb_device *dev, struct ch341_private *priv)
|
||||
@ -167,7 +179,7 @@ static int ch341_get_status(struct usb_device *dev, struct ch341_private *priv)
|
||||
if (!buffer)
|
||||
return -ENOMEM;
|
||||
|
||||
r = ch341_control_in(dev, 0x95, 0x0706, 0, buffer, size);
|
||||
r = ch341_control_in(dev, CH341_REQ_READ_REG, 0x0706, 0, buffer, size);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
|
||||
@ -197,24 +209,21 @@ static int ch341_configure(struct usb_device *dev, struct ch341_private *priv)
|
||||
return -ENOMEM;
|
||||
|
||||
/* expect two bytes 0x27 0x00 */
|
||||
r = ch341_control_in(dev, 0x5f, 0, 0, buffer, size);
|
||||
r = ch341_control_in(dev, CH341_REQ_READ_VERSION, 0, 0, buffer, size);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
dev_dbg(&dev->dev, "Chip version: 0x%02x\n", buffer[0]);
|
||||
|
||||
r = ch341_control_out(dev, 0xa1, 0, 0);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
|
||||
r = ch341_set_baudrate(dev, priv);
|
||||
r = ch341_control_out(dev, CH341_REQ_SERIAL_INIT, 0, 0);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
|
||||
/* expect two bytes 0x56 0x00 */
|
||||
r = ch341_control_in(dev, 0x95, 0x2518, 0, buffer, size);
|
||||
r = ch341_control_in(dev, CH341_REQ_READ_REG, 0x2518, 0, buffer, size);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
|
||||
r = ch341_control_out(dev, 0x9a, 0x2518, 0x0050);
|
||||
r = ch341_control_out(dev, CH341_REQ_WRITE_REG, 0x2518, 0x0050);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
|
||||
@ -223,11 +232,7 @@ static int ch341_configure(struct usb_device *dev, struct ch341_private *priv)
|
||||
if (r < 0)
|
||||
goto out;
|
||||
|
||||
r = ch341_control_out(dev, 0xa1, 0x501f, 0xd90a);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
|
||||
r = ch341_set_baudrate(dev, priv);
|
||||
r = ch341_init_set_baudrate(dev, priv, 0);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
|
||||
@ -342,16 +347,53 @@ static void ch341_set_termios(struct tty_struct *tty,
|
||||
struct ch341_private *priv = usb_get_serial_port_data(port);
|
||||
unsigned baud_rate;
|
||||
unsigned long flags;
|
||||
unsigned char ctrl;
|
||||
int r;
|
||||
|
||||
/* redundant changes may cause the chip to lose bytes */
|
||||
if (old_termios && !tty_termios_hw_change(&tty->termios, old_termios))
|
||||
return;
|
||||
|
||||
baud_rate = tty_get_baud_rate(tty);
|
||||
|
||||
priv->baud_rate = baud_rate;
|
||||
ctrl = CH341_LCR_ENABLE_RX | CH341_LCR_ENABLE_TX;
|
||||
|
||||
switch (C_CSIZE(tty)) {
|
||||
case CS5:
|
||||
ctrl |= CH341_LCR_CS5;
|
||||
break;
|
||||
case CS6:
|
||||
ctrl |= CH341_LCR_CS6;
|
||||
break;
|
||||
case CS7:
|
||||
ctrl |= CH341_LCR_CS7;
|
||||
break;
|
||||
case CS8:
|
||||
ctrl |= CH341_LCR_CS8;
|
||||
break;
|
||||
}
|
||||
|
||||
if (C_PARENB(tty)) {
|
||||
ctrl |= CH341_LCR_ENABLE_PAR;
|
||||
if (C_PARODD(tty) == 0)
|
||||
ctrl |= CH341_LCR_PAR_EVEN;
|
||||
if (C_CMSPAR(tty))
|
||||
ctrl |= CH341_LCR_MARK_SPACE;
|
||||
}
|
||||
|
||||
if (C_CSTOPB(tty))
|
||||
ctrl |= CH341_LCR_STOP_BITS_2;
|
||||
|
||||
if (baud_rate) {
|
||||
spin_lock_irqsave(&priv->lock, flags);
|
||||
priv->line_control |= (CH341_BIT_DTR | CH341_BIT_RTS);
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
ch341_set_baudrate(port->serial->dev, priv);
|
||||
r = ch341_init_set_baudrate(port->serial->dev, priv, ctrl);
|
||||
if (r < 0 && old_termios) {
|
||||
priv->baud_rate = tty_termios_baud_rate(old_termios);
|
||||
tty_termios_copy_hw(&tty->termios, old_termios);
|
||||
}
|
||||
} else {
|
||||
spin_lock_irqsave(&priv->lock, flags);
|
||||
priv->line_control &= ~(CH341_BIT_DTR | CH341_BIT_RTS);
|
||||
@ -360,17 +402,12 @@ static void ch341_set_termios(struct tty_struct *tty,
|
||||
|
||||
ch341_set_handshake(port->serial->dev, priv->line_control);
|
||||
|
||||
/* Unimplemented:
|
||||
* (cflag & CSIZE) : data bits [5, 8]
|
||||
* (cflag & PARENB) : parity {NONE, EVEN, ODD}
|
||||
* (cflag & CSTOPB) : stop bits [1, 2]
|
||||
*/
|
||||
}
|
||||
|
||||
static void ch341_break_ctl(struct tty_struct *tty, int break_state)
|
||||
{
|
||||
const uint16_t ch341_break_reg =
|
||||
((uint16_t) CH341_REG_BREAK2 << 8) | CH341_REG_BREAK1;
|
||||
((uint16_t) CH341_REG_LCR << 8) | CH341_REG_BREAK;
|
||||
struct usb_serial_port *port = tty->driver_data;
|
||||
int r;
|
||||
uint16_t reg_contents;
|
||||
@ -391,12 +428,12 @@ static void ch341_break_ctl(struct tty_struct *tty, int break_state)
|
||||
__func__, break_reg[0], break_reg[1]);
|
||||
if (break_state != 0) {
|
||||
dev_dbg(&port->dev, "%s - Enter break state requested\n", __func__);
|
||||
break_reg[0] &= ~CH341_NBREAK_BITS_REG1;
|
||||
break_reg[1] &= ~CH341_NBREAK_BITS_REG2;
|
||||
break_reg[0] &= ~CH341_NBREAK_BITS;
|
||||
break_reg[1] &= ~CH341_LCR_ENABLE_TX;
|
||||
} else {
|
||||
dev_dbg(&port->dev, "%s - Leave break state requested\n", __func__);
|
||||
break_reg[0] |= CH341_NBREAK_BITS_REG1;
|
||||
break_reg[1] |= CH341_NBREAK_BITS_REG2;
|
||||
break_reg[0] |= CH341_NBREAK_BITS;
|
||||
break_reg[1] |= CH341_LCR_ENABLE_TX;
|
||||
}
|
||||
dev_dbg(&port->dev, "%s - New ch341 break register contents - reg1: %x, reg2: %x\n",
|
||||
__func__, break_reg[0], break_reg[1]);
|
||||
|
@ -23,6 +23,9 @@
|
||||
#include <linux/usb.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/usb/serial.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
#define DRIVER_DESC "Silicon Labs CP210x RS232 serial adaptor driver"
|
||||
|
||||
@ -33,7 +36,7 @@ static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *);
|
||||
static void cp210x_close(struct usb_serial_port *);
|
||||
static void cp210x_get_termios(struct tty_struct *, struct usb_serial_port *);
|
||||
static void cp210x_get_termios_port(struct usb_serial_port *port,
|
||||
unsigned int *cflagp, unsigned int *baudp);
|
||||
tcflag_t *cflagp, unsigned int *baudp);
|
||||
static void cp210x_change_speed(struct tty_struct *, struct usb_serial_port *,
|
||||
struct ktermios *);
|
||||
static void cp210x_set_termios(struct tty_struct *, struct usb_serial_port *,
|
||||
@ -44,6 +47,9 @@ static int cp210x_tiocmset(struct tty_struct *, unsigned int, unsigned int);
|
||||
static int cp210x_tiocmset_port(struct usb_serial_port *port,
|
||||
unsigned int, unsigned int);
|
||||
static void cp210x_break_ctl(struct tty_struct *, int);
|
||||
static int cp210x_attach(struct usb_serial *);
|
||||
static void cp210x_disconnect(struct usb_serial *);
|
||||
static void cp210x_release(struct usb_serial *);
|
||||
static int cp210x_port_probe(struct usb_serial_port *);
|
||||
static int cp210x_port_remove(struct usb_serial_port *);
|
||||
static void cp210x_dtr_rts(struct usb_serial_port *p, int on);
|
||||
@ -209,6 +215,16 @@ static const struct usb_device_id id_table[] = {
|
||||
|
||||
MODULE_DEVICE_TABLE(usb, id_table);
|
||||
|
||||
struct cp210x_serial_private {
|
||||
#ifdef CONFIG_GPIOLIB
|
||||
struct gpio_chip gc;
|
||||
u8 config;
|
||||
u8 gpio_mode;
|
||||
bool gpio_registered;
|
||||
#endif
|
||||
u8 partnum;
|
||||
};
|
||||
|
||||
struct cp210x_port_private {
|
||||
__u8 bInterfaceNumber;
|
||||
bool has_swapped_line_ctl;
|
||||
@ -230,6 +246,9 @@ static struct usb_serial_driver cp210x_device = {
|
||||
.tx_empty = cp210x_tx_empty,
|
||||
.tiocmget = cp210x_tiocmget,
|
||||
.tiocmset = cp210x_tiocmset,
|
||||
.attach = cp210x_attach,
|
||||
.disconnect = cp210x_disconnect,
|
||||
.release = cp210x_release,
|
||||
.port_probe = cp210x_port_probe,
|
||||
.port_remove = cp210x_port_remove,
|
||||
.dtr_rts = cp210x_dtr_rts
|
||||
@ -272,6 +291,7 @@ static struct usb_serial_driver * const serial_drivers[] = {
|
||||
#define CP210X_SET_CHARS 0x19
|
||||
#define CP210X_GET_BAUDRATE 0x1D
|
||||
#define CP210X_SET_BAUDRATE 0x1E
|
||||
#define CP210X_VENDOR_SPECIFIC 0xFF
|
||||
|
||||
/* CP210X_IFC_ENABLE */
|
||||
#define UART_ENABLE 0x0001
|
||||
@ -314,6 +334,21 @@ static struct usb_serial_driver * const serial_drivers[] = {
|
||||
#define CONTROL_WRITE_DTR 0x0100
|
||||
#define CONTROL_WRITE_RTS 0x0200
|
||||
|
||||
/* CP210X_VENDOR_SPECIFIC values */
|
||||
#define CP210X_READ_LATCH 0x00C2
|
||||
#define CP210X_GET_PARTNUM 0x370B
|
||||
#define CP210X_GET_PORTCONFIG 0x370C
|
||||
#define CP210X_GET_DEVICEMODE 0x3711
|
||||
#define CP210X_WRITE_LATCH 0x37E1
|
||||
|
||||
/* Part number definitions */
|
||||
#define CP210X_PARTNUM_CP2101 0x01
|
||||
#define CP210X_PARTNUM_CP2102 0x02
|
||||
#define CP210X_PARTNUM_CP2103 0x03
|
||||
#define CP210X_PARTNUM_CP2104 0x04
|
||||
#define CP210X_PARTNUM_CP2105 0x05
|
||||
#define CP210X_PARTNUM_CP2108 0x08
|
||||
|
||||
/* CP210X_GET_COMM_STATUS returns these 0x13 bytes */
|
||||
struct cp210x_comm_status {
|
||||
__le32 ulErrors;
|
||||
@ -369,6 +404,60 @@ struct cp210x_flow_ctl {
|
||||
#define CP210X_SERIAL_RTS_ACTIVE 1
|
||||
#define CP210X_SERIAL_RTS_FLOW_CTL 2
|
||||
|
||||
/* CP210X_VENDOR_SPECIFIC, CP210X_GET_DEVICEMODE call reads these 0x2 bytes. */
|
||||
struct cp210x_pin_mode {
|
||||
u8 eci;
|
||||
u8 sci;
|
||||
} __packed;
|
||||
|
||||
#define CP210X_PIN_MODE_MODEM 0
|
||||
#define CP210X_PIN_MODE_GPIO BIT(0)
|
||||
|
||||
/*
|
||||
* CP210X_VENDOR_SPECIFIC, CP210X_GET_PORTCONFIG call reads these 0xf bytes.
|
||||
* Structure needs padding due to unused/unspecified bytes.
|
||||
*/
|
||||
struct cp210x_config {
|
||||
__le16 gpio_mode;
|
||||
u8 __pad0[2];
|
||||
__le16 reset_state;
|
||||
u8 __pad1[4];
|
||||
__le16 suspend_state;
|
||||
u8 sci_cfg;
|
||||
u8 eci_cfg;
|
||||
u8 device_cfg;
|
||||
} __packed;
|
||||
|
||||
/* GPIO modes */
|
||||
#define CP210X_SCI_GPIO_MODE_OFFSET 9
|
||||
#define CP210X_SCI_GPIO_MODE_MASK GENMASK(11, 9)
|
||||
|
||||
#define CP210X_ECI_GPIO_MODE_OFFSET 2
|
||||
#define CP210X_ECI_GPIO_MODE_MASK GENMASK(3, 2)
|
||||
|
||||
/* CP2105 port configuration values */
|
||||
#define CP2105_GPIO0_TXLED_MODE BIT(0)
|
||||
#define CP2105_GPIO1_RXLED_MODE BIT(1)
|
||||
#define CP2105_GPIO1_RS485_MODE BIT(2)
|
||||
|
||||
/* CP210X_VENDOR_SPECIFIC, CP210X_WRITE_LATCH call writes these 0x2 bytes. */
|
||||
struct cp210x_gpio_write {
|
||||
u8 mask;
|
||||
u8 state;
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* Helper to get interface number when we only have struct usb_serial.
|
||||
*/
|
||||
static u8 cp210x_interface_num(struct usb_serial *serial)
|
||||
{
|
||||
struct usb_host_interface *cur_altsetting;
|
||||
|
||||
cur_altsetting = serial->interface->cur_altsetting;
|
||||
|
||||
return cur_altsetting->desc.bInterfaceNumber;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reads a variable-sized block of CP210X_ registers, identified by req.
|
||||
* Returns data into buf in native USB byte order.
|
||||
@ -402,7 +491,7 @@ static int cp210x_read_reg_block(struct usb_serial_port *port, u8 req,
|
||||
dev_err(&port->dev, "failed get req 0x%x size %d status: %d\n",
|
||||
req, bufsize, result);
|
||||
if (result >= 0)
|
||||
result = -EPROTO;
|
||||
result = -EIO;
|
||||
|
||||
/*
|
||||
* FIXME Some callers don't bother to check for error,
|
||||
@ -464,6 +553,40 @@ static int cp210x_read_u8_reg(struct usb_serial_port *port, u8 req, u8 *val)
|
||||
return cp210x_read_reg_block(port, req, val, sizeof(*val));
|
||||
}
|
||||
|
||||
/*
|
||||
* Reads a variable-sized vendor block of CP210X_ registers, identified by val.
|
||||
* Returns data into buf in native USB byte order.
|
||||
*/
|
||||
static int cp210x_read_vendor_block(struct usb_serial *serial, u8 type, u16 val,
|
||||
void *buf, int bufsize)
|
||||
{
|
||||
void *dmabuf;
|
||||
int result;
|
||||
|
||||
dmabuf = kmalloc(bufsize, GFP_KERNEL);
|
||||
if (!dmabuf)
|
||||
return -ENOMEM;
|
||||
|
||||
result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
|
||||
CP210X_VENDOR_SPECIFIC, type, val,
|
||||
cp210x_interface_num(serial), dmabuf, bufsize,
|
||||
USB_CTRL_GET_TIMEOUT);
|
||||
if (result == bufsize) {
|
||||
memcpy(buf, dmabuf, bufsize);
|
||||
result = 0;
|
||||
} else {
|
||||
dev_err(&serial->interface->dev,
|
||||
"failed to get vendor val 0x%04x size %d: %d\n", val,
|
||||
bufsize, result);
|
||||
if (result >= 0)
|
||||
result = -EIO;
|
||||
}
|
||||
|
||||
kfree(dmabuf);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Writes any 16-bit CP210X_ register (req) whose value is passed
|
||||
* entirely in the wValue field of the USB request.
|
||||
@ -515,7 +638,7 @@ static int cp210x_write_reg_block(struct usb_serial_port *port, u8 req,
|
||||
dev_err(&port->dev, "failed set req 0x%x size %d status: %d\n",
|
||||
req, bufsize, result);
|
||||
if (result >= 0)
|
||||
result = -EPROTO;
|
||||
result = -EIO;
|
||||
}
|
||||
|
||||
return result;
|
||||
@ -533,6 +656,42 @@ static int cp210x_write_u32_reg(struct usb_serial_port *port, u8 req, u32 val)
|
||||
return cp210x_write_reg_block(port, req, &le32_val, sizeof(le32_val));
|
||||
}
|
||||
|
||||
#ifdef CONFIG_GPIOLIB
|
||||
/*
|
||||
* Writes a variable-sized vendor block of CP210X_ registers, identified by val.
|
||||
* Data in buf must be in native USB byte order.
|
||||
*/
|
||||
static int cp210x_write_vendor_block(struct usb_serial *serial, u8 type,
|
||||
u16 val, void *buf, int bufsize)
|
||||
{
|
||||
void *dmabuf;
|
||||
int result;
|
||||
|
||||
dmabuf = kmemdup(buf, bufsize, GFP_KERNEL);
|
||||
if (!dmabuf)
|
||||
return -ENOMEM;
|
||||
|
||||
result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
|
||||
CP210X_VENDOR_SPECIFIC, type, val,
|
||||
cp210x_interface_num(serial), dmabuf, bufsize,
|
||||
USB_CTRL_SET_TIMEOUT);
|
||||
|
||||
kfree(dmabuf);
|
||||
|
||||
if (result == bufsize) {
|
||||
result = 0;
|
||||
} else {
|
||||
dev_err(&serial->interface->dev,
|
||||
"failed to set vendor val 0x%04x size %d: %d\n", val,
|
||||
bufsize, result);
|
||||
if (result >= 0)
|
||||
result = -EIO;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Detect CP2108 GET_LINE_CTL bug and activate workaround.
|
||||
* Write a known good value 0x800, read it back.
|
||||
@ -683,7 +842,7 @@ static int cp210x_get_tx_queue_byte_count(struct usb_serial_port *port,
|
||||
} else {
|
||||
dev_err(&port->dev, "failed to get comm status: %d\n", result);
|
||||
if (result >= 0)
|
||||
result = -EPROTO;
|
||||
result = -EIO;
|
||||
}
|
||||
|
||||
kfree(sts);
|
||||
@ -719,7 +878,7 @@ static void cp210x_get_termios(struct tty_struct *tty,
|
||||
&tty->termios.c_cflag, &baud);
|
||||
tty_encode_baud_rate(tty, baud, baud);
|
||||
} else {
|
||||
unsigned int cflag;
|
||||
tcflag_t cflag;
|
||||
cflag = 0;
|
||||
cp210x_get_termios_port(port, &cflag, &baud);
|
||||
}
|
||||
@ -730,10 +889,10 @@ static void cp210x_get_termios(struct tty_struct *tty,
|
||||
* This is the heart of cp210x_get_termios which always uses a &usb_serial_port.
|
||||
*/
|
||||
static void cp210x_get_termios_port(struct usb_serial_port *port,
|
||||
unsigned int *cflagp, unsigned int *baudp)
|
||||
tcflag_t *cflagp, unsigned int *baudp)
|
||||
{
|
||||
struct device *dev = &port->dev;
|
||||
unsigned int cflag;
|
||||
tcflag_t cflag;
|
||||
struct cp210x_flow_ctl flow_ctl;
|
||||
u32 baud;
|
||||
u16 bits;
|
||||
@ -930,17 +1089,10 @@ static void cp210x_set_termios(struct tty_struct *tty,
|
||||
dev_dbg(dev, "%s - data bits = 7\n", __func__);
|
||||
break;
|
||||
case CS8:
|
||||
default:
|
||||
bits |= BITS_DATA_8;
|
||||
dev_dbg(dev, "%s - data bits = 8\n", __func__);
|
||||
break;
|
||||
/*case CS9:
|
||||
bits |= BITS_DATA_9;
|
||||
dev_dbg(dev, "%s - data bits = 9\n", __func__);
|
||||
break;*/
|
||||
default:
|
||||
dev_dbg(dev, "cp210x driver does not support the number of bits requested, using 8 bit mode\n");
|
||||
bits |= BITS_DATA_8;
|
||||
break;
|
||||
}
|
||||
if (cp210x_write_u16_reg(port, CP210X_SET_LINE_CTL, bits))
|
||||
dev_dbg(dev, "Number of data bits requested not supported by device\n");
|
||||
@ -1108,10 +1260,188 @@ static void cp210x_break_ctl(struct tty_struct *tty, int break_state)
|
||||
cp210x_write_u16_reg(port, CP210X_SET_BREAK, state);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_GPIOLIB
|
||||
static int cp210x_gpio_request(struct gpio_chip *gc, unsigned int offset)
|
||||
{
|
||||
struct usb_serial *serial = gpiochip_get_data(gc);
|
||||
struct cp210x_serial_private *priv = usb_get_serial_data(serial);
|
||||
|
||||
switch (offset) {
|
||||
case 0:
|
||||
if (priv->config & CP2105_GPIO0_TXLED_MODE)
|
||||
return -ENODEV;
|
||||
break;
|
||||
case 1:
|
||||
if (priv->config & (CP2105_GPIO1_RXLED_MODE |
|
||||
CP2105_GPIO1_RS485_MODE))
|
||||
return -ENODEV;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cp210x_gpio_get(struct gpio_chip *gc, unsigned int gpio)
|
||||
{
|
||||
struct usb_serial *serial = gpiochip_get_data(gc);
|
||||
int result;
|
||||
u8 buf;
|
||||
|
||||
result = cp210x_read_vendor_block(serial, REQTYPE_INTERFACE_TO_HOST,
|
||||
CP210X_READ_LATCH, &buf, sizeof(buf));
|
||||
if (result < 0)
|
||||
return result;
|
||||
|
||||
return !!(buf & BIT(gpio));
|
||||
}
|
||||
|
||||
static void cp210x_gpio_set(struct gpio_chip *gc, unsigned int gpio, int value)
|
||||
{
|
||||
struct usb_serial *serial = gpiochip_get_data(gc);
|
||||
struct cp210x_gpio_write buf;
|
||||
|
||||
if (value == 1)
|
||||
buf.state = BIT(gpio);
|
||||
else
|
||||
buf.state = 0;
|
||||
|
||||
buf.mask = BIT(gpio);
|
||||
|
||||
cp210x_write_vendor_block(serial, REQTYPE_HOST_TO_INTERFACE,
|
||||
CP210X_WRITE_LATCH, &buf, sizeof(buf));
|
||||
}
|
||||
|
||||
static int cp210x_gpio_direction_get(struct gpio_chip *gc, unsigned int gpio)
|
||||
{
|
||||
/* Hardware does not support an input mode */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cp210x_gpio_direction_input(struct gpio_chip *gc, unsigned int gpio)
|
||||
{
|
||||
/* Hardware does not support an input mode */
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
static int cp210x_gpio_direction_output(struct gpio_chip *gc, unsigned int gpio,
|
||||
int value)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cp210x_gpio_set_single_ended(struct gpio_chip *gc, unsigned int gpio,
|
||||
enum single_ended_mode mode)
|
||||
{
|
||||
struct usb_serial *serial = gpiochip_get_data(gc);
|
||||
struct cp210x_serial_private *priv = usb_get_serial_data(serial);
|
||||
|
||||
/* Succeed only if in correct mode (this can't be set at runtime) */
|
||||
if ((mode == LINE_MODE_PUSH_PULL) && (priv->gpio_mode & BIT(gpio)))
|
||||
return 0;
|
||||
|
||||
if ((mode == LINE_MODE_OPEN_DRAIN) && !(priv->gpio_mode & BIT(gpio)))
|
||||
return 0;
|
||||
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is for configuring GPIO using shared pins, where other signals
|
||||
* are made unavailable by configuring the use of GPIO. This is believed to be
|
||||
* only applicable to the cp2105 at this point, the other devices supported by
|
||||
* this driver that provide GPIO do so in a way that does not impact other
|
||||
* signals and are thus expected to have very different initialisation.
|
||||
*/
|
||||
static int cp2105_shared_gpio_init(struct usb_serial *serial)
|
||||
{
|
||||
struct cp210x_serial_private *priv = usb_get_serial_data(serial);
|
||||
struct cp210x_pin_mode mode;
|
||||
struct cp210x_config config;
|
||||
u8 intf_num = cp210x_interface_num(serial);
|
||||
int result;
|
||||
|
||||
result = cp210x_read_vendor_block(serial, REQTYPE_DEVICE_TO_HOST,
|
||||
CP210X_GET_DEVICEMODE, &mode,
|
||||
sizeof(mode));
|
||||
if (result < 0)
|
||||
return result;
|
||||
|
||||
result = cp210x_read_vendor_block(serial, REQTYPE_DEVICE_TO_HOST,
|
||||
CP210X_GET_PORTCONFIG, &config,
|
||||
sizeof(config));
|
||||
if (result < 0)
|
||||
return result;
|
||||
|
||||
/* 2 banks of GPIO - One for the pins taken from each serial port */
|
||||
if (intf_num == 0) {
|
||||
if (mode.eci == CP210X_PIN_MODE_MODEM)
|
||||
return 0;
|
||||
|
||||
priv->config = config.eci_cfg;
|
||||
priv->gpio_mode = (u8)((le16_to_cpu(config.gpio_mode) &
|
||||
CP210X_ECI_GPIO_MODE_MASK) >>
|
||||
CP210X_ECI_GPIO_MODE_OFFSET);
|
||||
priv->gc.ngpio = 2;
|
||||
} else if (intf_num == 1) {
|
||||
if (mode.sci == CP210X_PIN_MODE_MODEM)
|
||||
return 0;
|
||||
|
||||
priv->config = config.sci_cfg;
|
||||
priv->gpio_mode = (u8)((le16_to_cpu(config.gpio_mode) &
|
||||
CP210X_SCI_GPIO_MODE_MASK) >>
|
||||
CP210X_SCI_GPIO_MODE_OFFSET);
|
||||
priv->gc.ngpio = 3;
|
||||
} else {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
priv->gc.label = "cp210x";
|
||||
priv->gc.request = cp210x_gpio_request;
|
||||
priv->gc.get_direction = cp210x_gpio_direction_get;
|
||||
priv->gc.direction_input = cp210x_gpio_direction_input;
|
||||
priv->gc.direction_output = cp210x_gpio_direction_output;
|
||||
priv->gc.get = cp210x_gpio_get;
|
||||
priv->gc.set = cp210x_gpio_set;
|
||||
priv->gc.set_single_ended = cp210x_gpio_set_single_ended;
|
||||
priv->gc.owner = THIS_MODULE;
|
||||
priv->gc.parent = &serial->interface->dev;
|
||||
priv->gc.base = -1;
|
||||
priv->gc.can_sleep = true;
|
||||
|
||||
result = gpiochip_add_data(&priv->gc, serial);
|
||||
if (!result)
|
||||
priv->gpio_registered = true;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void cp210x_gpio_remove(struct usb_serial *serial)
|
||||
{
|
||||
struct cp210x_serial_private *priv = usb_get_serial_data(serial);
|
||||
|
||||
if (priv->gpio_registered) {
|
||||
gpiochip_remove(&priv->gc);
|
||||
priv->gpio_registered = false;
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static int cp2105_shared_gpio_init(struct usb_serial *serial)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cp210x_gpio_remove(struct usb_serial *serial)
|
||||
{
|
||||
/* Nothing to do */
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static int cp210x_port_probe(struct usb_serial_port *port)
|
||||
{
|
||||
struct usb_serial *serial = port->serial;
|
||||
struct usb_host_interface *cur_altsetting;
|
||||
struct cp210x_port_private *port_priv;
|
||||
int ret;
|
||||
|
||||
@ -1119,8 +1449,7 @@ static int cp210x_port_probe(struct usb_serial_port *port)
|
||||
if (!port_priv)
|
||||
return -ENOMEM;
|
||||
|
||||
cur_altsetting = serial->interface->cur_altsetting;
|
||||
port_priv->bInterfaceNumber = cur_altsetting->desc.bInterfaceNumber;
|
||||
port_priv->bInterfaceNumber = cp210x_interface_num(serial);
|
||||
|
||||
usb_set_serial_port_data(port, port_priv);
|
||||
|
||||
@ -1143,6 +1472,52 @@ static int cp210x_port_remove(struct usb_serial_port *port)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cp210x_attach(struct usb_serial *serial)
|
||||
{
|
||||
int result;
|
||||
struct cp210x_serial_private *priv;
|
||||
|
||||
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
result = cp210x_read_vendor_block(serial, REQTYPE_DEVICE_TO_HOST,
|
||||
CP210X_GET_PARTNUM, &priv->partnum,
|
||||
sizeof(priv->partnum));
|
||||
if (result < 0)
|
||||
goto err_free_priv;
|
||||
|
||||
usb_set_serial_data(serial, priv);
|
||||
|
||||
if (priv->partnum == CP210X_PARTNUM_CP2105) {
|
||||
result = cp2105_shared_gpio_init(serial);
|
||||
if (result < 0) {
|
||||
dev_err(&serial->interface->dev,
|
||||
"GPIO initialisation failed, continuing without GPIO support\n");
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
err_free_priv:
|
||||
kfree(priv);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void cp210x_disconnect(struct usb_serial *serial)
|
||||
{
|
||||
cp210x_gpio_remove(serial);
|
||||
}
|
||||
|
||||
static void cp210x_release(struct usb_serial *serial)
|
||||
{
|
||||
struct cp210x_serial_private *priv = usb_get_serial_data(serial);
|
||||
|
||||
cp210x_gpio_remove(serial);
|
||||
|
||||
kfree(priv);
|
||||
}
|
||||
|
||||
module_usb_serial_driver(serial_drivers, id_table);
|
||||
|
||||
MODULE_DESCRIPTION(DRIVER_DESC);
|
||||
|
1409
drivers/usb/serial/f81534.c
Normal file
1409
drivers/usb/serial/f81534.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -1455,8 +1455,6 @@ static int get_serial_info(struct usb_serial_port *port,
|
||||
struct ftdi_private *priv = usb_get_serial_port_data(port);
|
||||
struct serial_struct tmp;
|
||||
|
||||
if (!retinfo)
|
||||
return -EFAULT;
|
||||
memset(&tmp, 0, sizeof(tmp));
|
||||
tmp.flags = priv->flags;
|
||||
tmp.baud_base = priv->baud_base;
|
||||
@ -1538,9 +1536,6 @@ static int get_lsr_info(struct usb_serial_port *port,
|
||||
struct ftdi_private *priv = usb_get_serial_port_data(port);
|
||||
unsigned int result = 0;
|
||||
|
||||
if (!retinfo)
|
||||
return -EFAULT;
|
||||
|
||||
if (priv->transmit_empty)
|
||||
result = TIOCSER_TEMT;
|
||||
|
||||
|
@ -1554,9 +1554,6 @@ static int get_serial_info(struct edgeport_port *edge_port,
|
||||
{
|
||||
struct serial_struct tmp;
|
||||
|
||||
if (!retinfo)
|
||||
return -EFAULT;
|
||||
|
||||
memset(&tmp, 0, sizeof(tmp));
|
||||
|
||||
tmp.type = PORT_16550A;
|
||||
|
@ -2459,9 +2459,6 @@ static int get_serial_info(struct edgeport_port *edge_port,
|
||||
struct serial_struct tmp;
|
||||
unsigned cwait;
|
||||
|
||||
if (!retinfo)
|
||||
return -EFAULT;
|
||||
|
||||
cwait = edge_port->port->port.closing_wait;
|
||||
if (cwait != ASYNC_CLOSING_WAIT_NONE)
|
||||
cwait = jiffies_to_msecs(cwait) / 10;
|
||||
|
@ -296,7 +296,7 @@ static int klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port)
|
||||
rc = usb_serial_generic_open(tty, port);
|
||||
if (rc) {
|
||||
retval = rc;
|
||||
goto exit;
|
||||
goto err_free_cfg;
|
||||
}
|
||||
|
||||
rc = usb_control_msg(port->serial->dev,
|
||||
@ -311,21 +311,38 @@ static int klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port)
|
||||
if (rc < 0) {
|
||||
dev_err(&port->dev, "Enabling read failed (error = %d)\n", rc);
|
||||
retval = rc;
|
||||
goto err_generic_close;
|
||||
} else
|
||||
dev_dbg(&port->dev, "%s - enabled reading\n", __func__);
|
||||
|
||||
rc = klsi_105_get_line_state(port, &line_state);
|
||||
if (rc >= 0) {
|
||||
spin_lock_irqsave(&priv->lock, flags);
|
||||
priv->line_state = line_state;
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
dev_dbg(&port->dev, "%s - read line state 0x%lx\n", __func__, line_state);
|
||||
retval = 0;
|
||||
} else
|
||||
if (rc < 0) {
|
||||
retval = rc;
|
||||
goto err_disable_read;
|
||||
}
|
||||
|
||||
exit:
|
||||
spin_lock_irqsave(&priv->lock, flags);
|
||||
priv->line_state = line_state;
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
dev_dbg(&port->dev, "%s - read line state 0x%lx\n", __func__,
|
||||
line_state);
|
||||
|
||||
return 0;
|
||||
|
||||
err_disable_read:
|
||||
usb_control_msg(port->serial->dev,
|
||||
usb_sndctrlpipe(port->serial->dev, 0),
|
||||
KL5KUSB105A_SIO_CONFIGURE,
|
||||
USB_TYPE_VENDOR | USB_DIR_OUT,
|
||||
KL5KUSB105A_SIO_CONFIGURE_READ_OFF,
|
||||
0, /* index */
|
||||
NULL, 0,
|
||||
KLSI_TIMEOUT);
|
||||
err_generic_close:
|
||||
usb_serial_generic_close(port);
|
||||
err_free_cfg:
|
||||
kfree(cfg);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
@ -1861,9 +1861,6 @@ static int get_serial_info(struct moschip_port *mos7720_port,
|
||||
{
|
||||
struct serial_struct tmp;
|
||||
|
||||
if (!retinfo)
|
||||
return -EFAULT;
|
||||
|
||||
memset(&tmp, 0, sizeof(tmp));
|
||||
|
||||
tmp.type = PORT_16550A;
|
||||
|
@ -1956,9 +1956,6 @@ static int mos7840_get_serial_info(struct moschip_port *mos7840_port,
|
||||
if (mos7840_port == NULL)
|
||||
return -1;
|
||||
|
||||
if (!retinfo)
|
||||
return -EFAULT;
|
||||
|
||||
memset(&tmp, 0, sizeof(tmp));
|
||||
|
||||
tmp.type = PORT_16550A;
|
||||
|
@ -336,9 +336,6 @@ static int get_serial_info(struct usb_serial_port *port,
|
||||
{
|
||||
struct serial_struct tmp;
|
||||
|
||||
if (!serial)
|
||||
return -EFAULT;
|
||||
|
||||
memset(&tmp, 0x00, sizeof(tmp));
|
||||
|
||||
/* fake emulate a 16550 uart to make userspace code happy */
|
||||
|
@ -463,9 +463,6 @@ static int get_serial_info(struct usb_serial_port *port,
|
||||
{
|
||||
struct serial_struct tmp;
|
||||
|
||||
if (!retinfo)
|
||||
return -EFAULT;
|
||||
|
||||
memset(&tmp, 0, sizeof(tmp));
|
||||
tmp.line = port->minor;
|
||||
tmp.port = 0;
|
||||
|
@ -318,9 +318,6 @@ static int get_serial_info(struct usb_serial_port *port,
|
||||
{
|
||||
struct serial_struct tmp;
|
||||
|
||||
if (!retinfo)
|
||||
return -EFAULT;
|
||||
|
||||
memset(&tmp, 0, sizeof(tmp));
|
||||
tmp.line = port->minor;
|
||||
tmp.port = 0;
|
||||
|
@ -1426,9 +1426,6 @@ static int ti_get_serial_info(struct ti_port *tport,
|
||||
struct serial_struct ret_serial;
|
||||
unsigned cwait;
|
||||
|
||||
if (!ret_arg)
|
||||
return -EFAULT;
|
||||
|
||||
cwait = port->port.closing_wait;
|
||||
if (cwait != ASYNC_CLOSING_WAIT_NONE)
|
||||
cwait = jiffies_to_msecs(cwait) / 10;
|
||||
|
@ -140,9 +140,6 @@ static int get_serial_info(struct usb_serial_port *port,
|
||||
{
|
||||
struct serial_struct tmp;
|
||||
|
||||
if (!retinfo)
|
||||
return -EFAULT;
|
||||
|
||||
memset(&tmp, 0, sizeof(tmp));
|
||||
tmp.line = port->minor;
|
||||
tmp.port = port->port_number;
|
||||
|
Loading…
Reference in New Issue
Block a user