From patchwork Tue Jul 12 11:53:00 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Marek_Beh=C3=BAn?= X-Patchwork-Id: 590289 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id EF0E6CCA481 for ; Tue, 12 Jul 2022 11:54:26 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229872AbiGLLy0 (ORCPT ); Tue, 12 Jul 2022 07:54:26 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39158 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232787AbiGLLyN (ORCPT ); Tue, 12 Jul 2022 07:54:13 -0400 Received: from dfw.source.kernel.org (dfw.source.kernel.org [139.178.84.217]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 104E4B629D; Tue, 12 Jul 2022 04:53:14 -0700 (PDT) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dfw.source.kernel.org (Postfix) with ESMTPS id A0C5561574; Tue, 12 Jul 2022 11:53:13 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id B6F48C341CD; Tue, 12 Jul 2022 11:53:11 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1657626793; bh=6FigCnzE+Dx/FTtyanL8zrhQ0aZVYbr/GBQY5us+fH0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=cNPTMY5FNXdp6Wu6EXjb9vtuAaqtxL26Xu3K917cBSHbDgu+rOonCJdSJLe5EbnM4 FmYPRS4qpROLP040K+Vg42t49c4l+9g8nYOhvP6oCJwZxCWR2fVq4ZvfzMrSdh7MlB 0bB8XKMEM0fgyv3DeSmcLJX9bEwLAj2vq4ud+fzHJMkIMjcuv7cO9Kk6Q4mt8VWCsd st8MAkjVkYZtKjyc6EFCSD8Q+z50fVJN/hsxsvQgwY4tyoWIZ3BGxIF/bQpYQpbCcV jsbISFgqatWdrCB32hheK6gbQU3UeQj3LEhbCOU0EQ+1TvimFpPCdzCu6VXchU0knt 53QQUHG8nAf5w== From: =?utf-8?q?Marek_Beh=C3=BAn?= To: linux-usb@vger.kernel.org Cc: =?utf-8?q?Pali_Roh=C3=A1r?= , Johan Hovold , Greg Kroah-Hartman , =?utf-8?q?Marek_Beh=C3=BAn?= , stable@vger.kernel.org Subject: [PATCH v2 1/7] USB: serial: ftdi_sio: Fix divisor overflow Date: Tue, 12 Jul 2022 13:53:00 +0200 Message-Id: <20220712115306.26471-2-kabel@kernel.org> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220712115306.26471-1-kabel@kernel.org> References: <20220712115306.26471-1-kabel@kernel.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org From: Pali Rohár The baud rate generating divisor is a 17-bit wide (14 bits integer part and 3 bits fractional part). Example: base clock = 48 MHz requested baud rate = 180 Baud divisor = 48,000,000 / (16 * 180) = 0b100000100011010.101 In this case the MSB gets discarded because of the overflow, and the actually used divisor will be 0b100011010.101 = 282.625, resulting in baud rate 10615 Baud, instead of the requested 180 Baud. The best possible thing to do in this case is to generate lowest possible baud rate (in the example it would be 183 Baud), by using maximum possible divisor. In case of divisor overflow, use maximum possible divisor. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: Pali Rohár Tested-by: Marek Behún Signed-off-by: Marek Behún Cc: stable@vger.kernel.org --- drivers/usb/serial/ftdi_sio.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index b440d338a895..ea40f367e70c 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1157,6 +1157,8 @@ static unsigned short int ftdi_232am_baud_base_to_divisor(int baud, int base) int divisor3 = DIV_ROUND_CLOSEST(base, 2 * baud); if ((divisor3 & 0x7) == 7) divisor3++; /* round x.7/8 up to x+1 */ + if (divisor3 > GENMASK(16, 0)) + divisor3 = GENMASK(16, 0); divisor = divisor3 >> 3; divisor3 &= 0x7; if (divisor3 == 1) @@ -1181,6 +1183,8 @@ static u32 ftdi_232bm_baud_base_to_divisor(int baud, int base) u32 divisor; /* divisor shifted 3 bits to the left */ int divisor3 = DIV_ROUND_CLOSEST(base, 2 * baud); + if (divisor3 > GENMASK(16, 0)) + divisor3 = GENMASK(16, 0); divisor = divisor3 >> 3; divisor |= (u32)divfrac[divisor3 & 0x7] << 14; /* Deal with special cases for highest baud rates. */ @@ -1204,6 +1208,8 @@ static u32 ftdi_2232h_baud_base_to_divisor(int baud, int base) /* hi-speed baud rate is 10-bit sampling instead of 16-bit */ divisor3 = DIV_ROUND_CLOSEST(8 * base, 10 * baud); + if (divisor3 > GENMASK(16, 0)) + divisor3 = GENMASK(16, 0); divisor = divisor3 >> 3; divisor |= (u32)divfrac[divisor3 & 0x7] << 14; From patchwork Tue Jul 12 11:53:01 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Marek_Beh=C3=BAn?= X-Patchwork-Id: 590288 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 59F6EC43334 for ; Tue, 12 Jul 2022 11:54:32 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232732AbiGLLy3 (ORCPT ); Tue, 12 Jul 2022 07:54:29 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35012 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232756AbiGLLyP (ORCPT ); Tue, 12 Jul 2022 07:54:15 -0400 Received: from sin.source.kernel.org (sin.source.kernel.org [IPv6:2604:1380:40e1:4800::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 4C984B5D37 for ; Tue, 12 Jul 2022 04:53:20 -0700 (PDT) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by sin.source.kernel.org (Postfix) with ESMTPS id 7C31CCE1A9B for ; Tue, 12 Jul 2022 11:53:16 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 7844CC341CB; Tue, 12 Jul 2022 11:53:13 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1657626794; bh=lSNgtyL8u/58a3asNaRqnCpMiCYfkWiKLPR4264utCo=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=uk1WQ3MjF51mLZ/E7rijqppVD7ZjqaYEP373WTNxaaKvOkbgvLhp5SyZvhX5Oue7b TaLia35D7IXW+NI2oGCjJLQ8pKOK2OC/i9Z+u+U7E5JPE/p+5IZuBWfiqYjqo+90td 1uzHdK1jRJ7N6K9VJ9CBoWXfIKVjxR4lweuqsBQes12NlMZJ5HJRtiQ8Mt3NnJfm8V 6hpbwkm1W0/ro0d285+gw2r7VPZUuPbt0lBgLt8brdtln/T0/KByxL4ytI+y4IIIXo MqQ0HAALMuiT0/wz7CCUUFvM/KU3D+32TH2NKPcuRIukG6tt+C+ZY96Oj+sDqyASL2 F0e1CmvF3WUmg== From: =?utf-8?q?Marek_Beh=C3=BAn?= To: linux-usb@vger.kernel.org Cc: =?utf-8?q?Pali_Roh=C3=A1r?= , Johan Hovold , Greg Kroah-Hartman , =?utf-8?q?Marek_Beh=C3=BAn?= Subject: [PATCH v2 2/7] USB: serial: ftdi_sio: Add missing baud rate validation Date: Tue, 12 Jul 2022 13:53:01 +0200 Message-Id: <20220712115306.26471-3-kabel@kernel.org> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220712115306.26471-1-kabel@kernel.org> References: <20220712115306.26471-1-kabel@kernel.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org From: Pali Rohár Add lower checks for requested baud rate for FT8U232AM, FT232BM, FT2232C, FT232RL, FTX, FT2232H, FT4232H and FT232H. For all of these the minimum baud rate they can generate is 183 Baud. Signed-off-by: Pali Rohár Tested-by: Marek Behún Signed-off-by: Marek Behún --- drivers/usb/serial/ftdi_sio.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index ea40f367e70c..717b97f4e094 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1330,7 +1330,7 @@ static u32 get_ftdi_divisor(struct tty_struct *tty, } break; case FT8U232AM: /* 8U232AM chip */ - if (baud <= 3000000) { + if (baud >= 183 && baud <= 3000000) { div_value = ftdi_232am_baud_to_divisor(baud); } else { dev_dbg(dev, "%s - Baud rate too high!\n", __func__); @@ -1343,7 +1343,7 @@ static u32 get_ftdi_divisor(struct tty_struct *tty, case FT2232C: /* FT2232C chip */ case FT232RL: /* FT232RL chip */ case FTX: /* FT-X series */ - if (baud <= 3000000) { + if (baud >= 183 && baud <= 3000000) { u16 product_id = le16_to_cpu( port->serial->dev->descriptor.idProduct); if (((product_id == FTDI_NDI_HUC_PID) || @@ -1367,7 +1367,7 @@ static u32 get_ftdi_divisor(struct tty_struct *tty, case FT232H: /* FT232H chip */ if ((baud <= 12000000) && (baud >= 1200)) { div_value = ftdi_2232h_baud_to_divisor(baud); - } else if (baud < 1200) { + } else if (baud >= 183 && baud < 1200) { div_value = ftdi_232bm_baud_to_divisor(baud); } else { dev_dbg(dev, "%s - Baud rate too high!\n", __func__); From patchwork Tue Jul 12 11:53:02 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Marek_Beh=C3=BAn?= X-Patchwork-Id: 590032 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 025E5C43334 for ; Tue, 12 Jul 2022 11:54:30 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230004AbiGLLy1 (ORCPT ); Tue, 12 Jul 2022 07:54:27 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39178 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232740AbiGLLyP (ORCPT ); Tue, 12 Jul 2022 07:54:15 -0400 Received: from ams.source.kernel.org (ams.source.kernel.org [IPv6:2604:1380:4601:e00::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D6A1BB5D2F for ; Tue, 12 Jul 2022 04:53:18 -0700 (PDT) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ams.source.kernel.org (Postfix) with ESMTPS id 7259DB817D7 for ; Tue, 12 Jul 2022 11:53:17 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 10951C341CA; Tue, 12 Jul 2022 11:53:14 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1657626796; bh=xc0xDL10XjDO9onCBVCkGKLcFi1HmRGSB+L1iEWaQ8M=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=fCQ27WI7Tif2PeGeUxgV2+heq+UsFPgSTTLM3e3bq5ienOLX6Jc4QpFU6k8pS7gEu jIzuUPcMd4Y+WDfYBUeWbmvc/fzTQuNt2GGCDSaqItt0njExSDlt1Pe6KXu/BShPvb W7Ny+b0zpTX4HudGrzqGOK5DmxZ86/vnrPqDhXTu1IX7MCI3MpyZFPEGBI1GKFytsN dJ7/m3oHDEp6LFnbSn46FdW8wpNgqe3+B8YrokIGcb203FFVFIhBDhnhctFuxYycb/ CGDCtFyQQLUdSDeMpHZFpQG9fc+RJeyUNUBZrSbRzLVZ60+gFbXz4f0lrl6PT0r7Ds iI2vO3bduqEcA== From: =?utf-8?q?Marek_Beh=C3=BAn?= To: linux-usb@vger.kernel.org Cc: =?utf-8?q?Pali_Roh=C3=A1r?= , Johan Hovold , Greg Kroah-Hartman , =?utf-8?q?Marek_Beh=C3=BAn?= Subject: [PATCH v2 3/7] USB: serial: ftdi_sio: Extract SIO divisor code to function Date: Tue, 12 Jul 2022 13:53:02 +0200 Message-Id: <20220712115306.26471-4-kabel@kernel.org> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220712115306.26471-1-kabel@kernel.org> References: <20220712115306.26471-1-kabel@kernel.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org From: Pali Rohár In preparation for following changes, extract divisor code for SIO chip into new function ftdi_sio_baud_to_divisor(), as is done for other chips. No functional change. Signed-off-by: Pali Rohár Tested-by: Marek Behún Signed-off-by: Marek Behún --- drivers/usb/serial/ftdi_sio.c | 36 ++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 717b97f4e094..5b109714612f 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1150,6 +1150,23 @@ static struct usb_serial_driver * const serial_drivers[] = { * *************************************************************************** */ +static int ftdi_sio_baud_to_divisor(int baud) +{ + switch (baud) { + case 300: return ftdi_sio_b300; + case 600: return ftdi_sio_b600; + case 1200: return ftdi_sio_b1200; + case 2400: return ftdi_sio_b2400; + case 4800: return ftdi_sio_b4800; + case 9600: return ftdi_sio_b9600; + case 19200: return ftdi_sio_b19200; + case 38400: return ftdi_sio_b38400; + case 57600: return ftdi_sio_b57600; + case 115200: return ftdi_sio_b115200; + default: return -1; + } +} + static unsigned short int ftdi_232am_baud_base_to_divisor(int baud, int base) { unsigned short int divisor; @@ -1286,7 +1303,7 @@ static u32 get_ftdi_divisor(struct tty_struct *tty, { struct ftdi_private *priv = usb_get_serial_port_data(port); struct device *dev = &port->dev; - u32 div_value = 0; + int div_value = 0; int div_okay = 1; int baud; @@ -1309,23 +1326,12 @@ static u32 get_ftdi_divisor(struct tty_struct *tty, baud = 9600; switch (priv->chip_type) { case SIO: /* SIO chip */ - switch (baud) { - case 300: div_value = ftdi_sio_b300; break; - case 600: div_value = ftdi_sio_b600; break; - case 1200: div_value = ftdi_sio_b1200; break; - case 2400: div_value = ftdi_sio_b2400; break; - case 4800: div_value = ftdi_sio_b4800; break; - case 9600: div_value = ftdi_sio_b9600; break; - case 19200: div_value = ftdi_sio_b19200; break; - 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) { + div_value = ftdi_sio_baud_to_divisor(baud); + if (div_value == -1) { dev_dbg(dev, "%s - Baudrate (%d) requested is not supported\n", __func__, baud); - div_value = ftdi_sio_b9600; baud = 9600; + div_value = ftdi_sio_baud_to_divisor(baud); div_okay = 0; } break; From patchwork Tue Jul 12 11:53:03 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Marek_Beh=C3=BAn?= X-Patchwork-Id: 590031 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id DCBAFC433EF for ; Tue, 12 Jul 2022 11:54:32 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232947AbiGLLyc (ORCPT ); Tue, 12 Jul 2022 07:54:32 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35158 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232759AbiGLLyP (ORCPT ); Tue, 12 Jul 2022 07:54:15 -0400 Received: from ams.source.kernel.org (ams.source.kernel.org [IPv6:2604:1380:4601:e00::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 741FFB62B3 for ; Tue, 12 Jul 2022 04:53:20 -0700 (PDT) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ams.source.kernel.org (Postfix) with ESMTPS id 14F99B817D2 for ; Tue, 12 Jul 2022 11:53:19 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 9C9E5C341CD; Tue, 12 Jul 2022 11:53:16 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1657626797; bh=dOjeyEjyp7Idfbj83YUAKFYnn1f9HOeImcRded7YFIM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=mXk6gTQJs5khRVQhvA1FVall+TpCFKkGJ78fYolb9ZDOqcIxBokoAuAcz9gOgfiRF 0UN7QxXU7ptTWCk44wrgNOzLfk1f2ozGYryhfx9SGv9hwWX1XMwhhn4wIG9gKRzVrw ZalbT6noXdVnQLsi/eBTpOukf2Jb3gWdxTeDNfpIK2GvCNKaH3E3ihgvG9coFGkhKO KsHhG5nDkEGfE6+asfMh3UbVeA59BGxmfiaEMfwG5ABZv4OJ71lkxahnCPyMNk+hK7 Re1y3HjLBRBwx/oSwv7E6T7BSOD+ztktgujyBygRlykdcJXKAUp2Un8b4NeWAPdZro CnNJZ7V9tWITw== From: =?utf-8?q?Marek_Beh=C3=BAn?= To: linux-usb@vger.kernel.org Cc: =?utf-8?q?Pali_Roh=C3=A1r?= , Johan Hovold , Greg Kroah-Hartman , =?utf-8?q?Marek_Beh=C3=BAn?= Subject: [PATCH v2 4/7] USB: serial: ftdi_sio: Do not reset baud rate to 9600 Baud on error Date: Tue, 12 Jul 2022 13:53:03 +0200 Message-Id: <20220712115306.26471-5-kabel@kernel.org> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220712115306.26471-1-kabel@kernel.org> References: <20220712115306.26471-1-kabel@kernel.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org From: Pali Rohár If setting new baud rate fails, all other drivers leave the device at previous baud rate, only ftdi_sio resets to 9600 Baud. Change this behavior to that of other drivers so that /dev/ttyUSB* devices behave in the same way. Signed-off-by: Pali Rohár Tested-by: Marek Behún Signed-off-by: Marek Behún --- Greg pointed out that this make break some people's workflow, that they may depend on this behavior. This is of course possible, although IMO improbable: it would be weird to depend on the fall back to 9600 Baud on error, instead of expecting that the baud rate didn't change at all (like in other /dev/ttyUSB* drivers). Nonetheless if someone complains that they workflow got broken, we will need to revert this. --- drivers/usb/serial/ftdi_sio.c | 38 ++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 5b109714612f..cdbba1a9edd9 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1299,7 +1299,7 @@ static int update_mctrl(struct usb_serial_port *port, unsigned int set, static u32 get_ftdi_divisor(struct tty_struct *tty, - struct usb_serial_port *port) + struct usb_serial_port *port, speed_t old_baud) { struct ftdi_private *priv = usb_get_serial_port_data(port); struct device *dev = &port->dev; @@ -1322,6 +1322,8 @@ static u32 get_ftdi_divisor(struct tty_struct *tty, __func__, priv->custom_divisor, baud); } + if (!baud) + baud = old_baud; if (!baud) baud = 9600; switch (priv->chip_type) { @@ -1330,8 +1332,12 @@ static u32 get_ftdi_divisor(struct tty_struct *tty, if (div_value == -1) { dev_dbg(dev, "%s - Baudrate (%d) requested is not supported\n", __func__, baud); - baud = 9600; + baud = old_baud ? old_baud : 9600; div_value = ftdi_sio_baud_to_divisor(baud); + if (div_value == -1) { + baud = 9600; + div_value = ftdi_sio_baud_to_divisor(baud); + } div_okay = 0; } break; @@ -1340,8 +1346,8 @@ static u32 get_ftdi_divisor(struct tty_struct *tty, div_value = ftdi_232am_baud_to_divisor(baud); } else { dev_dbg(dev, "%s - Baud rate too high!\n", __func__); - baud = 9600; - div_value = ftdi_232am_baud_to_divisor(9600); + baud = (old_baud >= 183 && old_baud <= 3000000) ? old_baud : 9600; + div_value = ftdi_232am_baud_to_divisor(baud); div_okay = 0; } break; @@ -1363,9 +1369,9 @@ static u32 get_ftdi_divisor(struct tty_struct *tty, div_value = ftdi_232bm_baud_to_divisor(baud); } else { dev_dbg(dev, "%s - Baud rate too high!\n", __func__); - div_value = ftdi_232bm_baud_to_divisor(9600); + baud = (old_baud >= 183 && old_baud <= 3000000) ? old_baud : 9600; + div_value = ftdi_232bm_baud_to_divisor(baud); div_okay = 0; - baud = 9600; } break; case FT2232H: /* FT2232H chip */ @@ -1377,9 +1383,14 @@ static u32 get_ftdi_divisor(struct tty_struct *tty, div_value = ftdi_232bm_baud_to_divisor(baud); } else { dev_dbg(dev, "%s - Baud rate too high!\n", __func__); - div_value = ftdi_232bm_baud_to_divisor(9600); + if (old_baud >= 183 && old_baud < 1200) { + baud = old_baud; + div_value = ftdi_232bm_baud_to_divisor(baud); + } else { + baud = (old_baud >= 1200 && old_baud <= 12000000) ? old_baud : 9600; + div_value = ftdi_2232h_baud_to_divisor(baud); + } div_okay = 0; - baud = 9600; } break; } /* priv->chip_type */ @@ -1394,7 +1405,7 @@ static u32 get_ftdi_divisor(struct tty_struct *tty, return div_value; } -static int change_speed(struct tty_struct *tty, struct usb_serial_port *port) +static int change_speed(struct tty_struct *tty, struct usb_serial_port *port, speed_t old_baud) { struct ftdi_private *priv = usb_get_serial_port_data(port); u16 value; @@ -1402,7 +1413,7 @@ static int change_speed(struct tty_struct *tty, struct usb_serial_port *port) u32 index_value; int rv; - index_value = get_ftdi_divisor(tty, port); + index_value = get_ftdi_divisor(tty, port, old_baud); value = (u16)index_value; index = (u16)(index_value >> 16); if (priv->chip_type == FT2232C || priv->chip_type == FT2232H || @@ -1525,7 +1536,7 @@ static int set_serial_info(struct tty_struct *tty, struct serial_struct *ss) if (priv->flags & ASYNC_SPD_MASK) dev_warn_ratelimited(&port->dev, "use of SPD flags is deprecated\n"); - change_speed(tty, port); + change_speed(tty, port, 0); } mutex_unlock(&priv->cfg_lock); return 0; @@ -2774,9 +2785,12 @@ static void ftdi_set_termios(struct tty_struct *tty, /* Drop RTS and DTR */ clear_mctrl(port, TIOCM_DTR | TIOCM_RTS); } else { + speed_t old_baud = + old_termios ? tty_termios_baud_rate(old_termios) : 0; + /* set the baudrate determined before */ mutex_lock(&priv->cfg_lock); - if (change_speed(tty, port)) + if (change_speed(tty, port, old_baud)) dev_err(ddev, "%s urb failed to set baudrate\n", __func__); mutex_unlock(&priv->cfg_lock); /* Ensure RTS and DTR are raised when baudrate changed from 0 */ From patchwork Tue Jul 12 11:53:04 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Marek_Beh=C3=BAn?= X-Patchwork-Id: 590287 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 60BE1CCA47C for ; Tue, 12 Jul 2022 11:54:33 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229920AbiGLLyc (ORCPT ); Tue, 12 Jul 2022 07:54:32 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:34858 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232753AbiGLLyP (ORCPT ); Tue, 12 Jul 2022 07:54:15 -0400 Received: from dfw.source.kernel.org (dfw.source.kernel.org [IPv6:2604:1380:4641:c500::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 7311FB62B1 for ; Tue, 12 Jul 2022 04:53:20 -0700 (PDT) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dfw.source.kernel.org (Postfix) with ESMTPS id F28F26156D for ; Tue, 12 Jul 2022 11:53:19 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 38302C341CB; Tue, 12 Jul 2022 11:53:18 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1657626799; bh=SMWs9lHYCGSSpuMZB3WjxczPj7PPubzF2MJZNYCfYmw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=BGed5AsgyBZNmBHLqAlKpqpjAsWrdTV+9SaqJ1dW1IvBFIX9XDkLmbg+DjsmenjOC PUbw5fEq9N/rlQkfVgRffhI/aI45eFhVqycL0jDTfLZ3B7OMr/S+7fINY40suC5tbd qq2uBNveOtcOXhE8PaOZLeNAi0JNM8H3+FS0x4xb39bne0BSaJHmEH147Znu1ITm53 0PvjDYbBRvcA8vdrkZopAOMMJVUYi1t99JKrRbgOgTqlUeBlq7p+n7LfRJpAREoc8X 3p5PlCoOR02AH2ICD73RcEYvDzOavSNrSSbfWLZykohBMWNZiUIzolBbQulBL2hSzT dDll4cXLDbvQw== From: =?utf-8?q?Marek_Beh=C3=BAn?= To: linux-usb@vger.kernel.org Cc: =?utf-8?q?Pali_Roh=C3=A1r?= , Johan Hovold , Greg Kroah-Hartman , =?utf-8?q?Marek_Beh=C3=BAn?= Subject: [PATCH v2 5/7] USB: serial: ftdi_sio: Fix baud rate rounding for ASYNC_SPD_CUST Date: Tue, 12 Jul 2022 13:53:04 +0200 Message-Id: <20220712115306.26471-6-kabel@kernel.org> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220712115306.26471-1-kabel@kernel.org> References: <20220712115306.26471-1-kabel@kernel.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org From: Pali Rohár To compute more accurate baud rate when user uses ASYNC_SPD_CUST API, use DIV_ROUND_CLOSEST() instead of just rounding down. Rationale: Application uses old API, so it computes divisor D for baud rate B. The driver then tries to compute back the requested baud rate B, but rounds down in the division. Using rounding to closest value instead should increate accuracy here. Signed-off-by: Pali Rohár Tested-by: Marek Behún Signed-off-by: Marek Behún --- drivers/usb/serial/ftdi_sio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index cdbba1a9edd9..5db1293bb7a2 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1317,7 +1317,7 @@ static u32 get_ftdi_divisor(struct tty_struct *tty, if (baud == 38400 && ((priv->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) && (priv->custom_divisor)) { - baud = priv->baud_base / priv->custom_divisor; + baud = DIV_ROUND_CLOSEST(priv->baud_base, priv->custom_divisor); dev_dbg(dev, "%s - custom divisor %d sets baud rate to %d\n", __func__, priv->custom_divisor, baud); } From patchwork Tue Jul 12 11:53:05 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Marek_Beh=C3=BAn?= X-Patchwork-Id: 590030 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3371EC43334 for ; Tue, 12 Jul 2022 11:54:34 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232753AbiGLLyd (ORCPT ); Tue, 12 Jul 2022 07:54:33 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:36532 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232760AbiGLLyP (ORCPT ); Tue, 12 Jul 2022 07:54:15 -0400 Received: from dfw.source.kernel.org (dfw.source.kernel.org [IPv6:2604:1380:4641:c500::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id EB6D1B38D6 for ; Tue, 12 Jul 2022 04:53:21 -0700 (PDT) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dfw.source.kernel.org (Postfix) with ESMTPS id 889CD614D2 for ; Tue, 12 Jul 2022 11:53:21 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id C5E99C341CA; Tue, 12 Jul 2022 11:53:19 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1657626800; bh=R1PUUU3HotDygkPBJux3mO3BxfC2b5NYP/yyWUr7vs8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=LdNHfUhULpt3w/p5wPmhy7N/mATybEKjyFMgIJjo1WjU4wvkzNaECbiRyeWhPAHsD +/bQOhJX1505GkUjwGfEHr2QwrL597NJMFmTjYcVbv3pxFRY2I5we3SmYpbGWIcyq1 uRQMvB/5nArdvaKOlcacWyt8xNQcBsMVPxxXAtCkniYIiqrU25LQcacbREou9AGdUP iRtKqJ9XP5g7vEYaplmFYAJVNMYG5rbQa1i3kt/vVx/sJG92XFi5ThS0nXSUl+vIfN w4oZKx2JKzfLzfILFD5om7ca6TD1Q8v6J/vB575VU0optz3HoYHzrCj0zM7T+Iv2Qr aVCLyLnqXHjPg== From: =?utf-8?q?Marek_Beh=C3=BAn?= To: linux-usb@vger.kernel.org Cc: =?utf-8?q?Pali_Roh=C3=A1r?= , Johan Hovold , Greg Kroah-Hartman , =?utf-8?q?Marek_Beh=C3=BAn?= Subject: [PATCH v2 6/7] USB: serial: ftdi_sio: Fix custom_divisor and c_*speed for ASYNC_SPD_CUST Date: Tue, 12 Jul 2022 13:53:05 +0200 Message-Id: <20220712115306.26471-7-kabel@kernel.org> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220712115306.26471-1-kabel@kernel.org> References: <20220712115306.26471-1-kabel@kernel.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org From: Pali Rohár When ASYNC_SPD_CUST is used, update custom_divisor and c_*speed fields so that they correspond to the newly set baud rate value, so that userspace GET ioctls will see the true baud rate that is being used. Signed-off-by: Pali Rohár Tested-by: Marek Behún Signed-off-by: Marek Behún --- drivers/usb/serial/ftdi_sio.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 5db1293bb7a2..39e8c5d06157 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1303,6 +1303,7 @@ static u32 get_ftdi_divisor(struct tty_struct *tty, { struct ftdi_private *priv = usb_get_serial_port_data(port); struct device *dev = &port->dev; + int fix_custom_divisor = 0; int div_value = 0; int div_okay = 1; int baud; @@ -1317,6 +1318,7 @@ static u32 get_ftdi_divisor(struct tty_struct *tty, if (baud == 38400 && ((priv->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) && (priv->custom_divisor)) { + fix_custom_divisor = 1; baud = DIV_ROUND_CLOSEST(priv->baud_base, priv->custom_divisor); dev_dbg(dev, "%s - custom divisor %d sets baud rate to %d\n", __func__, priv->custom_divisor, baud); @@ -1401,7 +1403,19 @@ static u32 get_ftdi_divisor(struct tty_struct *tty, ftdi_chip_name[priv->chip_type]); } + /* Fix deprecated async-compatible custom_divisor hack and update tty baud rate */ + if (fix_custom_divisor) { + priv->custom_divisor = DIV_ROUND_CLOSEST(priv->baud_base, baud); + old_baud = baud; + baud = 38400; + } + tty_encode_baud_rate(tty, baud, baud); + + /* For async-compatible custom_divisor store into TCGETS2 c_*speed fields real baud rate */ + if (fix_custom_divisor) + tty->termios.c_ispeed = tty->termios.c_ospeed = old_baud; + return div_value; } @@ -2674,6 +2688,8 @@ static void ftdi_set_termios(struct tty_struct *tty, dev_dbg(ddev, "%s: forcing baud rate for this device\n", __func__); tty_encode_baud_rate(tty, priv->force_baud, priv->force_baud); + termios->c_ispeed = termios->c_ospeed = + DIV_ROUND_CLOSEST(priv->baud_base, priv->custom_divisor); } /* Force RTS-CTS if this device requires it. */ From patchwork Tue Jul 12 11:53:06 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Marek_Beh=C3=BAn?= X-Patchwork-Id: 590286 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id A946DC43334 for ; Tue, 12 Jul 2022 11:54:36 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232849AbiGLLye (ORCPT ); Tue, 12 Jul 2022 07:54:34 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:36530 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232810AbiGLLyP (ORCPT ); Tue, 12 Jul 2022 07:54:15 -0400 Received: from dfw.source.kernel.org (dfw.source.kernel.org [139.178.84.217]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 837C1B41BC for ; Tue, 12 Jul 2022 04:53:23 -0700 (PDT) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dfw.source.kernel.org (Postfix) with ESMTPS id 205276155D for ; Tue, 12 Jul 2022 11:53:23 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 5EF8CC341CB; Tue, 12 Jul 2022 11:53:21 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1657626802; bh=sgBd6DpgHKOIOyXCNr0kA310QdC6HP+HzFCBE4KBfto=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=MP0dfnNclseiLozY64zOve2elTrK/7FtXU1eNhVm+4fktx5Wv8xwCXtOkZVm+Irwb 3XqG27FPkhVX60w9k2M+4O2zT1/yddnEr24/hxZFIVvsiGg2+MpdXobUiqCfTgSpVX dHfyDiZ0Yy93YCoCdRW13CuU1QmMh0Gk8+Iv8slg8Hpv7mYGI4ZtBFIXfAIb1H8E9Z VoyydVIYrQxzxxnCOktmmiDLGQ/M9d+G+GGNAaR6qIxHmpA1x+BoQB6dWGwTTbcP+D 5bF9oIEpHW9x4F86OC3/wxigvgFdXmGTpmOKq2oF0XAvpcOy7yo32ydeX4RdSqJY2N B4g5B6S7hwdVA== From: =?utf-8?q?Marek_Beh=C3=BAn?= To: linux-usb@vger.kernel.org Cc: =?utf-8?q?Pali_Roh=C3=A1r?= , Johan Hovold , Greg Kroah-Hartman , =?utf-8?q?Marek_Beh=C3=BAn?= Subject: [PATCH v2 7/7] USB: serial: ftdi_sio: Fill c_*speed fields with real baud rate Date: Tue, 12 Jul 2022 13:53:06 +0200 Message-Id: <20220712115306.26471-8-kabel@kernel.org> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220712115306.26471-1-kabel@kernel.org> References: <20220712115306.26471-1-kabel@kernel.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org From: Pali Rohár Calculate baud rate value in c_*speed fields to the real values which were set on hardware. For this operation, add a new set of methods *_divisor_to_baud() for each chip and use them for calculating the real baud rate values. Each *_divisor_to_baud() method is constructed as an inverse function of its corresponding *_baud_to_divisor() method. Signed-off-by: Pali Rohár Tested-by: Marek Behún Signed-off-by: Marek Behún --- drivers/usb/serial/ftdi_sio.c | 83 +++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 39e8c5d06157..838acce53e69 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1167,6 +1167,23 @@ static int ftdi_sio_baud_to_divisor(int baud) } } +static int ftdi_sdio_divisor_to_baud(u32 divisor) +{ + switch (divisor) { + case ftdi_sio_b300: return 300; + case ftdi_sio_b600: return 600; + case ftdi_sio_b1200: return 1200; + case ftdi_sio_b2400: return 2400; + case ftdi_sio_b4800: return 4800; + case ftdi_sio_b9600: return 9600; + case ftdi_sio_b19200: return 19200; + case ftdi_sio_b38400: return 38400; + case ftdi_sio_b57600: return 57600; + case ftdi_sio_b115200: return 115200; + default: return 9600; + } +} + static unsigned short int ftdi_232am_baud_base_to_divisor(int baud, int base) { unsigned short int divisor; @@ -1189,15 +1206,33 @@ static unsigned short int ftdi_232am_baud_base_to_divisor(int baud, int base) return divisor; } +static int ftdi_232am_divisor_base_to_baud(unsigned short int divisor, int base) +{ + static const unsigned char divfrac_inv[4] = { 0, 4, 2, 1 }; + unsigned int divisor3; + + if (divisor == 0) + divisor = 1; + divisor3 = (GENMASK(13, 0) & divisor) << 3; + divisor3 |= divfrac_inv[(divisor >> 14) & 0x3]; + return DIV_ROUND_CLOSEST(base, 2 * divisor3); +} + static unsigned short int ftdi_232am_baud_to_divisor(int baud) { return ftdi_232am_baud_base_to_divisor(baud, 48000000); } +static int ftdi_232am_divisor_to_baud(unsigned short int divisor) +{ + return ftdi_232am_divisor_base_to_baud(divisor, 48000000); +} + static u32 ftdi_232bm_baud_base_to_divisor(int baud, int base) { static const unsigned char divfrac[8] = { 0, 3, 2, 4, 1, 5, 6, 7 }; u32 divisor; + /* divisor shifted 3 bits to the left */ int divisor3 = DIV_ROUND_CLOSEST(base, 2 * baud); if (divisor3 > GENMASK(16, 0)) @@ -1212,11 +1247,31 @@ static u32 ftdi_232bm_baud_base_to_divisor(int baud, int base) return divisor; } +static int ftdi_232bm_divisor_base_to_baud(u32 divisor, int base) +{ + static const unsigned char divfrac_inv[8] = { 0, 4, 2, 1, 3, 5, 6, 7 }; + u32 divisor3; + + /* Deal with special cases for highest baud rates. */ + if (divisor == 0) + divisor = 1; /* 1.0 */ + else if (divisor == 1) + divisor = 0x4001; /* 1.5 */ + divisor3 = (GENMASK(13, 0) & divisor) << 3; + divisor3 |= divfrac_inv[(divisor >> 14) & 0x7]; + return DIV_ROUND_CLOSEST(base, 2 * divisor3); +} + static u32 ftdi_232bm_baud_to_divisor(int baud) { return ftdi_232bm_baud_base_to_divisor(baud, 48000000); } +static int ftdi_232bm_divisor_to_baud(u32 divisor) +{ + return ftdi_232bm_divisor_base_to_baud(divisor, 48000000); +} + static u32 ftdi_2232h_baud_base_to_divisor(int baud, int base) { static const unsigned char divfrac[8] = { 0, 3, 2, 4, 1, 5, 6, 7 }; @@ -1244,11 +1299,32 @@ static u32 ftdi_2232h_baud_base_to_divisor(int baud, int base) return divisor; } +static int ftdi_2232h_divisor_base_to_baud(u32 divisor, int base) +{ + static const unsigned char divfrac_inv[8] = { 0, 4, 2, 1, 3, 5, 6, 7 }; + u32 divisor3; + + divisor &= GENMASK(16, 0); + /* Deal with special cases for highest baud rates. */ + if (divisor == 0) + divisor = 1; /* 1.0 */ + else if (divisor == 1) + divisor = 0x4001; /* 1.5 */ + divisor3 = (GENMASK(13, 0) & divisor) << 3; + divisor3 |= divfrac_inv[(divisor >> 14) & 0x7]; + return DIV_ROUND_CLOSEST(8 * base, 10 * divisor3); +} + static u32 ftdi_2232h_baud_to_divisor(int baud) { return ftdi_2232h_baud_base_to_divisor(baud, 120000000); } +static int ftdi_2232h_divisor_to_baud(u32 divisor) +{ + return ftdi_2232h_divisor_base_to_baud(divisor, 120000000); +} + #define set_mctrl(port, set) update_mctrl((port), (set), 0) #define clear_mctrl(port, clear) update_mctrl((port), 0, (clear)) @@ -1342,6 +1418,7 @@ static u32 get_ftdi_divisor(struct tty_struct *tty, } div_okay = 0; } + baud = ftdi_sdio_divisor_to_baud(div_value); break; case FT8U232AM: /* 8U232AM chip */ if (baud >= 183 && baud <= 3000000) { @@ -1352,6 +1429,7 @@ static u32 get_ftdi_divisor(struct tty_struct *tty, div_value = ftdi_232am_baud_to_divisor(baud); div_okay = 0; } + baud = ftdi_232am_divisor_to_baud(div_value); break; case FT232BM: /* FT232BM chip */ case FT2232C: /* FT2232C chip */ @@ -1375,22 +1453,27 @@ static u32 get_ftdi_divisor(struct tty_struct *tty, div_value = ftdi_232bm_baud_to_divisor(baud); div_okay = 0; } + baud = ftdi_232bm_divisor_to_baud(div_value); break; case FT2232H: /* FT2232H chip */ case FT4232H: /* FT4232H chip */ case FT232H: /* FT232H chip */ if ((baud <= 12000000) && (baud >= 1200)) { div_value = ftdi_2232h_baud_to_divisor(baud); + baud = ftdi_2232h_divisor_to_baud(div_value); } else if (baud >= 183 && baud < 1200) { div_value = ftdi_232bm_baud_to_divisor(baud); + baud = ftdi_232bm_divisor_to_baud(div_value); } else { dev_dbg(dev, "%s - Baud rate too high!\n", __func__); if (old_baud >= 183 && old_baud < 1200) { baud = old_baud; div_value = ftdi_232bm_baud_to_divisor(baud); + baud = ftdi_232bm_divisor_to_baud(div_value); } else { baud = (old_baud >= 1200 && old_baud <= 12000000) ? old_baud : 9600; div_value = ftdi_2232h_baud_to_divisor(baud); + baud = ftdi_2232h_divisor_to_baud(div_value); } div_okay = 0; }