USB: serial: ch314: use usb_control_msg_recv()
usb_control_msg_recv() is a new wrapper function for usb_control_msg() that has error checks for short reads. This function also accepts data buffer on stack. Hence use this function to simplify error handling for short reads. Short reads will now get reported as -EREMOTEIO with no indication of how short the transfer was. Signed-off-by: Himadri Pandya <himadrispandya@gmail.com> Link: https://lore.kernel.org/r/20211001065720.21330-2-himadrispandya@gmail.com [ johan: fix quirk-detection breakage, style changes ] Signed-off-by: Johan Hovold <johan@kernel.org>
This commit is contained in:
parent
c8345c0500
commit
74f2664550
|
@ -131,17 +131,11 @@ static int ch341_control_in(struct usb_device *dev,
|
|||
dev_dbg(&dev->dev, "%s - (%02x,%04x,%04x,%u)\n", __func__,
|
||||
request, value, index, bufsize);
|
||||
|
||||
r = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), request,
|
||||
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
|
||||
value, index, buf, bufsize, DEFAULT_TIMEOUT);
|
||||
if (r < (int)bufsize) {
|
||||
if (r >= 0) {
|
||||
dev_err(&dev->dev,
|
||||
"short control message received (%d < %u)\n",
|
||||
r, bufsize);
|
||||
r = -EIO;
|
||||
}
|
||||
|
||||
r = usb_control_msg_recv(dev, 0, request,
|
||||
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
|
||||
value, index, buf, bufsize, DEFAULT_TIMEOUT,
|
||||
GFP_KERNEL);
|
||||
if (r) {
|
||||
dev_err(&dev->dev, "failed to receive control message: %d\n",
|
||||
r);
|
||||
return r;
|
||||
|
@ -287,24 +281,19 @@ static int ch341_set_handshake(struct usb_device *dev, u8 control)
|
|||
static int ch341_get_status(struct usb_device *dev, struct ch341_private *priv)
|
||||
{
|
||||
const unsigned int size = 2;
|
||||
char *buffer;
|
||||
u8 buffer[2];
|
||||
int r;
|
||||
unsigned long flags;
|
||||
|
||||
buffer = kmalloc(size, GFP_KERNEL);
|
||||
if (!buffer)
|
||||
return -ENOMEM;
|
||||
|
||||
r = ch341_control_in(dev, CH341_REQ_READ_REG, 0x0706, 0, buffer, size);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
spin_lock_irqsave(&priv->lock, flags);
|
||||
priv->msr = (~(*buffer)) & CH341_BITS_MODEM_STAT;
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
|
||||
out: kfree(buffer);
|
||||
return r;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
@ -312,31 +301,28 @@ out: kfree(buffer);
|
|||
static int ch341_configure(struct usb_device *dev, struct ch341_private *priv)
|
||||
{
|
||||
const unsigned int size = 2;
|
||||
char *buffer;
|
||||
u8 buffer[2];
|
||||
int r;
|
||||
|
||||
buffer = kmalloc(size, GFP_KERNEL);
|
||||
if (!buffer)
|
||||
return -ENOMEM;
|
||||
|
||||
/* expect two bytes 0x27 0x00 */
|
||||
r = ch341_control_in(dev, CH341_REQ_READ_VERSION, 0, 0, buffer, size);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
if (r)
|
||||
return r;
|
||||
dev_dbg(&dev->dev, "Chip version: 0x%02x\n", buffer[0]);
|
||||
|
||||
r = ch341_control_out(dev, CH341_REQ_SERIAL_INIT, 0, 0);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
return r;
|
||||
|
||||
r = ch341_set_baudrate_lcr(dev, priv, priv->baud_rate, priv->lcr);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
return r;
|
||||
|
||||
r = ch341_set_handshake(dev, priv->mcr);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
out: kfree(buffer);
|
||||
return r;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ch341_detect_quirks(struct usb_serial_port *port)
|
||||
|
@ -345,40 +331,27 @@ static int ch341_detect_quirks(struct usb_serial_port *port)
|
|||
struct usb_device *udev = port->serial->dev;
|
||||
const unsigned int size = 2;
|
||||
unsigned long quirks = 0;
|
||||
char *buffer;
|
||||
u8 buffer[2];
|
||||
int r;
|
||||
|
||||
buffer = kmalloc(size, GFP_KERNEL);
|
||||
if (!buffer)
|
||||
return -ENOMEM;
|
||||
|
||||
/*
|
||||
* A subset of CH34x devices does not support all features. The
|
||||
* prescaler is limited and there is no support for sending a RS232
|
||||
* break condition. A read failure when trying to set up the latter is
|
||||
* used to detect these devices.
|
||||
*/
|
||||
r = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), CH341_REQ_READ_REG,
|
||||
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
|
||||
CH341_REG_BREAK, 0, buffer, size, DEFAULT_TIMEOUT);
|
||||
r = usb_control_msg_recv(udev, 0, CH341_REQ_READ_REG,
|
||||
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
|
||||
CH341_REG_BREAK, 0, &buffer, size,
|
||||
DEFAULT_TIMEOUT, GFP_KERNEL);
|
||||
if (r == -EPIPE) {
|
||||
dev_info(&port->dev, "break control not supported, using simulated break\n");
|
||||
quirks = CH341_QUIRK_LIMITED_PRESCALER | CH341_QUIRK_SIMULATE_BREAK;
|
||||
r = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (r != size) {
|
||||
if (r >= 0)
|
||||
r = -EIO;
|
||||
} else if (r) {
|
||||
dev_err(&port->dev, "failed to read break control: %d\n", r);
|
||||
goto out;
|
||||
}
|
||||
|
||||
r = 0;
|
||||
out:
|
||||
kfree(buffer);
|
||||
|
||||
if (quirks) {
|
||||
dev_dbg(&port->dev, "enabling quirk flags: 0x%02lx\n", quirks);
|
||||
priv->quirks |= quirks;
|
||||
|
@ -647,23 +620,19 @@ static void ch341_break_ctl(struct tty_struct *tty, int break_state)
|
|||
struct ch341_private *priv = usb_get_serial_port_data(port);
|
||||
int r;
|
||||
uint16_t reg_contents;
|
||||
uint8_t *break_reg;
|
||||
uint8_t break_reg[2];
|
||||
|
||||
if (priv->quirks & CH341_QUIRK_SIMULATE_BREAK) {
|
||||
ch341_simulate_break(tty, break_state);
|
||||
return;
|
||||
}
|
||||
|
||||
break_reg = kmalloc(2, GFP_KERNEL);
|
||||
if (!break_reg)
|
||||
return;
|
||||
|
||||
r = ch341_control_in(port->serial->dev, CH341_REQ_READ_REG,
|
||||
ch341_break_reg, 0, break_reg, 2);
|
||||
if (r < 0) {
|
||||
if (r) {
|
||||
dev_err(&port->dev, "%s - USB control read error (%d)\n",
|
||||
__func__, r);
|
||||
goto out;
|
||||
return;
|
||||
}
|
||||
dev_dbg(&port->dev, "%s - initial ch341 break register contents - reg1: %x, reg2: %x\n",
|
||||
__func__, break_reg[0], break_reg[1]);
|
||||
|
@ -684,8 +653,6 @@ static void ch341_break_ctl(struct tty_struct *tty, int break_state)
|
|||
if (r < 0)
|
||||
dev_err(&port->dev, "%s - USB control write error (%d)\n",
|
||||
__func__, r);
|
||||
out:
|
||||
kfree(break_reg);
|
||||
}
|
||||
|
||||
static int ch341_tiocmset(struct tty_struct *tty,
|
||||
|
|
Loading…
Reference in New Issue