Received: by 2002:a25:ca44:0:0:0:0:0 with SMTP id a65csp1745592ybg; Thu, 30 Jul 2020 01:16:45 -0700 (PDT) X-Google-Smtp-Source: ABdhPJwtcGRajPz3CqpWLxshf5HA5Zghnv/xzr0TRdgbbnXjFEQWBzJ+HrJrVBnMIsBrzJSv8rTN X-Received: by 2002:a17:906:1d5b:: with SMTP id o27mr1579406ejh.367.1596097005246; Thu, 30 Jul 2020 01:16:45 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1596097005; cv=none; d=google.com; s=arc-20160816; b=FZWmZt1dGWQyq/By4le0oEqpMP6VDS/EoAMAQ+0gJ6gEzVA0SUap2TQB0Xj+6QtgxS XR+S6Nu8idJdXEWwS5ZVHDrxJtk8VOGmGYKvHGLiBI5NVHqNR/QdmWF+kFTOrMk5jnR2 EifORvdVbt/36ViAiI49x50SSepyPBz4Q4a2yjCHXX5drlN1u6z0jC3QjH32oBxTwdNT y4LH29vzAB2Z+ERFtBaBcJe8oShHASIQBm5AUMNP1NPEXQ3pSVI6CDoJvyXBSjXZxJd1 D2SaKn0HWYyqpgixboVcVORvMA20hyeQB/hM62tAX51WeahEap+6hLRrfHdcBKAmwx/J 86Kg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:message-id:date:subject:cc:to:from :dkim-signature; bh=sq3ZqP/9IOq2CA8bWaY6LQE3pVu1n99et9lY6X29D4I=; b=DVYjgBr3g9tG90w1innlze9UCSxDc5YB3zrDgsJdZ62c2ykaa5qmfy/pMxXwy9oI6E sA345yQzQTjlfDUkCAWaZRYTbbiNin2w8hK3qN3pDAxKHkYexshnJTqjtdYHiE3Zi1Wm 6lfSBLPdBOmQ+hwHyKpNkbZwlgkPP1hayAjf9n2az+LZN3qRBZPV9vZk9jw/Aq5HxRkL SGJiyp+R4TYJ5Jz5Fzphj82KfAg5Dc5AnBKREQBjY9k+aod9aBh1QrpcFLGDUj7GP65x 34ZEkBzSsW3ZEcr5nSq4XAk4VFfscJfMQqk81nxKJdL1lJpYEOFJg/y54jCsIrnLEt4b 5nHA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@163.com header.s=s110527 header.b=SQG6T3Xy; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=163.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id c18si2597948eds.417.2020.07.30.01.16.23; Thu, 30 Jul 2020 01:16:45 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@163.com header.s=s110527 header.b=SQG6T3Xy; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=163.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729850AbgG3IPz (ORCPT + 99 others); Thu, 30 Jul 2020 04:15:55 -0400 Received: from m12-15.163.com ([220.181.12.15]:49057 "EHLO m12-15.163.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730060AbgG3IPq (ORCPT ); Thu, 30 Jul 2020 04:15:46 -0400 X-Greylist: delayed 917 seconds by postgrey-1.27 at vger.kernel.org; Thu, 30 Jul 2020 04:15:40 EDT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=163.com; s=s110527; h=From:Subject:Date:Message-Id; bh=sq3ZqP/9IOq2CA8bWa Y6LQE3pVu1n99et9lY6X29D4I=; b=SQG6T3XyX+5I9LUV3lHzxvaE4QVV8chN0G HREo6hyD1WZquO+kHd9URIopeJ6D9XKR3D8HCHKs7RM5bfbc6LhXk0FFvElOJtJK 5qcawa5uwbCLFPq4Xe/ZDsL/9xy5lRnZogCSRG6peo5sURuwd+9cB4f07Q7ze0ev oETQhlNTg= Received: from localhost.localdomain (unknown [182.149.199.78]) by smtp11 (Coremail) with SMTP id D8CowACnQ83jfSJfAnTdDQ--.38317S4; Thu, 30 Jul 2020 15:59:31 +0800 (CST) From: Sheng Long Wang To: johan@kernel.org, gregkh@linuxfoundation.org Cc: linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org, jan.kiszka@siemens.com, Wang Sheng Long Subject: [PATCH] usb-serial:cp210x: add support to software flow control Date: Thu, 30 Jul 2020 15:59:22 +0800 Message-Id: <20200730075922.28041-1-china_shenglong@163.com> X-Mailer: git-send-email 2.17.1 X-CM-TRANSID: D8CowACnQ83jfSJfAnTdDQ--.38317S4 X-Coremail-Antispam: 1Uf129KBjvJXoW3JF45Jw18Jr45GFWftFyrZwb_yoW7Cw1DpF W8trWfKF4DZF43Wa1rAF4Uu3sxuanaqry2yFW3G39Ik3W3Jr1fKF1Ika4Yvr1UArW7J345 Jrs8tayDur47trJanT9S1TB71UUUUUUqnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDUYxBIdaVFxhVjvjDU0xZFpf9x07bYpBfUUUUU= X-Originating-IP: [182.149.199.78] X-CM-SenderInfo: xfkl0tpbvkv0xjor0wi6rwjhhfrp/1tbiyQRxslQHKy9QnwAAsW Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Wang Sheng Long When data is transmitted between two serial ports, the phenomenon of data loss often occurs. The two kinds of flow control commonly used in serial communication are hardware flow control and software flow control. In serial communication, If you only use RX/TX/GND Pins, you can't do hardware flow. So we often used software flow control and prevent data loss. The user sets the software flow control through the application program, and the application program sets the software flow control mode for the serial port chip through the driver. For the cp210 serial port chip, its driver lacks the software flow control setting code, so the user cannot set the software flow control function through the application program. This adds the missing software flow control. Signed-off-by: Wang Sheng Long --- drivers/usb/serial/cp210x.c | 118 ++++++++++++++++++++++++++++++++++-- 1 file changed, 113 insertions(+), 5 deletions(-) diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index e732949f65..c66a0e0fb9 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -380,6 +380,9 @@ static struct usb_serial_driver * const serial_drivers[] = { #define CP210X_PARTNUM_CP2102N_QFN20 0x22 #define CP210X_PARTNUM_UNKNOWN 0xFF +#define CP210X_VSTART 0x11 +#define CP210X_VSTOP 0x13 + /* CP210X_GET_COMM_STATUS returns these 0x13 bytes */ struct cp210x_comm_status { __le32 ulErrors; @@ -391,6 +394,15 @@ struct cp210x_comm_status { u8 bReserved; } __packed; +struct cp210x_chars_response { + u8 eofchar; + u8 errochar; + u8 breakchar; + u8 eventchar; + u8 xonchar; + u8 xoffchar; +} __packed; + /* * CP210X_PURGE - 16 bits passed in wValue of USB request. * SiLabs app note AN571 gives a strange description of the 4 bits: @@ -624,6 +636,45 @@ static int cp210x_read_vendor_block(struct usb_serial *serial, u8 type, u16 val, return result; } +/* + * Read and Write Character Responses operate + * Register SET_CHARS/GET_CHATS + */ +static int cp210x_operate_chars_block(struct usb_serial_port *port, + u8 req, u8 type, void *buf, int bufsize) +{ + struct usb_serial *serial = port->serial; + struct cp210x_port_private *port_priv = usb_get_serial_port_data(port); + void *dmabuf; + int result; + + dmabuf = kmemdup(buf, bufsize, GFP_KERNEL); + if (!dmabuf) + return -ENOMEM; + + result = usb_control_msg(serial->dev, + usb_rcvctrlpipe(serial->dev, 0), + req, type, 0, port_priv->bInterfaceNumber, + dmabuf, bufsize, USB_CTRL_SET_TIMEOUT); + + if (result == bufsize) { + if (type == REQTYPE_DEVICE_TO_HOST) + memcpy(buf, dmabuf, bufsize); + + result = 0; + } else { + dev_err(&port->dev, "failed get req 0x%x size %d status: %d\n", + req, 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. @@ -1134,11 +1185,17 @@ static void cp210x_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old_termios) { struct device *dev = &port->dev; - unsigned int cflag, old_cflag; + struct cp210x_chars_response charsres; + struct cp210x_flow_ctl flow_ctl; + unsigned int cflag, old_cflag, iflag; u16 bits; + int result; + u32 ctl_hs; + u32 flow_repl; cflag = tty->termios.c_cflag; old_cflag = old_termios->c_cflag; + iflag = tty->termios.c_iflag; if (tty->termios.c_ospeed != old_termios->c_ospeed) cp210x_change_speed(tty, port, old_termios); @@ -1212,10 +1269,6 @@ static void cp210x_set_termios(struct tty_struct *tty, } if ((cflag & CRTSCTS) != (old_cflag & CRTSCTS)) { - struct cp210x_flow_ctl flow_ctl; - u32 ctl_hs; - u32 flow_repl; - cp210x_read_reg_block(port, CP210X_GET_FLOW, &flow_ctl, sizeof(flow_ctl)); ctl_hs = le32_to_cpu(flow_ctl.ulControlHandshake); @@ -1252,6 +1305,61 @@ static void cp210x_set_termios(struct tty_struct *tty, sizeof(flow_ctl)); } + /* + * Set Software Flow Control + * Check the IXOFF/IXON status in the iflag component of the + * termios structure. + * + */ + if ((iflag & IXOFF) || (iflag & IXON)) { + + result = cp210x_operate_chars_block(port, + CP210X_GET_CHARS, + REQTYPE_DEVICE_TO_HOST, + &charsres, + sizeof(charsres)); + + if (result < 0) { + dev_err(dev, "Read Characrter Responses failed\n"); + return; + } + charsres.xonchar = CP210X_VSTART; + charsres.xoffchar = CP210X_VSTOP; + result = cp210x_operate_chars_block(port, + CP210X_SET_CHARS, + REQTYPE_HOST_TO_INTERFACE, + &charsres, + sizeof(charsres)); + if (result < 0) { + memset(&charsres, 0, sizeof(charsres)); + dev_err(dev, "Write Characrter Responses failed\n"); + return; + } + + /* Set Rx/Tx Flow Control Flag in ulFlowReplace */ + cp210x_read_reg_block(port, + CP210X_GET_FLOW, + &flow_ctl, + sizeof(flow_ctl)); + + flow_repl = le32_to_cpu(flow_ctl.ulFlowReplace); + + if (iflag & IXOFF) + flow_repl |= CP210X_SERIAL_AUTO_RECEIVE; + else + flow_repl &= ~CP210X_SERIAL_AUTO_RECEIVE; + + if (iflag & IXON) + flow_repl |= CP210X_SERIAL_AUTO_TRANSMIT; + else + flow_repl &= ~CP210X_SERIAL_AUTO_TRANSMIT; + + flow_ctl.ulFlowReplace = cpu_to_le32(flow_repl); + cp210x_write_reg_block(port, + CP210X_SET_FLOW, + &flow_ctl, + sizeof(flow_ctl)); + } } static int cp210x_tiocmset(struct tty_struct *tty, -- 2.17.1